1/*
2 * xpath.c: XML Path Language implementation
3 *          XPath is a language for addressing parts of an XML document,
4 *          designed to be used by both XSLT and XPointer
5 *f
6 * Reference: W3C Recommendation 16 November 1999
7 *     http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 *     http://www.w3.org/TR/xpath
10 *
11 * See Copyright for the status of this software
12 *
13 * Author: daniel@veillard.com
14 *
15 */
16
17#define IN_LIBXML
18#include "libxml.h"
19
20#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
31#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
34#ifdef HAVE_SIGNAL_H
35#include <signal.h>
36#endif
37
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
52#include <libxml/threads.h>
53#include <libxml/globals.h>
54#ifdef LIBXML_PATTERN_ENABLED
55#include <libxml/pattern.h>
56#endif
57
58#ifdef LIBXML_PATTERN_ENABLED
59#define XPATH_STREAMING
60#endif
61
62#define TODO								\
63    xmlGenericError(xmlGenericErrorContext,				\
64	    "Unimplemented block at %s:%d\n",				\
65            __FILE__, __LINE__);
66
67/*
68* XP_OPTIMIZED_NON_ELEM_COMPARISON:
69* If defined, this will use xmlXPathCmpNodesExt() instead of
70* xmlXPathCmpNodes(). The new function is optimized comparison of
71* non-element nodes; actually it will speed up comparison only if
72* xmlXPathOrderDocElems() was called in order to index the elements of
73* a tree in document order; Libxslt does such an indexing, thus it will
74* benefit from this optimization.
75*/
76#define XP_OPTIMIZED_NON_ELEM_COMPARISON
77
78/*
79* XP_OPTIMIZED_FILTER_FIRST:
80* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81* in a way, that it stop evaluation at the first node.
82*/
83#define XP_OPTIMIZED_FILTER_FIRST
84
85/*
86* XP_DEBUG_OBJ_USAGE:
87* Internal flag to enable tracking of how much XPath objects have been
88* created.
89*/
90/* #define XP_DEBUG_OBJ_USAGE */
91
92/*
93 * TODO:
94 * There are a few spots where some tests are done which depend upon ascii
95 * data.  These should be enhanced for full UTF8 support (see particularly
96 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
97 */
98
99#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
100
101/************************************************************************
102 *									*
103 *			Floating point stuff				*
104 *									*
105 ************************************************************************/
106
107#ifndef TRIO_REPLACE_STDIO
108#define TRIO_PUBLIC static
109#endif
110#include "trionan.c"
111
112/*
113 * The lack of portability of this section of the libc is annoying !
114 */
115double xmlXPathNAN = 0;
116double xmlXPathPINF = 1;
117double xmlXPathNINF = -1;
118static double xmlXPathNZERO = 0; /* not exported from headers */
119static int xmlXPathInitialized = 0;
120
121/**
122 * xmlXPathInit:
123 *
124 * Initialize the XPath environment
125 */
126void
127xmlXPathInit(void) {
128    if (xmlXPathInitialized) return;
129
130    xmlXPathPINF = trio_pinf();
131    xmlXPathNINF = trio_ninf();
132    xmlXPathNAN = trio_nan();
133    xmlXPathNZERO = trio_nzero();
134
135    xmlXPathInitialized = 1;
136}
137
138/**
139 * xmlXPathIsNaN:
140 * @val:  a double value
141 *
142 * Provides a portable isnan() function to detect whether a double
143 * is a NotaNumber. Based on trio code
144 * http://sourceforge.net/projects/ctrio/
145 *
146 * Returns 1 if the value is a NaN, 0 otherwise
147 */
148int
149xmlXPathIsNaN(double val) {
150    return(trio_isnan(val));
151}
152
153/**
154 * xmlXPathIsInf:
155 * @val:  a double value
156 *
157 * Provides a portable isinf() function to detect whether a double
158 * is a +Infinite or -Infinite. Based on trio code
159 * http://sourceforge.net/projects/ctrio/
160 *
161 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
162 */
163int
164xmlXPathIsInf(double val) {
165    return(trio_isinf(val));
166}
167
168#endif /* SCHEMAS or XPATH */
169#ifdef LIBXML_XPATH_ENABLED
170/**
171 * xmlXPathGetSign:
172 * @val:  a double value
173 *
174 * Provides a portable function to detect the sign of a double
175 * Modified from trio code
176 * http://sourceforge.net/projects/ctrio/
177 *
178 * Returns 1 if the value is Negative, 0 if positive
179 */
180static int
181xmlXPathGetSign(double val) {
182    return(trio_signbit(val));
183}
184
185
186/*
187 * TODO: when compatibility allows remove all "fake node libxslt" strings
188 *       the test should just be name[0] = ' '
189 */
190#ifdef DEBUG_XPATH_EXPRESSION
191#define DEBUG_STEP
192#define DEBUG_EXPR
193#define DEBUG_EVAL_COUNTS
194#endif
195
196static xmlNs xmlXPathXMLNamespaceStruct = {
197    NULL,
198    XML_NAMESPACE_DECL,
199    XML_XML_NAMESPACE,
200    BAD_CAST "xml",
201    NULL,
202    NULL
203};
204static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
205#ifndef LIBXML_THREAD_ENABLED
206/*
207 * Optimizer is disabled only when threaded apps are detected while
208 * the library ain't compiled for thread safety.
209 */
210static int xmlXPathDisableOptimizer = 0;
211#endif
212
213/************************************************************************
214 *									*
215 *			Error handling routines				*
216 *									*
217 ************************************************************************/
218
219/**
220 * XP_ERRORNULL:
221 * @X:  the error code
222 *
223 * Macro to raise an XPath error and return NULL.
224 */
225#define XP_ERRORNULL(X)							\
226    { xmlXPathErr(ctxt, X); return(NULL); }
227
228/*
229 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
230 */
231static const char *xmlXPathErrorMessages[] = {
232    "Ok\n",
233    "Number encoding\n",
234    "Unfinished literal\n",
235    "Start of literal\n",
236    "Expected $ for variable reference\n",
237    "Undefined variable\n",
238    "Invalid predicate\n",
239    "Invalid expression\n",
240    "Missing closing curly brace\n",
241    "Unregistered function\n",
242    "Invalid operand\n",
243    "Invalid type\n",
244    "Invalid number of arguments\n",
245    "Invalid context size\n",
246    "Invalid context position\n",
247    "Memory allocation error\n",
248    "Syntax error\n",
249    "Resource error\n",
250    "Sub resource error\n",
251    "Undefined namespace prefix\n",
252    "Encoding error\n",
253    "Char out of XML range\n",
254    "Invalid or incomplete context\n",
255    "?? Unknown error ??\n"	/* Must be last in the list! */
256};
257#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
258		   sizeof(xmlXPathErrorMessages[0])) - 1)
259/**
260 * xmlXPathErrMemory:
261 * @ctxt:  an XPath context
262 * @extra:  extra informations
263 *
264 * Handle a redefinition of attribute error
265 */
266static void
267xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
268{
269    if (ctxt != NULL) {
270        if (extra) {
271            xmlChar buf[200];
272
273            xmlStrPrintf(buf, 200,
274                         BAD_CAST "Memory allocation failed : %s\n",
275                         extra);
276            ctxt->lastError.message = (char *) xmlStrdup(buf);
277        } else {
278            ctxt->lastError.message = (char *)
279	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
280        }
281        ctxt->lastError.domain = XML_FROM_XPATH;
282        ctxt->lastError.code = XML_ERR_NO_MEMORY;
283	if (ctxt->error != NULL)
284	    ctxt->error(ctxt->userData, &ctxt->lastError);
285    } else {
286        if (extra)
287            __xmlRaiseError(NULL, NULL, NULL,
288                            NULL, NULL, XML_FROM_XPATH,
289                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
290                            extra, NULL, NULL, 0, 0,
291                            "Memory allocation failed : %s\n", extra);
292        else
293            __xmlRaiseError(NULL, NULL, NULL,
294                            NULL, NULL, XML_FROM_XPATH,
295                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
296                            NULL, NULL, NULL, 0, 0,
297                            "Memory allocation failed\n");
298    }
299}
300
301/**
302 * xmlXPathPErrMemory:
303 * @ctxt:  an XPath parser context
304 * @extra:  extra informations
305 *
306 * Handle a redefinition of attribute error
307 */
308static void
309xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
310{
311    if (ctxt == NULL)
312	xmlXPathErrMemory(NULL, extra);
313    else {
314	ctxt->error = XPATH_MEMORY_ERROR;
315	xmlXPathErrMemory(ctxt->context, extra);
316    }
317}
318
319/**
320 * xmlXPathErr:
321 * @ctxt:  a XPath parser context
322 * @error:  the error code
323 *
324 * Handle an XPath error
325 */
326void
327xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
328{
329    if ((error < 0) || (error > MAXERRNO))
330	error = MAXERRNO;
331    if (ctxt == NULL) {
332	__xmlRaiseError(NULL, NULL, NULL,
333			NULL, NULL, XML_FROM_XPATH,
334			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
335			XML_ERR_ERROR, NULL, 0,
336			NULL, NULL, NULL, 0, 0,
337			"%s", xmlXPathErrorMessages[error]);
338	return;
339    }
340    ctxt->error = error;
341    if (ctxt->context == NULL) {
342	__xmlRaiseError(NULL, NULL, NULL,
343			NULL, NULL, XML_FROM_XPATH,
344			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
345			XML_ERR_ERROR, NULL, 0,
346			(const char *) ctxt->base, NULL, NULL,
347			ctxt->cur - ctxt->base, 0,
348			"%s", xmlXPathErrorMessages[error]);
349	return;
350    }
351
352    /* cleanup current last error */
353    xmlResetError(&ctxt->context->lastError);
354
355    ctxt->context->lastError.domain = XML_FROM_XPATH;
356    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
357                           XPATH_EXPRESSION_OK;
358    ctxt->context->lastError.level = XML_ERR_ERROR;
359    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
360    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
361    ctxt->context->lastError.node = ctxt->context->debugNode;
362    if (ctxt->context->error != NULL) {
363	ctxt->context->error(ctxt->context->userData,
364	                     &ctxt->context->lastError);
365    } else {
366	__xmlRaiseError(NULL, NULL, NULL,
367			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
368			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
369			XML_ERR_ERROR, NULL, 0,
370			(const char *) ctxt->base, NULL, NULL,
371			ctxt->cur - ctxt->base, 0,
372			"%s", xmlXPathErrorMessages[error]);
373    }
374
375}
376
377/**
378 * xmlXPatherror:
379 * @ctxt:  the XPath Parser context
380 * @file:  the file name
381 * @line:  the line number
382 * @no:  the error number
383 *
384 * Formats an error message.
385 */
386void
387xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
388              int line ATTRIBUTE_UNUSED, int no) {
389    xmlXPathErr(ctxt, no);
390}
391
392/************************************************************************
393 *									*
394 *			Utilities					*
395 *									*
396 ************************************************************************/
397
398/**
399 * xsltPointerList:
400 *
401 * Pointer-list for various purposes.
402 */
403typedef struct _xmlPointerList xmlPointerList;
404typedef xmlPointerList *xmlPointerListPtr;
405struct _xmlPointerList {
406    void **items;
407    int number;
408    int size;
409};
410/*
411* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
412* and here, we should make the functions public.
413*/
414static int
415xmlPointerListAddSize(xmlPointerListPtr list,
416		       void *item,
417		       int initialSize)
418{
419    if (list->items == NULL) {
420	if (initialSize <= 0)
421	    initialSize = 1;
422	list->items = (void **) xmlMalloc(
423	    initialSize * sizeof(void *));
424	if (list->items == NULL) {
425	    xmlXPathErrMemory(NULL,
426		"xmlPointerListCreate: allocating item\n");
427	    return(-1);
428	}
429	list->number = 0;
430	list->size = initialSize;
431    } else if (list->size <= list->number) {
432	list->size *= 2;
433	list->items = (void **) xmlRealloc(list->items,
434	    list->size * sizeof(void *));
435	if (list->items == NULL) {
436	    xmlXPathErrMemory(NULL,
437		"xmlPointerListCreate: re-allocating item\n");
438	    list->size = 0;
439	    return(-1);
440	}
441    }
442    list->items[list->number++] = item;
443    return(0);
444}
445
446/**
447 * xsltPointerListCreate:
448 *
449 * Creates an xsltPointerList structure.
450 *
451 * Returns a xsltPointerList structure or NULL in case of an error.
452 */
453static xmlPointerListPtr
454xmlPointerListCreate(int initialSize)
455{
456    xmlPointerListPtr ret;
457
458    ret = xmlMalloc(sizeof(xmlPointerList));
459    if (ret == NULL) {
460	xmlXPathErrMemory(NULL,
461	    "xmlPointerListCreate: allocating item\n");
462	return (NULL);
463    }
464    memset(ret, 0, sizeof(xmlPointerList));
465    if (initialSize > 0) {
466	xmlPointerListAddSize(ret, NULL, initialSize);
467	ret->number = 0;
468    }
469    return (ret);
470}
471
472/**
473 * xsltPointerListFree:
474 *
475 * Frees the xsltPointerList structure. This does not free
476 * the content of the list.
477 */
478static void
479xmlPointerListFree(xmlPointerListPtr list)
480{
481    if (list == NULL)
482	return;
483    if (list->items != NULL)
484	xmlFree(list->items);
485    xmlFree(list);
486}
487
488/************************************************************************
489 *									*
490 *			Parser Types					*
491 *									*
492 ************************************************************************/
493
494/*
495 * Types are private:
496 */
497
498typedef enum {
499    XPATH_OP_END=0,
500    XPATH_OP_AND,
501    XPATH_OP_OR,
502    XPATH_OP_EQUAL,
503    XPATH_OP_CMP,
504    XPATH_OP_PLUS,
505    XPATH_OP_MULT,
506    XPATH_OP_UNION,
507    XPATH_OP_ROOT,
508    XPATH_OP_NODE,
509    XPATH_OP_RESET, /* 10 */
510    XPATH_OP_COLLECT,
511    XPATH_OP_VALUE, /* 12 */
512    XPATH_OP_VARIABLE,
513    XPATH_OP_FUNCTION,
514    XPATH_OP_ARG,
515    XPATH_OP_PREDICATE,
516    XPATH_OP_FILTER, /* 17 */
517    XPATH_OP_SORT /* 18 */
518#ifdef LIBXML_XPTR_ENABLED
519    ,XPATH_OP_RANGETO
520#endif
521} xmlXPathOp;
522
523typedef enum {
524    AXIS_ANCESTOR = 1,
525    AXIS_ANCESTOR_OR_SELF,
526    AXIS_ATTRIBUTE,
527    AXIS_CHILD,
528    AXIS_DESCENDANT,
529    AXIS_DESCENDANT_OR_SELF,
530    AXIS_FOLLOWING,
531    AXIS_FOLLOWING_SIBLING,
532    AXIS_NAMESPACE,
533    AXIS_PARENT,
534    AXIS_PRECEDING,
535    AXIS_PRECEDING_SIBLING,
536    AXIS_SELF
537} xmlXPathAxisVal;
538
539typedef enum {
540    NODE_TEST_NONE = 0,
541    NODE_TEST_TYPE = 1,
542    NODE_TEST_PI = 2,
543    NODE_TEST_ALL = 3,
544    NODE_TEST_NS = 4,
545    NODE_TEST_NAME = 5
546} xmlXPathTestVal;
547
548typedef enum {
549    NODE_TYPE_NODE = 0,
550    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
551    NODE_TYPE_TEXT = XML_TEXT_NODE,
552    NODE_TYPE_PI = XML_PI_NODE
553} xmlXPathTypeVal;
554
555#define XP_REWRITE_DOS_CHILD_ELEM 1
556
557typedef struct _xmlXPathStepOp xmlXPathStepOp;
558typedef xmlXPathStepOp *xmlXPathStepOpPtr;
559struct _xmlXPathStepOp {
560    xmlXPathOp op;		/* The identifier of the operation */
561    int ch1;			/* First child */
562    int ch2;			/* Second child */
563    int value;
564    int value2;
565    int value3;
566    void *value4;
567    void *value5;
568    void *cache;
569    void *cacheURI;
570    int rewriteType;
571};
572
573struct _xmlXPathCompExpr {
574    int nbStep;			/* Number of steps in this expression */
575    int maxStep;		/* Maximum number of steps allocated */
576    xmlXPathStepOp *steps;	/* ops for computation of this expression */
577    int last;			/* index of last step in expression */
578    xmlChar *expr;		/* the expression being computed */
579    xmlDictPtr dict;		/* the dictionnary to use if any */
580#ifdef DEBUG_EVAL_COUNTS
581    int nb;
582    xmlChar *string;
583#endif
584#ifdef XPATH_STREAMING
585    xmlPatternPtr stream;
586#endif
587};
588
589/************************************************************************
590 *									*
591 *			Forward declarations				*
592 *									*
593 ************************************************************************/
594static void
595xmlXPathFreeValueTree(xmlNodeSetPtr obj);
596static void
597xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
598static int
599xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
600                        xmlXPathStepOpPtr op, xmlNodePtr *first);
601static int
602xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
603			    xmlXPathStepOpPtr op,
604			    int isPredicate);
605
606/************************************************************************
607 *									*
608 *			Parser Type functions				*
609 *									*
610 ************************************************************************/
611
612/**
613 * xmlXPathNewCompExpr:
614 *
615 * Create a new Xpath component
616 *
617 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
618 */
619static xmlXPathCompExprPtr
620xmlXPathNewCompExpr(void) {
621    xmlXPathCompExprPtr cur;
622
623    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
624    if (cur == NULL) {
625        xmlXPathErrMemory(NULL, "allocating component\n");
626	return(NULL);
627    }
628    memset(cur, 0, sizeof(xmlXPathCompExpr));
629    cur->maxStep = 10;
630    cur->nbStep = 0;
631    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
632	                                   sizeof(xmlXPathStepOp));
633    if (cur->steps == NULL) {
634        xmlXPathErrMemory(NULL, "allocating steps\n");
635	xmlFree(cur);
636	return(NULL);
637    }
638    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
639    cur->last = -1;
640#ifdef DEBUG_EVAL_COUNTS
641    cur->nb = 0;
642#endif
643    return(cur);
644}
645
646/**
647 * xmlXPathFreeCompExpr:
648 * @comp:  an XPATH comp
649 *
650 * Free up the memory allocated by @comp
651 */
652void
653xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
654{
655    xmlXPathStepOpPtr op;
656    int i;
657
658    if (comp == NULL)
659        return;
660    if (comp->dict == NULL) {
661	for (i = 0; i < comp->nbStep; i++) {
662	    op = &comp->steps[i];
663	    if (op->value4 != NULL) {
664		if (op->op == XPATH_OP_VALUE)
665		    xmlXPathFreeObject(op->value4);
666		else
667		    xmlFree(op->value4);
668	    }
669	    if (op->value5 != NULL)
670		xmlFree(op->value5);
671	}
672    } else {
673	for (i = 0; i < comp->nbStep; i++) {
674	    op = &comp->steps[i];
675	    if (op->value4 != NULL) {
676		if (op->op == XPATH_OP_VALUE)
677		    xmlXPathFreeObject(op->value4);
678	    }
679	}
680        xmlDictFree(comp->dict);
681    }
682    if (comp->steps != NULL) {
683        xmlFree(comp->steps);
684    }
685#ifdef DEBUG_EVAL_COUNTS
686    if (comp->string != NULL) {
687        xmlFree(comp->string);
688    }
689#endif
690#ifdef XPATH_STREAMING
691    if (comp->stream != NULL) {
692        xmlFreePatternList(comp->stream);
693    }
694#endif
695    if (comp->expr != NULL) {
696        xmlFree(comp->expr);
697    }
698
699    xmlFree(comp);
700}
701
702/**
703 * xmlXPathCompExprAdd:
704 * @comp:  the compiled expression
705 * @ch1: first child index
706 * @ch2: second child index
707 * @op:  an op
708 * @value:  the first int value
709 * @value2:  the second int value
710 * @value3:  the third int value
711 * @value4:  the first string value
712 * @value5:  the second string value
713 *
714 * Add a step to an XPath Compiled Expression
715 *
716 * Returns -1 in case of failure, the index otherwise
717 */
718static int
719xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
720   xmlXPathOp op, int value,
721   int value2, int value3, void *value4, void *value5) {
722    if (comp->nbStep >= comp->maxStep) {
723	xmlXPathStepOp *real;
724
725	comp->maxStep *= 2;
726	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
727		                      comp->maxStep * sizeof(xmlXPathStepOp));
728	if (real == NULL) {
729	    comp->maxStep /= 2;
730	    xmlXPathErrMemory(NULL, "adding step\n");
731	    return(-1);
732	}
733	comp->steps = real;
734    }
735    comp->last = comp->nbStep;
736    comp->steps[comp->nbStep].rewriteType = 0;
737    comp->steps[comp->nbStep].ch1 = ch1;
738    comp->steps[comp->nbStep].ch2 = ch2;
739    comp->steps[comp->nbStep].op = op;
740    comp->steps[comp->nbStep].value = value;
741    comp->steps[comp->nbStep].value2 = value2;
742    comp->steps[comp->nbStep].value3 = value3;
743    if ((comp->dict != NULL) &&
744        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
745	 (op == XPATH_OP_COLLECT))) {
746        if (value4 != NULL) {
747	    comp->steps[comp->nbStep].value4 = (xmlChar *)
748	        (void *)xmlDictLookup(comp->dict, value4, -1);
749	    xmlFree(value4);
750	} else
751	    comp->steps[comp->nbStep].value4 = NULL;
752        if (value5 != NULL) {
753	    comp->steps[comp->nbStep].value5 = (xmlChar *)
754	        (void *)xmlDictLookup(comp->dict, value5, -1);
755	    xmlFree(value5);
756	} else
757	    comp->steps[comp->nbStep].value5 = NULL;
758    } else {
759	comp->steps[comp->nbStep].value4 = value4;
760	comp->steps[comp->nbStep].value5 = value5;
761    }
762    comp->steps[comp->nbStep].cache = NULL;
763    return(comp->nbStep++);
764}
765
766/**
767 * xmlXPathCompSwap:
768 * @comp:  the compiled expression
769 * @op: operation index
770 *
771 * Swaps 2 operations in the compiled expression
772 */
773static void
774xmlXPathCompSwap(xmlXPathStepOpPtr op) {
775    int tmp;
776
777#ifndef LIBXML_THREAD_ENABLED
778    /*
779     * Since this manipulates possibly shared variables, this is
780     * disabled if one detects that the library is used in a multithreaded
781     * application
782     */
783    if (xmlXPathDisableOptimizer)
784	return;
785#endif
786
787    tmp = op->ch1;
788    op->ch1 = op->ch2;
789    op->ch2 = tmp;
790}
791
792#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
793    xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
794	                (op), (val), (val2), (val3), (val4), (val5))
795#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
796    xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
797	                (op), (val), (val2), (val3), (val4), (val5))
798
799#define PUSH_LEAVE_EXPR(op, val, val2)					\
800xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
801
802#define PUSH_UNARY_EXPR(op, ch, val, val2)				\
803xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
804
805#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
806xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
807			(val), (val2), 0 ,NULL ,NULL)
808
809/************************************************************************
810 *									*
811 *		XPath object cache structures				*
812 *									*
813 ************************************************************************/
814
815/* #define XP_DEFAULT_CACHE_ON */
816
817#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
818
819typedef struct _xmlXPathContextCache xmlXPathContextCache;
820typedef xmlXPathContextCache *xmlXPathContextCachePtr;
821struct _xmlXPathContextCache {
822    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
823    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
824    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
825    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
826    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
827    int maxNodeset;
828    int maxString;
829    int maxBoolean;
830    int maxNumber;
831    int maxMisc;
832#ifdef XP_DEBUG_OBJ_USAGE
833    int dbgCachedAll;
834    int dbgCachedNodeset;
835    int dbgCachedString;
836    int dbgCachedBool;
837    int dbgCachedNumber;
838    int dbgCachedPoint;
839    int dbgCachedRange;
840    int dbgCachedLocset;
841    int dbgCachedUsers;
842    int dbgCachedXSLTTree;
843    int dbgCachedUndefined;
844
845
846    int dbgReusedAll;
847    int dbgReusedNodeset;
848    int dbgReusedString;
849    int dbgReusedBool;
850    int dbgReusedNumber;
851    int dbgReusedPoint;
852    int dbgReusedRange;
853    int dbgReusedLocset;
854    int dbgReusedUsers;
855    int dbgReusedXSLTTree;
856    int dbgReusedUndefined;
857
858#endif
859};
860
861/************************************************************************
862 *									*
863 *		Debugging related functions				*
864 *									*
865 ************************************************************************/
866
867#define STRANGE							\
868    xmlGenericError(xmlGenericErrorContext,				\
869	    "Internal error at %s:%d\n",				\
870            __FILE__, __LINE__);
871
872#ifdef LIBXML_DEBUG_ENABLED
873static void
874xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
875    int i;
876    char shift[100];
877
878    for (i = 0;((i < depth) && (i < 25));i++)
879        shift[2 * i] = shift[2 * i + 1] = ' ';
880    shift[2 * i] = shift[2 * i + 1] = 0;
881    if (cur == NULL) {
882	fprintf(output, "%s", shift);
883	fprintf(output, "Node is NULL !\n");
884	return;
885
886    }
887
888    if ((cur->type == XML_DOCUMENT_NODE) ||
889	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
890	fprintf(output, "%s", shift);
891	fprintf(output, " /\n");
892    } else if (cur->type == XML_ATTRIBUTE_NODE)
893	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
894    else
895	xmlDebugDumpOneNode(output, cur, depth);
896}
897static void
898xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
899    xmlNodePtr tmp;
900    int i;
901    char shift[100];
902
903    for (i = 0;((i < depth) && (i < 25));i++)
904        shift[2 * i] = shift[2 * i + 1] = ' ';
905    shift[2 * i] = shift[2 * i + 1] = 0;
906    if (cur == NULL) {
907	fprintf(output, "%s", shift);
908	fprintf(output, "Node is NULL !\n");
909	return;
910
911    }
912
913    while (cur != NULL) {
914	tmp = cur;
915	cur = cur->next;
916	xmlDebugDumpOneNode(output, tmp, depth);
917    }
918}
919
920static void
921xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
922    int i;
923    char shift[100];
924
925    for (i = 0;((i < depth) && (i < 25));i++)
926        shift[2 * i] = shift[2 * i + 1] = ' ';
927    shift[2 * i] = shift[2 * i + 1] = 0;
928
929    if (cur == NULL) {
930	fprintf(output, "%s", shift);
931	fprintf(output, "NodeSet is NULL !\n");
932	return;
933
934    }
935
936    if (cur != NULL) {
937	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
938	for (i = 0;i < cur->nodeNr;i++) {
939	    fprintf(output, "%s", shift);
940	    fprintf(output, "%d", i + 1);
941	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
942	}
943    }
944}
945
946static void
947xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
948    int i;
949    char shift[100];
950
951    for (i = 0;((i < depth) && (i < 25));i++)
952        shift[2 * i] = shift[2 * i + 1] = ' ';
953    shift[2 * i] = shift[2 * i + 1] = 0;
954
955    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
956	fprintf(output, "%s", shift);
957	fprintf(output, "Value Tree is NULL !\n");
958	return;
959
960    }
961
962    fprintf(output, "%s", shift);
963    fprintf(output, "%d", i + 1);
964    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
965}
966#if defined(LIBXML_XPTR_ENABLED)
967static void
968xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
969    int i;
970    char shift[100];
971
972    for (i = 0;((i < depth) && (i < 25));i++)
973        shift[2 * i] = shift[2 * i + 1] = ' ';
974    shift[2 * i] = shift[2 * i + 1] = 0;
975
976    if (cur == NULL) {
977	fprintf(output, "%s", shift);
978	fprintf(output, "LocationSet is NULL !\n");
979	return;
980
981    }
982
983    for (i = 0;i < cur->locNr;i++) {
984	fprintf(output, "%s", shift);
985        fprintf(output, "%d : ", i + 1);
986	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
987    }
988}
989#endif /* LIBXML_XPTR_ENABLED */
990
991/**
992 * xmlXPathDebugDumpObject:
993 * @output:  the FILE * to dump the output
994 * @cur:  the object to inspect
995 * @depth:  indentation level
996 *
997 * Dump the content of the object for debugging purposes
998 */
999void
1000xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1001    int i;
1002    char shift[100];
1003
1004    if (output == NULL) return;
1005
1006    for (i = 0;((i < depth) && (i < 25));i++)
1007        shift[2 * i] = shift[2 * i + 1] = ' ';
1008    shift[2 * i] = shift[2 * i + 1] = 0;
1009
1010
1011    fprintf(output, "%s", shift);
1012
1013    if (cur == NULL) {
1014        fprintf(output, "Object is empty (NULL)\n");
1015	return;
1016    }
1017    switch(cur->type) {
1018        case XPATH_UNDEFINED:
1019	    fprintf(output, "Object is uninitialized\n");
1020	    break;
1021        case XPATH_NODESET:
1022	    fprintf(output, "Object is a Node Set :\n");
1023	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1024	    break;
1025	case XPATH_XSLT_TREE:
1026	    fprintf(output, "Object is an XSLT value tree :\n");
1027	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1028	    break;
1029        case XPATH_BOOLEAN:
1030	    fprintf(output, "Object is a Boolean : ");
1031	    if (cur->boolval) fprintf(output, "true\n");
1032	    else fprintf(output, "false\n");
1033	    break;
1034        case XPATH_NUMBER:
1035	    switch (xmlXPathIsInf(cur->floatval)) {
1036	    case 1:
1037		fprintf(output, "Object is a number : Infinity\n");
1038		break;
1039	    case -1:
1040		fprintf(output, "Object is a number : -Infinity\n");
1041		break;
1042	    default:
1043		if (xmlXPathIsNaN(cur->floatval)) {
1044		    fprintf(output, "Object is a number : NaN\n");
1045		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1046		    fprintf(output, "Object is a number : 0\n");
1047		} else {
1048		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1049		}
1050	    }
1051	    break;
1052        case XPATH_STRING:
1053	    fprintf(output, "Object is a string : ");
1054	    xmlDebugDumpString(output, cur->stringval);
1055	    fprintf(output, "\n");
1056	    break;
1057	case XPATH_POINT:
1058	    fprintf(output, "Object is a point : index %d in node", cur->index);
1059	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1060	    fprintf(output, "\n");
1061	    break;
1062	case XPATH_RANGE:
1063	    if ((cur->user2 == NULL) ||
1064		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1065		fprintf(output, "Object is a collapsed range :\n");
1066		fprintf(output, "%s", shift);
1067		if (cur->index >= 0)
1068		    fprintf(output, "index %d in ", cur->index);
1069		fprintf(output, "node\n");
1070		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1071			              depth + 1);
1072	    } else  {
1073		fprintf(output, "Object is a range :\n");
1074		fprintf(output, "%s", shift);
1075		fprintf(output, "From ");
1076		if (cur->index >= 0)
1077		    fprintf(output, "index %d in ", cur->index);
1078		fprintf(output, "node\n");
1079		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1080			              depth + 1);
1081		fprintf(output, "%s", shift);
1082		fprintf(output, "To ");
1083		if (cur->index2 >= 0)
1084		    fprintf(output, "index %d in ", cur->index2);
1085		fprintf(output, "node\n");
1086		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1087			              depth + 1);
1088		fprintf(output, "\n");
1089	    }
1090	    break;
1091	case XPATH_LOCATIONSET:
1092#if defined(LIBXML_XPTR_ENABLED)
1093	    fprintf(output, "Object is a Location Set:\n");
1094	    xmlXPathDebugDumpLocationSet(output,
1095		    (xmlLocationSetPtr) cur->user, depth);
1096#endif
1097	    break;
1098	case XPATH_USERS:
1099	    fprintf(output, "Object is user defined\n");
1100	    break;
1101    }
1102}
1103
1104static void
1105xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1106	                     xmlXPathStepOpPtr op, int depth) {
1107    int i;
1108    char shift[100];
1109
1110    for (i = 0;((i < depth) && (i < 25));i++)
1111        shift[2 * i] = shift[2 * i + 1] = ' ';
1112    shift[2 * i] = shift[2 * i + 1] = 0;
1113
1114    fprintf(output, "%s", shift);
1115    if (op == NULL) {
1116	fprintf(output, "Step is NULL\n");
1117	return;
1118    }
1119    switch (op->op) {
1120        case XPATH_OP_END:
1121	    fprintf(output, "END"); break;
1122        case XPATH_OP_AND:
1123	    fprintf(output, "AND"); break;
1124        case XPATH_OP_OR:
1125	    fprintf(output, "OR"); break;
1126        case XPATH_OP_EQUAL:
1127	     if (op->value)
1128		 fprintf(output, "EQUAL =");
1129	     else
1130		 fprintf(output, "EQUAL !=");
1131	     break;
1132        case XPATH_OP_CMP:
1133	     if (op->value)
1134		 fprintf(output, "CMP <");
1135	     else
1136		 fprintf(output, "CMP >");
1137	     if (!op->value2)
1138		 fprintf(output, "=");
1139	     break;
1140        case XPATH_OP_PLUS:
1141	     if (op->value == 0)
1142		 fprintf(output, "PLUS -");
1143	     else if (op->value == 1)
1144		 fprintf(output, "PLUS +");
1145	     else if (op->value == 2)
1146		 fprintf(output, "PLUS unary -");
1147	     else if (op->value == 3)
1148		 fprintf(output, "PLUS unary - -");
1149	     break;
1150        case XPATH_OP_MULT:
1151	     if (op->value == 0)
1152		 fprintf(output, "MULT *");
1153	     else if (op->value == 1)
1154		 fprintf(output, "MULT div");
1155	     else
1156		 fprintf(output, "MULT mod");
1157	     break;
1158        case XPATH_OP_UNION:
1159	     fprintf(output, "UNION"); break;
1160        case XPATH_OP_ROOT:
1161	     fprintf(output, "ROOT"); break;
1162        case XPATH_OP_NODE:
1163	     fprintf(output, "NODE"); break;
1164        case XPATH_OP_RESET:
1165	     fprintf(output, "RESET"); break;
1166        case XPATH_OP_SORT:
1167	     fprintf(output, "SORT"); break;
1168        case XPATH_OP_COLLECT: {
1169	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1170	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1171	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1172	    const xmlChar *prefix = op->value4;
1173	    const xmlChar *name = op->value5;
1174
1175	    fprintf(output, "COLLECT ");
1176	    switch (axis) {
1177		case AXIS_ANCESTOR:
1178		    fprintf(output, " 'ancestors' "); break;
1179		case AXIS_ANCESTOR_OR_SELF:
1180		    fprintf(output, " 'ancestors-or-self' "); break;
1181		case AXIS_ATTRIBUTE:
1182		    fprintf(output, " 'attributes' "); break;
1183		case AXIS_CHILD:
1184		    fprintf(output, " 'child' "); break;
1185		case AXIS_DESCENDANT:
1186		    fprintf(output, " 'descendant' "); break;
1187		case AXIS_DESCENDANT_OR_SELF:
1188		    fprintf(output, " 'descendant-or-self' "); break;
1189		case AXIS_FOLLOWING:
1190		    fprintf(output, " 'following' "); break;
1191		case AXIS_FOLLOWING_SIBLING:
1192		    fprintf(output, " 'following-siblings' "); break;
1193		case AXIS_NAMESPACE:
1194		    fprintf(output, " 'namespace' "); break;
1195		case AXIS_PARENT:
1196		    fprintf(output, " 'parent' "); break;
1197		case AXIS_PRECEDING:
1198		    fprintf(output, " 'preceding' "); break;
1199		case AXIS_PRECEDING_SIBLING:
1200		    fprintf(output, " 'preceding-sibling' "); break;
1201		case AXIS_SELF:
1202		    fprintf(output, " 'self' "); break;
1203	    }
1204	    switch (test) {
1205                case NODE_TEST_NONE:
1206		    fprintf(output, "'none' "); break;
1207                case NODE_TEST_TYPE:
1208		    fprintf(output, "'type' "); break;
1209                case NODE_TEST_PI:
1210		    fprintf(output, "'PI' "); break;
1211                case NODE_TEST_ALL:
1212		    fprintf(output, "'all' "); break;
1213                case NODE_TEST_NS:
1214		    fprintf(output, "'namespace' "); break;
1215                case NODE_TEST_NAME:
1216		    fprintf(output, "'name' "); break;
1217	    }
1218	    switch (type) {
1219                case NODE_TYPE_NODE:
1220		    fprintf(output, "'node' "); break;
1221                case NODE_TYPE_COMMENT:
1222		    fprintf(output, "'comment' "); break;
1223                case NODE_TYPE_TEXT:
1224		    fprintf(output, "'text' "); break;
1225                case NODE_TYPE_PI:
1226		    fprintf(output, "'PI' "); break;
1227	    }
1228	    if (prefix != NULL)
1229		fprintf(output, "%s:", prefix);
1230	    if (name != NULL)
1231		fprintf(output, "%s", (const char *) name);
1232	    break;
1233
1234        }
1235	case XPATH_OP_VALUE: {
1236	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1237
1238	    fprintf(output, "ELEM ");
1239	    xmlXPathDebugDumpObject(output, object, 0);
1240	    goto finish;
1241	}
1242	case XPATH_OP_VARIABLE: {
1243	    const xmlChar *prefix = op->value5;
1244	    const xmlChar *name = op->value4;
1245
1246	    if (prefix != NULL)
1247		fprintf(output, "VARIABLE %s:%s", prefix, name);
1248	    else
1249		fprintf(output, "VARIABLE %s", name);
1250	    break;
1251	}
1252	case XPATH_OP_FUNCTION: {
1253	    int nbargs = op->value;
1254	    const xmlChar *prefix = op->value5;
1255	    const xmlChar *name = op->value4;
1256
1257	    if (prefix != NULL)
1258		fprintf(output, "FUNCTION %s:%s(%d args)",
1259			prefix, name, nbargs);
1260	    else
1261		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1262	    break;
1263	}
1264        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1265        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1266        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1267#ifdef LIBXML_XPTR_ENABLED
1268        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1269#endif
1270	default:
1271        fprintf(output, "UNKNOWN %d\n", op->op); return;
1272    }
1273    fprintf(output, "\n");
1274finish:
1275    if (op->ch1 >= 0)
1276	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1277    if (op->ch2 >= 0)
1278	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1279}
1280
1281/**
1282 * xmlXPathDebugDumpCompExpr:
1283 * @output:  the FILE * for the output
1284 * @comp:  the precompiled XPath expression
1285 * @depth:  the indentation level.
1286 *
1287 * Dumps the tree of the compiled XPath expression.
1288 */
1289void
1290xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1291	                  int depth) {
1292    int i;
1293    char shift[100];
1294
1295    if ((output == NULL) || (comp == NULL)) return;
1296
1297    for (i = 0;((i < depth) && (i < 25));i++)
1298        shift[2 * i] = shift[2 * i + 1] = ' ';
1299    shift[2 * i] = shift[2 * i + 1] = 0;
1300
1301    fprintf(output, "%s", shift);
1302
1303    fprintf(output, "Compiled Expression : %d elements\n",
1304	    comp->nbStep);
1305    i = comp->last;
1306    xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1307}
1308
1309#ifdef XP_DEBUG_OBJ_USAGE
1310
1311/*
1312* XPath object usage related debugging variables.
1313*/
1314static int xmlXPathDebugObjCounterUndefined = 0;
1315static int xmlXPathDebugObjCounterNodeset = 0;
1316static int xmlXPathDebugObjCounterBool = 0;
1317static int xmlXPathDebugObjCounterNumber = 0;
1318static int xmlXPathDebugObjCounterString = 0;
1319static int xmlXPathDebugObjCounterPoint = 0;
1320static int xmlXPathDebugObjCounterRange = 0;
1321static int xmlXPathDebugObjCounterLocset = 0;
1322static int xmlXPathDebugObjCounterUsers = 0;
1323static int xmlXPathDebugObjCounterXSLTTree = 0;
1324static int xmlXPathDebugObjCounterAll = 0;
1325
1326static int xmlXPathDebugObjTotalUndefined = 0;
1327static int xmlXPathDebugObjTotalNodeset = 0;
1328static int xmlXPathDebugObjTotalBool = 0;
1329static int xmlXPathDebugObjTotalNumber = 0;
1330static int xmlXPathDebugObjTotalString = 0;
1331static int xmlXPathDebugObjTotalPoint = 0;
1332static int xmlXPathDebugObjTotalRange = 0;
1333static int xmlXPathDebugObjTotalLocset = 0;
1334static int xmlXPathDebugObjTotalUsers = 0;
1335static int xmlXPathDebugObjTotalXSLTTree = 0;
1336static int xmlXPathDebugObjTotalAll = 0;
1337
1338static int xmlXPathDebugObjMaxUndefined = 0;
1339static int xmlXPathDebugObjMaxNodeset = 0;
1340static int xmlXPathDebugObjMaxBool = 0;
1341static int xmlXPathDebugObjMaxNumber = 0;
1342static int xmlXPathDebugObjMaxString = 0;
1343static int xmlXPathDebugObjMaxPoint = 0;
1344static int xmlXPathDebugObjMaxRange = 0;
1345static int xmlXPathDebugObjMaxLocset = 0;
1346static int xmlXPathDebugObjMaxUsers = 0;
1347static int xmlXPathDebugObjMaxXSLTTree = 0;
1348static int xmlXPathDebugObjMaxAll = 0;
1349
1350/* REVISIT TODO: Make this static when committing */
1351static void
1352xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1353{
1354    if (ctxt != NULL) {
1355	if (ctxt->cache != NULL) {
1356	    xmlXPathContextCachePtr cache =
1357		(xmlXPathContextCachePtr) ctxt->cache;
1358
1359	    cache->dbgCachedAll = 0;
1360	    cache->dbgCachedNodeset = 0;
1361	    cache->dbgCachedString = 0;
1362	    cache->dbgCachedBool = 0;
1363	    cache->dbgCachedNumber = 0;
1364	    cache->dbgCachedPoint = 0;
1365	    cache->dbgCachedRange = 0;
1366	    cache->dbgCachedLocset = 0;
1367	    cache->dbgCachedUsers = 0;
1368	    cache->dbgCachedXSLTTree = 0;
1369	    cache->dbgCachedUndefined = 0;
1370
1371	    cache->dbgReusedAll = 0;
1372	    cache->dbgReusedNodeset = 0;
1373	    cache->dbgReusedString = 0;
1374	    cache->dbgReusedBool = 0;
1375	    cache->dbgReusedNumber = 0;
1376	    cache->dbgReusedPoint = 0;
1377	    cache->dbgReusedRange = 0;
1378	    cache->dbgReusedLocset = 0;
1379	    cache->dbgReusedUsers = 0;
1380	    cache->dbgReusedXSLTTree = 0;
1381	    cache->dbgReusedUndefined = 0;
1382	}
1383    }
1384
1385    xmlXPathDebugObjCounterUndefined = 0;
1386    xmlXPathDebugObjCounterNodeset = 0;
1387    xmlXPathDebugObjCounterBool = 0;
1388    xmlXPathDebugObjCounterNumber = 0;
1389    xmlXPathDebugObjCounterString = 0;
1390    xmlXPathDebugObjCounterPoint = 0;
1391    xmlXPathDebugObjCounterRange = 0;
1392    xmlXPathDebugObjCounterLocset = 0;
1393    xmlXPathDebugObjCounterUsers = 0;
1394    xmlXPathDebugObjCounterXSLTTree = 0;
1395    xmlXPathDebugObjCounterAll = 0;
1396
1397    xmlXPathDebugObjTotalUndefined = 0;
1398    xmlXPathDebugObjTotalNodeset = 0;
1399    xmlXPathDebugObjTotalBool = 0;
1400    xmlXPathDebugObjTotalNumber = 0;
1401    xmlXPathDebugObjTotalString = 0;
1402    xmlXPathDebugObjTotalPoint = 0;
1403    xmlXPathDebugObjTotalRange = 0;
1404    xmlXPathDebugObjTotalLocset = 0;
1405    xmlXPathDebugObjTotalUsers = 0;
1406    xmlXPathDebugObjTotalXSLTTree = 0;
1407    xmlXPathDebugObjTotalAll = 0;
1408
1409    xmlXPathDebugObjMaxUndefined = 0;
1410    xmlXPathDebugObjMaxNodeset = 0;
1411    xmlXPathDebugObjMaxBool = 0;
1412    xmlXPathDebugObjMaxNumber = 0;
1413    xmlXPathDebugObjMaxString = 0;
1414    xmlXPathDebugObjMaxPoint = 0;
1415    xmlXPathDebugObjMaxRange = 0;
1416    xmlXPathDebugObjMaxLocset = 0;
1417    xmlXPathDebugObjMaxUsers = 0;
1418    xmlXPathDebugObjMaxXSLTTree = 0;
1419    xmlXPathDebugObjMaxAll = 0;
1420
1421}
1422
1423static void
1424xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1425			      xmlXPathObjectType objType)
1426{
1427    int isCached = 0;
1428
1429    if (ctxt != NULL) {
1430	if (ctxt->cache != NULL) {
1431	    xmlXPathContextCachePtr cache =
1432		(xmlXPathContextCachePtr) ctxt->cache;
1433
1434	    isCached = 1;
1435
1436	    cache->dbgReusedAll++;
1437	    switch (objType) {
1438		case XPATH_UNDEFINED:
1439		    cache->dbgReusedUndefined++;
1440		    break;
1441		case XPATH_NODESET:
1442		    cache->dbgReusedNodeset++;
1443		    break;
1444		case XPATH_BOOLEAN:
1445		    cache->dbgReusedBool++;
1446		    break;
1447		case XPATH_NUMBER:
1448		    cache->dbgReusedNumber++;
1449		    break;
1450		case XPATH_STRING:
1451		    cache->dbgReusedString++;
1452		    break;
1453		case XPATH_POINT:
1454		    cache->dbgReusedPoint++;
1455		    break;
1456		case XPATH_RANGE:
1457		    cache->dbgReusedRange++;
1458		    break;
1459		case XPATH_LOCATIONSET:
1460		    cache->dbgReusedLocset++;
1461		    break;
1462		case XPATH_USERS:
1463		    cache->dbgReusedUsers++;
1464		    break;
1465		case XPATH_XSLT_TREE:
1466		    cache->dbgReusedXSLTTree++;
1467		    break;
1468		default:
1469		    break;
1470	    }
1471	}
1472    }
1473
1474    switch (objType) {
1475	case XPATH_UNDEFINED:
1476	    if (! isCached)
1477		xmlXPathDebugObjTotalUndefined++;
1478	    xmlXPathDebugObjCounterUndefined++;
1479	    if (xmlXPathDebugObjCounterUndefined >
1480		xmlXPathDebugObjMaxUndefined)
1481		xmlXPathDebugObjMaxUndefined =
1482		    xmlXPathDebugObjCounterUndefined;
1483	    break;
1484	case XPATH_NODESET:
1485	    if (! isCached)
1486		xmlXPathDebugObjTotalNodeset++;
1487	    xmlXPathDebugObjCounterNodeset++;
1488	    if (xmlXPathDebugObjCounterNodeset >
1489		xmlXPathDebugObjMaxNodeset)
1490		xmlXPathDebugObjMaxNodeset =
1491		    xmlXPathDebugObjCounterNodeset;
1492	    break;
1493	case XPATH_BOOLEAN:
1494	    if (! isCached)
1495		xmlXPathDebugObjTotalBool++;
1496	    xmlXPathDebugObjCounterBool++;
1497	    if (xmlXPathDebugObjCounterBool >
1498		xmlXPathDebugObjMaxBool)
1499		xmlXPathDebugObjMaxBool =
1500		    xmlXPathDebugObjCounterBool;
1501	    break;
1502	case XPATH_NUMBER:
1503	    if (! isCached)
1504		xmlXPathDebugObjTotalNumber++;
1505	    xmlXPathDebugObjCounterNumber++;
1506	    if (xmlXPathDebugObjCounterNumber >
1507		xmlXPathDebugObjMaxNumber)
1508		xmlXPathDebugObjMaxNumber =
1509		    xmlXPathDebugObjCounterNumber;
1510	    break;
1511	case XPATH_STRING:
1512	    if (! isCached)
1513		xmlXPathDebugObjTotalString++;
1514	    xmlXPathDebugObjCounterString++;
1515	    if (xmlXPathDebugObjCounterString >
1516		xmlXPathDebugObjMaxString)
1517		xmlXPathDebugObjMaxString =
1518		    xmlXPathDebugObjCounterString;
1519	    break;
1520	case XPATH_POINT:
1521	    if (! isCached)
1522		xmlXPathDebugObjTotalPoint++;
1523	    xmlXPathDebugObjCounterPoint++;
1524	    if (xmlXPathDebugObjCounterPoint >
1525		xmlXPathDebugObjMaxPoint)
1526		xmlXPathDebugObjMaxPoint =
1527		    xmlXPathDebugObjCounterPoint;
1528	    break;
1529	case XPATH_RANGE:
1530	    if (! isCached)
1531		xmlXPathDebugObjTotalRange++;
1532	    xmlXPathDebugObjCounterRange++;
1533	    if (xmlXPathDebugObjCounterRange >
1534		xmlXPathDebugObjMaxRange)
1535		xmlXPathDebugObjMaxRange =
1536		    xmlXPathDebugObjCounterRange;
1537	    break;
1538	case XPATH_LOCATIONSET:
1539	    if (! isCached)
1540		xmlXPathDebugObjTotalLocset++;
1541	    xmlXPathDebugObjCounterLocset++;
1542	    if (xmlXPathDebugObjCounterLocset >
1543		xmlXPathDebugObjMaxLocset)
1544		xmlXPathDebugObjMaxLocset =
1545		    xmlXPathDebugObjCounterLocset;
1546	    break;
1547	case XPATH_USERS:
1548	    if (! isCached)
1549		xmlXPathDebugObjTotalUsers++;
1550	    xmlXPathDebugObjCounterUsers++;
1551	    if (xmlXPathDebugObjCounterUsers >
1552		xmlXPathDebugObjMaxUsers)
1553		xmlXPathDebugObjMaxUsers =
1554		    xmlXPathDebugObjCounterUsers;
1555	    break;
1556	case XPATH_XSLT_TREE:
1557	    if (! isCached)
1558		xmlXPathDebugObjTotalXSLTTree++;
1559	    xmlXPathDebugObjCounterXSLTTree++;
1560	    if (xmlXPathDebugObjCounterXSLTTree >
1561		xmlXPathDebugObjMaxXSLTTree)
1562		xmlXPathDebugObjMaxXSLTTree =
1563		    xmlXPathDebugObjCounterXSLTTree;
1564	    break;
1565	default:
1566	    break;
1567    }
1568    if (! isCached)
1569	xmlXPathDebugObjTotalAll++;
1570    xmlXPathDebugObjCounterAll++;
1571    if (xmlXPathDebugObjCounterAll >
1572	xmlXPathDebugObjMaxAll)
1573	xmlXPathDebugObjMaxAll =
1574	    xmlXPathDebugObjCounterAll;
1575}
1576
1577static void
1578xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1579			      xmlXPathObjectType objType)
1580{
1581    int isCached = 0;
1582
1583    if (ctxt != NULL) {
1584	if (ctxt->cache != NULL) {
1585	    xmlXPathContextCachePtr cache =
1586		(xmlXPathContextCachePtr) ctxt->cache;
1587
1588	    isCached = 1;
1589
1590	    cache->dbgCachedAll++;
1591	    switch (objType) {
1592		case XPATH_UNDEFINED:
1593		    cache->dbgCachedUndefined++;
1594		    break;
1595		case XPATH_NODESET:
1596		    cache->dbgCachedNodeset++;
1597		    break;
1598		case XPATH_BOOLEAN:
1599		    cache->dbgCachedBool++;
1600		    break;
1601		case XPATH_NUMBER:
1602		    cache->dbgCachedNumber++;
1603		    break;
1604		case XPATH_STRING:
1605		    cache->dbgCachedString++;
1606		    break;
1607		case XPATH_POINT:
1608		    cache->dbgCachedPoint++;
1609		    break;
1610		case XPATH_RANGE:
1611		    cache->dbgCachedRange++;
1612		    break;
1613		case XPATH_LOCATIONSET:
1614		    cache->dbgCachedLocset++;
1615		    break;
1616		case XPATH_USERS:
1617		    cache->dbgCachedUsers++;
1618		    break;
1619		case XPATH_XSLT_TREE:
1620		    cache->dbgCachedXSLTTree++;
1621		    break;
1622		default:
1623		    break;
1624	    }
1625
1626	}
1627    }
1628    switch (objType) {
1629	case XPATH_UNDEFINED:
1630	    xmlXPathDebugObjCounterUndefined--;
1631	    break;
1632	case XPATH_NODESET:
1633	    xmlXPathDebugObjCounterNodeset--;
1634	    break;
1635	case XPATH_BOOLEAN:
1636	    xmlXPathDebugObjCounterBool--;
1637	    break;
1638	case XPATH_NUMBER:
1639	    xmlXPathDebugObjCounterNumber--;
1640	    break;
1641	case XPATH_STRING:
1642	    xmlXPathDebugObjCounterString--;
1643	    break;
1644	case XPATH_POINT:
1645	    xmlXPathDebugObjCounterPoint--;
1646	    break;
1647	case XPATH_RANGE:
1648	    xmlXPathDebugObjCounterRange--;
1649	    break;
1650	case XPATH_LOCATIONSET:
1651	    xmlXPathDebugObjCounterLocset--;
1652	    break;
1653	case XPATH_USERS:
1654	    xmlXPathDebugObjCounterUsers--;
1655	    break;
1656	case XPATH_XSLT_TREE:
1657	    xmlXPathDebugObjCounterXSLTTree--;
1658	    break;
1659	default:
1660	    break;
1661    }
1662    xmlXPathDebugObjCounterAll--;
1663}
1664
1665/* REVISIT TODO: Make this static when committing */
1666static void
1667xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1668{
1669    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1670	reqXSLTTree, reqUndefined;
1671    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1672	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1673    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1674	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1675    int leftObjs = xmlXPathDebugObjCounterAll;
1676
1677    reqAll = xmlXPathDebugObjTotalAll;
1678    reqNodeset = xmlXPathDebugObjTotalNodeset;
1679    reqString = xmlXPathDebugObjTotalString;
1680    reqBool = xmlXPathDebugObjTotalBool;
1681    reqNumber = xmlXPathDebugObjTotalNumber;
1682    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1683    reqUndefined = xmlXPathDebugObjTotalUndefined;
1684
1685    printf("# XPath object usage:\n");
1686
1687    if (ctxt != NULL) {
1688	if (ctxt->cache != NULL) {
1689	    xmlXPathContextCachePtr cache =
1690		(xmlXPathContextCachePtr) ctxt->cache;
1691
1692	    reAll = cache->dbgReusedAll;
1693	    reqAll += reAll;
1694	    reNodeset = cache->dbgReusedNodeset;
1695	    reqNodeset += reNodeset;
1696	    reString = cache->dbgReusedString;
1697	    reqString += reString;
1698	    reBool = cache->dbgReusedBool;
1699	    reqBool += reBool;
1700	    reNumber = cache->dbgReusedNumber;
1701	    reqNumber += reNumber;
1702	    reXSLTTree = cache->dbgReusedXSLTTree;
1703	    reqXSLTTree += reXSLTTree;
1704	    reUndefined = cache->dbgReusedUndefined;
1705	    reqUndefined += reUndefined;
1706
1707	    caAll = cache->dbgCachedAll;
1708	    caBool = cache->dbgCachedBool;
1709	    caNodeset = cache->dbgCachedNodeset;
1710	    caString = cache->dbgCachedString;
1711	    caNumber = cache->dbgCachedNumber;
1712	    caXSLTTree = cache->dbgCachedXSLTTree;
1713	    caUndefined = cache->dbgCachedUndefined;
1714
1715	    if (cache->nodesetObjs)
1716		leftObjs -= cache->nodesetObjs->number;
1717	    if (cache->stringObjs)
1718		leftObjs -= cache->stringObjs->number;
1719	    if (cache->booleanObjs)
1720		leftObjs -= cache->booleanObjs->number;
1721	    if (cache->numberObjs)
1722		leftObjs -= cache->numberObjs->number;
1723	    if (cache->miscObjs)
1724		leftObjs -= cache->miscObjs->number;
1725	}
1726    }
1727
1728    printf("# all\n");
1729    printf("#   total  : %d\n", reqAll);
1730    printf("#   left  : %d\n", leftObjs);
1731    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
1732    printf("#   reused : %d\n", reAll);
1733    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
1734
1735    printf("# node-sets\n");
1736    printf("#   total  : %d\n", reqNodeset);
1737    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
1738    printf("#   reused : %d\n", reNodeset);
1739    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
1740
1741    printf("# strings\n");
1742    printf("#   total  : %d\n", reqString);
1743    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
1744    printf("#   reused : %d\n", reString);
1745    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
1746
1747    printf("# booleans\n");
1748    printf("#   total  : %d\n", reqBool);
1749    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
1750    printf("#   reused : %d\n", reBool);
1751    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
1752
1753    printf("# numbers\n");
1754    printf("#   total  : %d\n", reqNumber);
1755    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
1756    printf("#   reused : %d\n", reNumber);
1757    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
1758
1759    printf("# XSLT result tree fragments\n");
1760    printf("#   total  : %d\n", reqXSLTTree);
1761    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1762    printf("#   reused : %d\n", reXSLTTree);
1763    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
1764
1765    printf("# undefined\n");
1766    printf("#   total  : %d\n", reqUndefined);
1767    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
1768    printf("#   reused : %d\n", reUndefined);
1769    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
1770
1771}
1772
1773#endif /* XP_DEBUG_OBJ_USAGE */
1774
1775#endif /* LIBXML_DEBUG_ENABLED */
1776
1777/************************************************************************
1778 *									*
1779 *			XPath object caching				*
1780 *									*
1781 ************************************************************************/
1782
1783/**
1784 * xmlXPathNewCache:
1785 *
1786 * Create a new object cache
1787 *
1788 * Returns the xmlXPathCache just allocated.
1789 */
1790static xmlXPathContextCachePtr
1791xmlXPathNewCache(void)
1792{
1793    xmlXPathContextCachePtr ret;
1794
1795    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1796    if (ret == NULL) {
1797        xmlXPathErrMemory(NULL, "creating object cache\n");
1798	return(NULL);
1799    }
1800    memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1801    ret->maxNodeset = 100;
1802    ret->maxString = 100;
1803    ret->maxBoolean = 100;
1804    ret->maxNumber = 100;
1805    ret->maxMisc = 100;
1806    return(ret);
1807}
1808
1809static void
1810xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1811{
1812    int i;
1813    xmlXPathObjectPtr obj;
1814
1815    if (list == NULL)
1816	return;
1817
1818    for (i = 0; i < list->number; i++) {
1819	obj = list->items[i];
1820	/*
1821	* Note that it is already assured that we don't need to
1822	* look out for namespace nodes in the node-set.
1823	*/
1824	if (obj->nodesetval != NULL) {
1825	    if (obj->nodesetval->nodeTab != NULL)
1826		xmlFree(obj->nodesetval->nodeTab);
1827	    xmlFree(obj->nodesetval);
1828	}
1829	xmlFree(obj);
1830#ifdef XP_DEBUG_OBJ_USAGE
1831	xmlXPathDebugObjCounterAll--;
1832#endif
1833    }
1834    xmlPointerListFree(list);
1835}
1836
1837static void
1838xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1839{
1840    if (cache == NULL)
1841	return;
1842    if (cache->nodesetObjs)
1843	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1844    if (cache->stringObjs)
1845	xmlXPathCacheFreeObjectList(cache->stringObjs);
1846    if (cache->booleanObjs)
1847	xmlXPathCacheFreeObjectList(cache->booleanObjs);
1848    if (cache->numberObjs)
1849	xmlXPathCacheFreeObjectList(cache->numberObjs);
1850    if (cache->miscObjs)
1851	xmlXPathCacheFreeObjectList(cache->miscObjs);
1852    xmlFree(cache);
1853}
1854
1855/**
1856 * xmlXPathContextSetCache:
1857 *
1858 * @ctxt:  the XPath context
1859 * @active: enables/disables (creates/frees) the cache
1860 * @value: a value with semantics dependant on @options
1861 * @options: options (currently only the value 0 is used)
1862 *
1863 * Creates/frees an object cache on the XPath context.
1864 * If activates XPath objects (xmlXPathObject) will be cached internally
1865 * to be reused.
1866 * @options:
1867 *   0: This will set the XPath object caching:
1868 *      @value:
1869 *        This will set the maximum number of XPath objects
1870 *        to be cached per slot
1871 *        There are 5 slots for: node-set, string, number, boolean, and
1872 *        misc objects. Use <0 for the default number (100).
1873 *   Other values for @options have currently no effect.
1874 *
1875 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1876 */
1877int
1878xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1879			int active,
1880			int value,
1881			int options)
1882{
1883    if (ctxt == NULL)
1884	return(-1);
1885    if (active) {
1886	xmlXPathContextCachePtr cache;
1887
1888	if (ctxt->cache == NULL) {
1889	    ctxt->cache = xmlXPathNewCache();
1890	    if (ctxt->cache == NULL)
1891		return(-1);
1892	}
1893	cache = (xmlXPathContextCachePtr) ctxt->cache;
1894	if (options == 0) {
1895	    if (value < 0)
1896		value = 100;
1897	    cache->maxNodeset = value;
1898	    cache->maxString = value;
1899	    cache->maxNumber = value;
1900	    cache->maxBoolean = value;
1901	    cache->maxMisc = value;
1902	}
1903    } else if (ctxt->cache != NULL) {
1904	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1905	ctxt->cache = NULL;
1906    }
1907    return(0);
1908}
1909
1910/**
1911 * xmlXPathCacheWrapNodeSet:
1912 * @ctxt: the XPath context
1913 * @val:  the NodePtr value
1914 *
1915 * This is the cached version of xmlXPathWrapNodeSet().
1916 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1917 *
1918 * Returns the created or reused object.
1919 */
1920static xmlXPathObjectPtr
1921xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1922{
1923    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1924	xmlXPathContextCachePtr cache =
1925	    (xmlXPathContextCachePtr) ctxt->cache;
1926
1927	if ((cache->miscObjs != NULL) &&
1928	    (cache->miscObjs->number != 0))
1929	{
1930	    xmlXPathObjectPtr ret;
1931
1932	    ret = (xmlXPathObjectPtr)
1933		cache->miscObjs->items[--cache->miscObjs->number];
1934	    ret->type = XPATH_NODESET;
1935	    ret->nodesetval = val;
1936#ifdef XP_DEBUG_OBJ_USAGE
1937	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1938#endif
1939	    return(ret);
1940	}
1941    }
1942
1943    return(xmlXPathWrapNodeSet(val));
1944
1945}
1946
1947/**
1948 * xmlXPathCacheWrapString:
1949 * @ctxt: the XPath context
1950 * @val:  the xmlChar * value
1951 *
1952 * This is the cached version of xmlXPathWrapString().
1953 * Wraps the @val string into an XPath object.
1954 *
1955 * Returns the created or reused object.
1956 */
1957static xmlXPathObjectPtr
1958xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1959{
1960    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1961	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1962
1963	if ((cache->stringObjs != NULL) &&
1964	    (cache->stringObjs->number != 0))
1965	{
1966
1967	    xmlXPathObjectPtr ret;
1968
1969	    ret = (xmlXPathObjectPtr)
1970		cache->stringObjs->items[--cache->stringObjs->number];
1971	    ret->type = XPATH_STRING;
1972	    ret->stringval = val;
1973#ifdef XP_DEBUG_OBJ_USAGE
1974	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1975#endif
1976	    return(ret);
1977	} else if ((cache->miscObjs != NULL) &&
1978	    (cache->miscObjs->number != 0))
1979	{
1980	    xmlXPathObjectPtr ret;
1981	    /*
1982	    * Fallback to misc-cache.
1983	    */
1984	    ret = (xmlXPathObjectPtr)
1985		cache->miscObjs->items[--cache->miscObjs->number];
1986
1987	    ret->type = XPATH_STRING;
1988	    ret->stringval = val;
1989#ifdef XP_DEBUG_OBJ_USAGE
1990	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1991#endif
1992	    return(ret);
1993	}
1994    }
1995    return(xmlXPathWrapString(val));
1996}
1997
1998/**
1999 * xmlXPathCacheNewNodeSet:
2000 * @ctxt: the XPath context
2001 * @val:  the NodePtr value
2002 *
2003 * This is the cached version of xmlXPathNewNodeSet().
2004 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2005 * it with the single Node @val
2006 *
2007 * Returns the created or reused object.
2008 */
2009static xmlXPathObjectPtr
2010xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2011{
2012    if ((ctxt != NULL) && (ctxt->cache)) {
2013	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2014
2015	if ((cache->nodesetObjs != NULL) &&
2016	    (cache->nodesetObjs->number != 0))
2017	{
2018	    xmlXPathObjectPtr ret;
2019	    /*
2020	    * Use the nodset-cache.
2021	    */
2022	    ret = (xmlXPathObjectPtr)
2023		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2024	    ret->type = XPATH_NODESET;
2025	    ret->boolval = 0;
2026	    if (val) {
2027		if ((ret->nodesetval->nodeMax == 0) ||
2028		    (val->type == XML_NAMESPACE_DECL))
2029		{
2030		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2031		} else {
2032		    ret->nodesetval->nodeTab[0] = val;
2033		    ret->nodesetval->nodeNr = 1;
2034		}
2035	    }
2036#ifdef XP_DEBUG_OBJ_USAGE
2037	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2038#endif
2039	    return(ret);
2040	} else if ((cache->miscObjs != NULL) &&
2041	    (cache->miscObjs->number != 0))
2042	{
2043	    xmlXPathObjectPtr ret;
2044	    /*
2045	    * Fallback to misc-cache.
2046	    */
2047
2048	    ret = (xmlXPathObjectPtr)
2049		cache->miscObjs->items[--cache->miscObjs->number];
2050
2051	    ret->type = XPATH_NODESET;
2052	    ret->boolval = 0;
2053	    ret->nodesetval = xmlXPathNodeSetCreate(val);
2054#ifdef XP_DEBUG_OBJ_USAGE
2055	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2056#endif
2057	    return(ret);
2058	}
2059    }
2060    return(xmlXPathNewNodeSet(val));
2061}
2062
2063/**
2064 * xmlXPathCacheNewCString:
2065 * @ctxt: the XPath context
2066 * @val:  the char * value
2067 *
2068 * This is the cached version of xmlXPathNewCString().
2069 * Acquire an xmlXPathObjectPtr of type string and of value @val
2070 *
2071 * Returns the created or reused object.
2072 */
2073static xmlXPathObjectPtr
2074xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2075{
2076    if ((ctxt != NULL) && (ctxt->cache)) {
2077	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2078
2079	if ((cache->stringObjs != NULL) &&
2080	    (cache->stringObjs->number != 0))
2081	{
2082	    xmlXPathObjectPtr ret;
2083
2084	    ret = (xmlXPathObjectPtr)
2085		cache->stringObjs->items[--cache->stringObjs->number];
2086
2087	    ret->type = XPATH_STRING;
2088	    ret->stringval = xmlStrdup(BAD_CAST val);
2089#ifdef XP_DEBUG_OBJ_USAGE
2090	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2091#endif
2092	    return(ret);
2093	} else if ((cache->miscObjs != NULL) &&
2094	    (cache->miscObjs->number != 0))
2095	{
2096	    xmlXPathObjectPtr ret;
2097
2098	    ret = (xmlXPathObjectPtr)
2099		cache->miscObjs->items[--cache->miscObjs->number];
2100
2101	    ret->type = XPATH_STRING;
2102	    ret->stringval = xmlStrdup(BAD_CAST val);
2103#ifdef XP_DEBUG_OBJ_USAGE
2104	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2105#endif
2106	    return(ret);
2107	}
2108    }
2109    return(xmlXPathNewCString(val));
2110}
2111
2112/**
2113 * xmlXPathCacheNewString:
2114 * @ctxt: the XPath context
2115 * @val:  the xmlChar * value
2116 *
2117 * This is the cached version of xmlXPathNewString().
2118 * Acquire an xmlXPathObjectPtr of type string and of value @val
2119 *
2120 * Returns the created or reused object.
2121 */
2122static xmlXPathObjectPtr
2123xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2124{
2125    if ((ctxt != NULL) && (ctxt->cache)) {
2126	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2127
2128	if ((cache->stringObjs != NULL) &&
2129	    (cache->stringObjs->number != 0))
2130	{
2131	    xmlXPathObjectPtr ret;
2132
2133	    ret = (xmlXPathObjectPtr)
2134		cache->stringObjs->items[--cache->stringObjs->number];
2135	    ret->type = XPATH_STRING;
2136	    if (val != NULL)
2137		ret->stringval = xmlStrdup(val);
2138	    else
2139		ret->stringval = xmlStrdup((const xmlChar *)"");
2140#ifdef XP_DEBUG_OBJ_USAGE
2141	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2142#endif
2143	    return(ret);
2144	} else if ((cache->miscObjs != NULL) &&
2145	    (cache->miscObjs->number != 0))
2146	{
2147	    xmlXPathObjectPtr ret;
2148
2149	    ret = (xmlXPathObjectPtr)
2150		cache->miscObjs->items[--cache->miscObjs->number];
2151
2152	    ret->type = XPATH_STRING;
2153	    if (val != NULL)
2154		ret->stringval = xmlStrdup(val);
2155	    else
2156		ret->stringval = xmlStrdup((const xmlChar *)"");
2157#ifdef XP_DEBUG_OBJ_USAGE
2158	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2159#endif
2160	    return(ret);
2161	}
2162    }
2163    return(xmlXPathNewString(val));
2164}
2165
2166/**
2167 * xmlXPathCacheNewBoolean:
2168 * @ctxt: the XPath context
2169 * @val:  the boolean value
2170 *
2171 * This is the cached version of xmlXPathNewBoolean().
2172 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2173 *
2174 * Returns the created or reused object.
2175 */
2176static xmlXPathObjectPtr
2177xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2178{
2179    if ((ctxt != NULL) && (ctxt->cache)) {
2180	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2181
2182	if ((cache->booleanObjs != NULL) &&
2183	    (cache->booleanObjs->number != 0))
2184	{
2185	    xmlXPathObjectPtr ret;
2186
2187	    ret = (xmlXPathObjectPtr)
2188		cache->booleanObjs->items[--cache->booleanObjs->number];
2189	    ret->type = XPATH_BOOLEAN;
2190	    ret->boolval = (val != 0);
2191#ifdef XP_DEBUG_OBJ_USAGE
2192	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2193#endif
2194	    return(ret);
2195	} else if ((cache->miscObjs != NULL) &&
2196	    (cache->miscObjs->number != 0))
2197	{
2198	    xmlXPathObjectPtr ret;
2199
2200	    ret = (xmlXPathObjectPtr)
2201		cache->miscObjs->items[--cache->miscObjs->number];
2202
2203	    ret->type = XPATH_BOOLEAN;
2204	    ret->boolval = (val != 0);
2205#ifdef XP_DEBUG_OBJ_USAGE
2206	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2207#endif
2208	    return(ret);
2209	}
2210    }
2211    return(xmlXPathNewBoolean(val));
2212}
2213
2214/**
2215 * xmlXPathCacheNewFloat:
2216 * @ctxt: the XPath context
2217 * @val:  the double value
2218 *
2219 * This is the cached version of xmlXPathNewFloat().
2220 * Acquires an xmlXPathObjectPtr of type double and of value @val
2221 *
2222 * Returns the created or reused object.
2223 */
2224static xmlXPathObjectPtr
2225xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2226{
2227     if ((ctxt != NULL) && (ctxt->cache)) {
2228	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2229
2230	if ((cache->numberObjs != NULL) &&
2231	    (cache->numberObjs->number != 0))
2232	{
2233	    xmlXPathObjectPtr ret;
2234
2235	    ret = (xmlXPathObjectPtr)
2236		cache->numberObjs->items[--cache->numberObjs->number];
2237	    ret->type = XPATH_NUMBER;
2238	    ret->floatval = val;
2239#ifdef XP_DEBUG_OBJ_USAGE
2240	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2241#endif
2242	    return(ret);
2243	} else if ((cache->miscObjs != NULL) &&
2244	    (cache->miscObjs->number != 0))
2245	{
2246	    xmlXPathObjectPtr ret;
2247
2248	    ret = (xmlXPathObjectPtr)
2249		cache->miscObjs->items[--cache->miscObjs->number];
2250
2251	    ret->type = XPATH_NUMBER;
2252	    ret->floatval = val;
2253#ifdef XP_DEBUG_OBJ_USAGE
2254	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2255#endif
2256	    return(ret);
2257	}
2258    }
2259    return(xmlXPathNewFloat(val));
2260}
2261
2262/**
2263 * xmlXPathCacheConvertString:
2264 * @ctxt: the XPath context
2265 * @val:  an XPath object
2266 *
2267 * This is the cached version of xmlXPathConvertString().
2268 * Converts an existing object to its string() equivalent
2269 *
2270 * Returns a created or reused object, the old one is freed (cached)
2271 *         (or the operation is done directly on @val)
2272 */
2273
2274static xmlXPathObjectPtr
2275xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2276    xmlChar *res = NULL;
2277
2278    if (val == NULL)
2279	return(xmlXPathCacheNewCString(ctxt, ""));
2280
2281    switch (val->type) {
2282    case XPATH_UNDEFINED:
2283#ifdef DEBUG_EXPR
2284	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2285#endif
2286	break;
2287    case XPATH_NODESET:
2288    case XPATH_XSLT_TREE:
2289	res = xmlXPathCastNodeSetToString(val->nodesetval);
2290	break;
2291    case XPATH_STRING:
2292	return(val);
2293    case XPATH_BOOLEAN:
2294	res = xmlXPathCastBooleanToString(val->boolval);
2295	break;
2296    case XPATH_NUMBER:
2297	res = xmlXPathCastNumberToString(val->floatval);
2298	break;
2299    case XPATH_USERS:
2300    case XPATH_POINT:
2301    case XPATH_RANGE:
2302    case XPATH_LOCATIONSET:
2303	TODO;
2304	break;
2305    }
2306    xmlXPathReleaseObject(ctxt, val);
2307    if (res == NULL)
2308	return(xmlXPathCacheNewCString(ctxt, ""));
2309    return(xmlXPathCacheWrapString(ctxt, res));
2310}
2311
2312/**
2313 * xmlXPathCacheObjectCopy:
2314 * @ctxt: the XPath context
2315 * @val:  the original object
2316 *
2317 * This is the cached version of xmlXPathObjectCopy().
2318 * Acquire a copy of a given object
2319 *
2320 * Returns a created or reused created object.
2321 */
2322static xmlXPathObjectPtr
2323xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2324{
2325    if (val == NULL)
2326	return(NULL);
2327
2328    if (XP_HAS_CACHE(ctxt)) {
2329	switch (val->type) {
2330	    case XPATH_NODESET:
2331		return(xmlXPathCacheWrapNodeSet(ctxt,
2332		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2333	    case XPATH_STRING:
2334		return(xmlXPathCacheNewString(ctxt, val->stringval));
2335	    case XPATH_BOOLEAN:
2336		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2337	    case XPATH_NUMBER:
2338		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2339	    default:
2340		break;
2341	}
2342    }
2343    return(xmlXPathObjectCopy(val));
2344}
2345
2346/**
2347 * xmlXPathCacheConvertBoolean:
2348 * @ctxt: the XPath context
2349 * @val:  an XPath object
2350 *
2351 * This is the cached version of xmlXPathConvertBoolean().
2352 * Converts an existing object to its boolean() equivalent
2353 *
2354 * Returns a created or reused object, the old one is freed (or the operation
2355 *         is done directly on @val)
2356 */
2357static xmlXPathObjectPtr
2358xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2359    xmlXPathObjectPtr ret;
2360
2361    if (val == NULL)
2362	return(xmlXPathCacheNewBoolean(ctxt, 0));
2363    if (val->type == XPATH_BOOLEAN)
2364	return(val);
2365    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2366    xmlXPathReleaseObject(ctxt, val);
2367    return(ret);
2368}
2369
2370/**
2371 * xmlXPathCacheConvertNumber:
2372 * @ctxt: the XPath context
2373 * @val:  an XPath object
2374 *
2375 * This is the cached version of xmlXPathConvertNumber().
2376 * Converts an existing object to its number() equivalent
2377 *
2378 * Returns a created or reused object, the old one is freed (or the operation
2379 *         is done directly on @val)
2380 */
2381static xmlXPathObjectPtr
2382xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2383    xmlXPathObjectPtr ret;
2384
2385    if (val == NULL)
2386	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2387    if (val->type == XPATH_NUMBER)
2388	return(val);
2389    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2390    xmlXPathReleaseObject(ctxt, val);
2391    return(ret);
2392}
2393
2394/************************************************************************
2395 *									*
2396 *		Parser stacks related functions and macros		*
2397 *									*
2398 ************************************************************************/
2399
2400/**
2401 * valuePop:
2402 * @ctxt: an XPath evaluation context
2403 *
2404 * Pops the top XPath object from the value stack
2405 *
2406 * Returns the XPath object just removed
2407 */
2408xmlXPathObjectPtr
2409valuePop(xmlXPathParserContextPtr ctxt)
2410{
2411    xmlXPathObjectPtr ret;
2412
2413    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2414        return (NULL);
2415    ctxt->valueNr--;
2416    if (ctxt->valueNr > 0)
2417        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2418    else
2419        ctxt->value = NULL;
2420    ret = ctxt->valueTab[ctxt->valueNr];
2421    ctxt->valueTab[ctxt->valueNr] = NULL;
2422    return (ret);
2423}
2424/**
2425 * valuePush:
2426 * @ctxt:  an XPath evaluation context
2427 * @value:  the XPath object
2428 *
2429 * Pushes a new XPath object on top of the value stack
2430 *
2431 * returns the number of items on the value stack
2432 */
2433int
2434valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2435{
2436    if ((ctxt == NULL) || (value == NULL)) return(-1);
2437    if (ctxt->valueNr >= ctxt->valueMax) {
2438        xmlXPathObjectPtr *tmp;
2439
2440        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2441                                             2 * ctxt->valueMax *
2442                                             sizeof(ctxt->valueTab[0]));
2443        if (tmp == NULL) {
2444            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2445            return (0);
2446        }
2447        ctxt->valueMax *= 2;
2448	ctxt->valueTab = tmp;
2449    }
2450    ctxt->valueTab[ctxt->valueNr] = value;
2451    ctxt->value = value;
2452    return (ctxt->valueNr++);
2453}
2454
2455/**
2456 * xmlXPathPopBoolean:
2457 * @ctxt:  an XPath parser context
2458 *
2459 * Pops a boolean from the stack, handling conversion if needed.
2460 * Check error with #xmlXPathCheckError.
2461 *
2462 * Returns the boolean
2463 */
2464int
2465xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2466    xmlXPathObjectPtr obj;
2467    int ret;
2468
2469    obj = valuePop(ctxt);
2470    if (obj == NULL) {
2471	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2472	return(0);
2473    }
2474    if (obj->type != XPATH_BOOLEAN)
2475	ret = xmlXPathCastToBoolean(obj);
2476    else
2477        ret = obj->boolval;
2478    xmlXPathReleaseObject(ctxt->context, obj);
2479    return(ret);
2480}
2481
2482/**
2483 * xmlXPathPopNumber:
2484 * @ctxt:  an XPath parser context
2485 *
2486 * Pops a number from the stack, handling conversion if needed.
2487 * Check error with #xmlXPathCheckError.
2488 *
2489 * Returns the number
2490 */
2491double
2492xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2493    xmlXPathObjectPtr obj;
2494    double ret;
2495
2496    obj = valuePop(ctxt);
2497    if (obj == NULL) {
2498	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2499	return(0);
2500    }
2501    if (obj->type != XPATH_NUMBER)
2502	ret = xmlXPathCastToNumber(obj);
2503    else
2504        ret = obj->floatval;
2505    xmlXPathReleaseObject(ctxt->context, obj);
2506    return(ret);
2507}
2508
2509/**
2510 * xmlXPathPopString:
2511 * @ctxt:  an XPath parser context
2512 *
2513 * Pops a string from the stack, handling conversion if needed.
2514 * Check error with #xmlXPathCheckError.
2515 *
2516 * Returns the string
2517 */
2518xmlChar *
2519xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2520    xmlXPathObjectPtr obj;
2521    xmlChar * ret;
2522
2523    obj = valuePop(ctxt);
2524    if (obj == NULL) {
2525	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2526	return(NULL);
2527    }
2528    ret = xmlXPathCastToString(obj);	/* this does required strdup */
2529    /* TODO: needs refactoring somewhere else */
2530    if (obj->stringval == ret)
2531	obj->stringval = NULL;
2532    xmlXPathReleaseObject(ctxt->context, obj);
2533    return(ret);
2534}
2535
2536/**
2537 * xmlXPathPopNodeSet:
2538 * @ctxt:  an XPath parser context
2539 *
2540 * Pops a node-set from the stack, handling conversion if needed.
2541 * Check error with #xmlXPathCheckError.
2542 *
2543 * Returns the node-set
2544 */
2545xmlNodeSetPtr
2546xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2547    xmlXPathObjectPtr obj;
2548    xmlNodeSetPtr ret;
2549
2550    if (ctxt == NULL) return(NULL);
2551    if (ctxt->value == NULL) {
2552	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2553	return(NULL);
2554    }
2555    if (!xmlXPathStackIsNodeSet(ctxt)) {
2556	xmlXPathSetTypeError(ctxt);
2557	return(NULL);
2558    }
2559    obj = valuePop(ctxt);
2560    ret = obj->nodesetval;
2561#if 0
2562    /* to fix memory leak of not clearing obj->user */
2563    if (obj->boolval && obj->user != NULL)
2564        xmlFreeNodeList((xmlNodePtr) obj->user);
2565#endif
2566    obj->nodesetval = NULL;
2567    xmlXPathReleaseObject(ctxt->context, obj);
2568    return(ret);
2569}
2570
2571/**
2572 * xmlXPathPopExternal:
2573 * @ctxt:  an XPath parser context
2574 *
2575 * Pops an external object from the stack, handling conversion if needed.
2576 * Check error with #xmlXPathCheckError.
2577 *
2578 * Returns the object
2579 */
2580void *
2581xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2582    xmlXPathObjectPtr obj;
2583    void * ret;
2584
2585    if ((ctxt == NULL) || (ctxt->value == NULL)) {
2586	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2587	return(NULL);
2588    }
2589    if (ctxt->value->type != XPATH_USERS) {
2590	xmlXPathSetTypeError(ctxt);
2591	return(NULL);
2592    }
2593    obj = valuePop(ctxt);
2594    ret = obj->user;
2595    obj->user = NULL;
2596    xmlXPathReleaseObject(ctxt->context, obj);
2597    return(ret);
2598}
2599
2600/*
2601 * Macros for accessing the content. Those should be used only by the parser,
2602 * and not exported.
2603 *
2604 * Dirty macros, i.e. one need to make assumption on the context to use them
2605 *
2606 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2607 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2608 *           in ISO-Latin or UTF-8.
2609 *           This should be used internally by the parser
2610 *           only to compare to ASCII values otherwise it would break when
2611 *           running with UTF-8 encoding.
2612 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2613 *           to compare on ASCII based substring.
2614 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2615 *           strings within the parser.
2616 *   CURRENT Returns the current char value, with the full decoding of
2617 *           UTF-8 if we are using this mode. It returns an int.
2618 *   NEXT    Skip to the next character, this does the proper decoding
2619 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2620 *           It returns the pointer to the current xmlChar.
2621 */
2622
2623#define CUR (*ctxt->cur)
2624#define SKIP(val) ctxt->cur += (val)
2625#define NXT(val) ctxt->cur[(val)]
2626#define CUR_PTR ctxt->cur
2627#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2628
2629#define COPY_BUF(l,b,i,v)                                              \
2630    if (l == 1) b[i++] = (xmlChar) v;                                  \
2631    else i += xmlCopyChar(l,&b[i],v)
2632
2633#define NEXTL(l)  ctxt->cur += l
2634
2635#define SKIP_BLANKS							\
2636    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2637
2638#define CURRENT (*ctxt->cur)
2639#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2640
2641
2642#ifndef DBL_DIG
2643#define DBL_DIG 16
2644#endif
2645#ifndef DBL_EPSILON
2646#define DBL_EPSILON 1E-9
2647#endif
2648
2649#define UPPER_DOUBLE 1E9
2650#define LOWER_DOUBLE 1E-5
2651#define	LOWER_DOUBLE_EXP 5
2652
2653#define INTEGER_DIGITS DBL_DIG
2654#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2655#define EXPONENT_DIGITS (3 + 2)
2656
2657/**
2658 * xmlXPathFormatNumber:
2659 * @number:     number to format
2660 * @buffer:     output buffer
2661 * @buffersize: size of output buffer
2662 *
2663 * Convert the number into a string representation.
2664 */
2665static void
2666xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2667{
2668    switch (xmlXPathIsInf(number)) {
2669    case 1:
2670	if (buffersize > (int)sizeof("Infinity"))
2671	    snprintf(buffer, buffersize, "Infinity");
2672	break;
2673    case -1:
2674	if (buffersize > (int)sizeof("-Infinity"))
2675	    snprintf(buffer, buffersize, "-Infinity");
2676	break;
2677    default:
2678	if (xmlXPathIsNaN(number)) {
2679	    if (buffersize > (int)sizeof("NaN"))
2680		snprintf(buffer, buffersize, "NaN");
2681	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
2682	    snprintf(buffer, buffersize, "0");
2683	} else if (number == ((int) number)) {
2684	    char work[30];
2685	    char *ptr, *cur;
2686	    int value = (int) number;
2687
2688            ptr = &buffer[0];
2689	    if (value == 0) {
2690		*ptr++ = '0';
2691	    } else {
2692		snprintf(work, 29, "%d", value);
2693		cur = &work[0];
2694		while ((*cur) && (ptr - buffer < buffersize)) {
2695		    *ptr++ = *cur++;
2696		}
2697	    }
2698	    if (ptr - buffer < buffersize) {
2699		*ptr = 0;
2700	    } else if (buffersize > 0) {
2701		ptr--;
2702		*ptr = 0;
2703	    }
2704	} else {
2705	    /*
2706	      For the dimension of work,
2707	          DBL_DIG is number of significant digits
2708		  EXPONENT is only needed for "scientific notation"
2709	          3 is sign, decimal point, and terminating zero
2710		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2711	      Note that this dimension is slightly (a few characters)
2712	      larger than actually necessary.
2713	    */
2714	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2715	    int integer_place, fraction_place;
2716	    char *ptr;
2717	    char *after_fraction;
2718	    double absolute_value;
2719	    int size;
2720
2721	    absolute_value = fabs(number);
2722
2723	    /*
2724	     * First choose format - scientific or regular floating point.
2725	     * In either case, result is in work, and after_fraction points
2726	     * just past the fractional part.
2727	    */
2728	    if ( ((absolute_value > UPPER_DOUBLE) ||
2729		  (absolute_value < LOWER_DOUBLE)) &&
2730		 (absolute_value != 0.0) ) {
2731		/* Use scientific notation */
2732		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2733		fraction_place = DBL_DIG - 1;
2734		size = snprintf(work, sizeof(work),"%*.*e",
2735			 integer_place, fraction_place, number);
2736		while ((size > 0) && (work[size] != 'e')) size--;
2737
2738	    }
2739	    else {
2740		/* Use regular notation */
2741		if (absolute_value > 0.0) {
2742		    integer_place = (int)log10(absolute_value);
2743		    if (integer_place > 0)
2744		        fraction_place = DBL_DIG - integer_place - 1;
2745		    else
2746		        fraction_place = DBL_DIG - integer_place;
2747		} else {
2748		    fraction_place = 1;
2749		}
2750		size = snprintf(work, sizeof(work), "%0.*f",
2751				fraction_place, number);
2752	    }
2753
2754	    /* Remove fractional trailing zeroes */
2755	    after_fraction = work + size;
2756	    ptr = after_fraction;
2757	    while (*(--ptr) == '0')
2758		;
2759	    if (*ptr != '.')
2760	        ptr++;
2761	    while ((*ptr++ = *after_fraction++) != 0);
2762
2763	    /* Finally copy result back to caller */
2764	    size = strlen(work) + 1;
2765	    if (size > buffersize) {
2766		work[buffersize - 1] = 0;
2767		size = buffersize;
2768	    }
2769	    memmove(buffer, work, size);
2770	}
2771	break;
2772    }
2773}
2774
2775
2776/************************************************************************
2777 *									*
2778 *			Routines to handle NodeSets			*
2779 *									*
2780 ************************************************************************/
2781
2782/**
2783 * xmlXPathOrderDocElems:
2784 * @doc:  an input document
2785 *
2786 * Call this routine to speed up XPath computation on static documents.
2787 * This stamps all the element nodes with the document order
2788 * Like for line information, the order is kept in the element->content
2789 * field, the value stored is actually - the node number (starting at -1)
2790 * to be able to differentiate from line numbers.
2791 *
2792 * Returns the number of elements found in the document or -1 in case
2793 *    of error.
2794 */
2795long
2796xmlXPathOrderDocElems(xmlDocPtr doc) {
2797    long count = 0;
2798    xmlNodePtr cur;
2799
2800    if (doc == NULL)
2801	return(-1);
2802    cur = doc->children;
2803    while (cur != NULL) {
2804	if (cur->type == XML_ELEMENT_NODE) {
2805	    cur->content = (void *) (-(++count));
2806	    if (cur->children != NULL) {
2807		cur = cur->children;
2808		continue;
2809	    }
2810	}
2811	if (cur->next != NULL) {
2812	    cur = cur->next;
2813	    continue;
2814	}
2815	do {
2816	    cur = cur->parent;
2817	    if (cur == NULL)
2818		break;
2819	    if (cur == (xmlNodePtr) doc) {
2820		cur = NULL;
2821		break;
2822	    }
2823	    if (cur->next != NULL) {
2824		cur = cur->next;
2825		break;
2826	    }
2827	} while (cur != NULL);
2828    }
2829    return(count);
2830}
2831
2832/**
2833 * xmlXPathCmpNodes:
2834 * @node1:  the first node
2835 * @node2:  the second node
2836 *
2837 * Compare two nodes w.r.t document order
2838 *
2839 * Returns -2 in case of error 1 if first point < second point, 0 if
2840 *         it's the same node, -1 otherwise
2841 */
2842int
2843xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2844    int depth1, depth2;
2845    int attr1 = 0, attr2 = 0;
2846    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2847    xmlNodePtr cur, root;
2848
2849    if ((node1 == NULL) || (node2 == NULL))
2850	return(-2);
2851    /*
2852     * a couple of optimizations which will avoid computations in most cases
2853     */
2854    if (node1 == node2)		/* trivial case */
2855	return(0);
2856    if (node1->type == XML_ATTRIBUTE_NODE) {
2857	attr1 = 1;
2858	attrNode1 = node1;
2859	node1 = node1->parent;
2860    }
2861    if (node2->type == XML_ATTRIBUTE_NODE) {
2862	attr2 = 1;
2863	attrNode2 = node2;
2864	node2 = node2->parent;
2865    }
2866    if (node1 == node2) {
2867	if (attr1 == attr2) {
2868	    /* not required, but we keep attributes in order */
2869	    if (attr1 != 0) {
2870	        cur = attrNode2->prev;
2871		while (cur != NULL) {
2872		    if (cur == attrNode1)
2873		        return (1);
2874		    cur = cur->prev;
2875		}
2876		return (-1);
2877	    }
2878	    return(0);
2879	}
2880	if (attr2 == 1)
2881	    return(1);
2882	return(-1);
2883    }
2884    if ((node1->type == XML_NAMESPACE_DECL) ||
2885        (node2->type == XML_NAMESPACE_DECL))
2886	return(1);
2887    if (node1 == node2->prev)
2888	return(1);
2889    if (node1 == node2->next)
2890	return(-1);
2891
2892    /*
2893     * Speedup using document order if availble.
2894     */
2895    if ((node1->type == XML_ELEMENT_NODE) &&
2896	(node2->type == XML_ELEMENT_NODE) &&
2897	(0 > (long) node1->content) &&
2898	(0 > (long) node2->content) &&
2899	(node1->doc == node2->doc)) {
2900	long l1, l2;
2901
2902	l1 = -((long) node1->content);
2903	l2 = -((long) node2->content);
2904	if (l1 < l2)
2905	    return(1);
2906	if (l1 > l2)
2907	    return(-1);
2908    }
2909
2910    /*
2911     * compute depth to root
2912     */
2913    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2914	if (cur == node1)
2915	    return(1);
2916	depth2++;
2917    }
2918    root = cur;
2919    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2920	if (cur == node2)
2921	    return(-1);
2922	depth1++;
2923    }
2924    /*
2925     * Distinct document (or distinct entities :-( ) case.
2926     */
2927    if (root != cur) {
2928	return(-2);
2929    }
2930    /*
2931     * get the nearest common ancestor.
2932     */
2933    while (depth1 > depth2) {
2934	depth1--;
2935	node1 = node1->parent;
2936    }
2937    while (depth2 > depth1) {
2938	depth2--;
2939	node2 = node2->parent;
2940    }
2941    while (node1->parent != node2->parent) {
2942	node1 = node1->parent;
2943	node2 = node2->parent;
2944	/* should not happen but just in case ... */
2945	if ((node1 == NULL) || (node2 == NULL))
2946	    return(-2);
2947    }
2948    /*
2949     * Find who's first.
2950     */
2951    if (node1 == node2->prev)
2952	return(1);
2953    if (node1 == node2->next)
2954	return(-1);
2955    /*
2956     * Speedup using document order if availble.
2957     */
2958    if ((node1->type == XML_ELEMENT_NODE) &&
2959	(node2->type == XML_ELEMENT_NODE) &&
2960	(0 > (long) node1->content) &&
2961	(0 > (long) node2->content) &&
2962	(node1->doc == node2->doc)) {
2963	long l1, l2;
2964
2965	l1 = -((long) node1->content);
2966	l2 = -((long) node2->content);
2967	if (l1 < l2)
2968	    return(1);
2969	if (l1 > l2)
2970	    return(-1);
2971    }
2972
2973    for (cur = node1->next;cur != NULL;cur = cur->next)
2974	if (cur == node2)
2975	    return(1);
2976    return(-1); /* assume there is no sibling list corruption */
2977}
2978
2979#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2980/**
2981 * xmlXPathCmpNodesExt:
2982 * @node1:  the first node
2983 * @node2:  the second node
2984 *
2985 * Compare two nodes w.r.t document order.
2986 * This one is optimized for handling of non-element nodes.
2987 *
2988 * Returns -2 in case of error 1 if first point < second point, 0 if
2989 *         it's the same node, -1 otherwise
2990 */
2991static int
2992xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2993    int depth1, depth2;
2994    int misc = 0, precedence1 = 0, precedence2 = 0;
2995    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2996    xmlNodePtr cur, root;
2997    long l1, l2;
2998
2999    if ((node1 == NULL) || (node2 == NULL))
3000	return(-2);
3001
3002    if (node1 == node2)
3003	return(0);
3004
3005    /*
3006     * a couple of optimizations which will avoid computations in most cases
3007     */
3008    switch (node1->type) {
3009	case XML_ELEMENT_NODE:
3010	    if (node2->type == XML_ELEMENT_NODE) {
3011		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3012		    (0 > (long) node2->content) &&
3013		    (node1->doc == node2->doc))
3014		{
3015		    l1 = -((long) node1->content);
3016		    l2 = -((long) node2->content);
3017		    if (l1 < l2)
3018			return(1);
3019		    if (l1 > l2)
3020			return(-1);
3021		} else
3022		    goto turtle_comparison;
3023	    }
3024	    break;
3025	case XML_ATTRIBUTE_NODE:
3026	    precedence1 = 1; /* element is owner */
3027	    miscNode1 = node1;
3028	    node1 = node1->parent;
3029	    misc = 1;
3030	    break;
3031	case XML_TEXT_NODE:
3032	case XML_CDATA_SECTION_NODE:
3033	case XML_COMMENT_NODE:
3034	case XML_PI_NODE: {
3035	    miscNode1 = node1;
3036	    /*
3037	    * Find nearest element node.
3038	    */
3039	    if (node1->prev != NULL) {
3040		do {
3041		    node1 = node1->prev;
3042		    if (node1->type == XML_ELEMENT_NODE) {
3043			precedence1 = 3; /* element in prev-sibl axis */
3044			break;
3045		    }
3046		    if (node1->prev == NULL) {
3047			precedence1 = 2; /* element is parent */
3048			/*
3049			* URGENT TODO: Are there any cases, where the
3050			* parent of such a node is not an element node?
3051			*/
3052			node1 = node1->parent;
3053			break;
3054		    }
3055		} while (1);
3056	    } else {
3057		precedence1 = 2; /* element is parent */
3058		node1 = node1->parent;
3059	    }
3060	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3061		(0 <= (long) node1->content)) {
3062		/*
3063		* Fallback for whatever case.
3064		*/
3065		node1 = miscNode1;
3066		precedence1 = 0;
3067	    } else
3068		misc = 1;
3069	}
3070	    break;
3071	case XML_NAMESPACE_DECL:
3072	    /*
3073	    * TODO: why do we return 1 for namespace nodes?
3074	    */
3075	    return(1);
3076	default:
3077	    break;
3078    }
3079    switch (node2->type) {
3080	case XML_ELEMENT_NODE:
3081	    break;
3082	case XML_ATTRIBUTE_NODE:
3083	    precedence2 = 1; /* element is owner */
3084	    miscNode2 = node2;
3085	    node2 = node2->parent;
3086	    misc = 1;
3087	    break;
3088	case XML_TEXT_NODE:
3089	case XML_CDATA_SECTION_NODE:
3090	case XML_COMMENT_NODE:
3091	case XML_PI_NODE: {
3092	    miscNode2 = node2;
3093	    if (node2->prev != NULL) {
3094		do {
3095		    node2 = node2->prev;
3096		    if (node2->type == XML_ELEMENT_NODE) {
3097			precedence2 = 3; /* element in prev-sibl axis */
3098			break;
3099		    }
3100		    if (node2->prev == NULL) {
3101			precedence2 = 2; /* element is parent */
3102			node2 = node2->parent;
3103			break;
3104		    }
3105		} while (1);
3106	    } else {
3107		precedence2 = 2; /* element is parent */
3108		node2 = node2->parent;
3109	    }
3110	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3111		(0 <= (long) node1->content))
3112	    {
3113		node2 = miscNode2;
3114		precedence2 = 0;
3115	    } else
3116		misc = 1;
3117	}
3118	    break;
3119	case XML_NAMESPACE_DECL:
3120	    return(1);
3121	default:
3122	    break;
3123    }
3124    if (misc) {
3125	if (node1 == node2) {
3126	    if (precedence1 == precedence2) {
3127		/*
3128		* The ugly case; but normally there aren't many
3129		* adjacent non-element nodes around.
3130		*/
3131		cur = miscNode2->prev;
3132		while (cur != NULL) {
3133		    if (cur == miscNode1)
3134			return(1);
3135		    if (cur->type == XML_ELEMENT_NODE)
3136			return(-1);
3137		    cur = cur->prev;
3138		}
3139		return (-1);
3140	    } else {
3141		/*
3142		* Evaluate based on higher precedence wrt to the element.
3143		* TODO: This assumes attributes are sorted before content.
3144		*   Is this 100% correct?
3145		*/
3146		if (precedence1 < precedence2)
3147		    return(1);
3148		else
3149		    return(-1);
3150	    }
3151	}
3152	/*
3153	* Special case: One of the helper-elements is contained by the other.
3154	* <foo>
3155	*   <node2>
3156	*     <node1>Text-1(precedence1 == 2)</node1>
3157	*   </node2>
3158	*   Text-6(precedence2 == 3)
3159	* </foo>
3160	*/
3161	if ((precedence2 == 3) && (precedence1 > 1)) {
3162	    cur = node1->parent;
3163	    while (cur) {
3164		if (cur == node2)
3165		    return(1);
3166		cur = cur->parent;
3167	    }
3168	}
3169	if ((precedence1 == 3) && (precedence2 > 1)) {
3170	    cur = node2->parent;
3171	    while (cur) {
3172		if (cur == node1)
3173		    return(-1);
3174		cur = cur->parent;
3175	    }
3176	}
3177    }
3178
3179    /*
3180     * Speedup using document order if availble.
3181     */
3182    if ((node1->type == XML_ELEMENT_NODE) &&
3183	(node2->type == XML_ELEMENT_NODE) &&
3184	(0 > (long) node1->content) &&
3185	(0 > (long) node2->content) &&
3186	(node1->doc == node2->doc)) {
3187
3188	l1 = -((long) node1->content);
3189	l2 = -((long) node2->content);
3190	if (l1 < l2)
3191	    return(1);
3192	if (l1 > l2)
3193	    return(-1);
3194    }
3195
3196turtle_comparison:
3197
3198    if (node1 == node2->prev)
3199	return(1);
3200    if (node1 == node2->next)
3201	return(-1);
3202    /*
3203     * compute depth to root
3204     */
3205    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3206	if (cur == node1)
3207	    return(1);
3208	depth2++;
3209    }
3210    root = cur;
3211    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3212	if (cur == node2)
3213	    return(-1);
3214	depth1++;
3215    }
3216    /*
3217     * Distinct document (or distinct entities :-( ) case.
3218     */
3219    if (root != cur) {
3220	return(-2);
3221    }
3222    /*
3223     * get the nearest common ancestor.
3224     */
3225    while (depth1 > depth2) {
3226	depth1--;
3227	node1 = node1->parent;
3228    }
3229    while (depth2 > depth1) {
3230	depth2--;
3231	node2 = node2->parent;
3232    }
3233    while (node1->parent != node2->parent) {
3234	node1 = node1->parent;
3235	node2 = node2->parent;
3236	/* should not happen but just in case ... */
3237	if ((node1 == NULL) || (node2 == NULL))
3238	    return(-2);
3239    }
3240    /*
3241     * Find who's first.
3242     */
3243    if (node1 == node2->prev)
3244	return(1);
3245    if (node1 == node2->next)
3246	return(-1);
3247    /*
3248     * Speedup using document order if availble.
3249     */
3250    if ((node1->type == XML_ELEMENT_NODE) &&
3251	(node2->type == XML_ELEMENT_NODE) &&
3252	(0 > (long) node1->content) &&
3253	(0 > (long) node2->content) &&
3254	(node1->doc == node2->doc)) {
3255
3256	l1 = -((long) node1->content);
3257	l2 = -((long) node2->content);
3258	if (l1 < l2)
3259	    return(1);
3260	if (l1 > l2)
3261	    return(-1);
3262    }
3263
3264    for (cur = node1->next;cur != NULL;cur = cur->next)
3265	if (cur == node2)
3266	    return(1);
3267    return(-1); /* assume there is no sibling list corruption */
3268}
3269#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3270
3271/**
3272 * xmlXPathNodeSetSort:
3273 * @set:  the node set
3274 *
3275 * Sort the node set in document order
3276 */
3277void
3278xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3279    int i, j, incr, len;
3280    xmlNodePtr tmp;
3281
3282    if (set == NULL)
3283	return;
3284
3285    /* Use Shell's sort to sort the node-set */
3286    len = set->nodeNr;
3287    for (incr = len / 2; incr > 0; incr /= 2) {
3288	for (i = incr; i < len; i++) {
3289	    j = i - incr;
3290	    while (j >= 0) {
3291#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3292		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3293			set->nodeTab[j + incr]) == -1)
3294#else
3295		if (xmlXPathCmpNodes(set->nodeTab[j],
3296			set->nodeTab[j + incr]) == -1)
3297#endif
3298		{
3299		    tmp = set->nodeTab[j];
3300		    set->nodeTab[j] = set->nodeTab[j + incr];
3301		    set->nodeTab[j + incr] = tmp;
3302		    j -= incr;
3303		} else
3304		    break;
3305	    }
3306	}
3307    }
3308}
3309
3310#define XML_NODESET_DEFAULT	10
3311/**
3312 * xmlXPathNodeSetDupNs:
3313 * @node:  the parent node of the namespace XPath node
3314 * @ns:  the libxml namespace declaration node.
3315 *
3316 * Namespace node in libxml don't match the XPath semantic. In a node set
3317 * the namespace nodes are duplicated and the next pointer is set to the
3318 * parent node in the XPath semantic.
3319 *
3320 * Returns the newly created object.
3321 */
3322static xmlNodePtr
3323xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3324    xmlNsPtr cur;
3325
3326    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3327	return(NULL);
3328    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3329	return((xmlNodePtr) ns);
3330
3331    /*
3332     * Allocate a new Namespace and fill the fields.
3333     */
3334    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3335    if (cur == NULL) {
3336        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3337	return(NULL);
3338    }
3339    memset(cur, 0, sizeof(xmlNs));
3340    cur->type = XML_NAMESPACE_DECL;
3341    if (ns->href != NULL)
3342	cur->href = xmlStrdup(ns->href);
3343    if (ns->prefix != NULL)
3344	cur->prefix = xmlStrdup(ns->prefix);
3345    cur->next = (xmlNsPtr) node;
3346    return((xmlNodePtr) cur);
3347}
3348
3349/**
3350 * xmlXPathNodeSetFreeNs:
3351 * @ns:  the XPath namespace node found in a nodeset.
3352 *
3353 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3354 * the namespace nodes are duplicated and the next pointer is set to the
3355 * parent node in the XPath semantic. Check if such a node needs to be freed
3356 */
3357void
3358xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3359    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3360	return;
3361
3362    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3363	if (ns->href != NULL)
3364	    xmlFree((xmlChar *)ns->href);
3365	if (ns->prefix != NULL)
3366	    xmlFree((xmlChar *)ns->prefix);
3367	xmlFree(ns);
3368    }
3369}
3370
3371/**
3372 * xmlXPathNodeSetCreate:
3373 * @val:  an initial xmlNodePtr, or NULL
3374 *
3375 * Create a new xmlNodeSetPtr of type double and of value @val
3376 *
3377 * Returns the newly created object.
3378 */
3379xmlNodeSetPtr
3380xmlXPathNodeSetCreate(xmlNodePtr val) {
3381    xmlNodeSetPtr ret;
3382
3383    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3384    if (ret == NULL) {
3385        xmlXPathErrMemory(NULL, "creating nodeset\n");
3386	return(NULL);
3387    }
3388    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3389    if (val != NULL) {
3390        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3391					     sizeof(xmlNodePtr));
3392	if (ret->nodeTab == NULL) {
3393	    xmlXPathErrMemory(NULL, "creating nodeset\n");
3394	    xmlFree(ret);
3395	    return(NULL);
3396	}
3397	memset(ret->nodeTab, 0 ,
3398	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3399        ret->nodeMax = XML_NODESET_DEFAULT;
3400	if (val->type == XML_NAMESPACE_DECL) {
3401	    xmlNsPtr ns = (xmlNsPtr) val;
3402
3403	    ret->nodeTab[ret->nodeNr++] =
3404		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3405	} else
3406	    ret->nodeTab[ret->nodeNr++] = val;
3407    }
3408    return(ret);
3409}
3410
3411/**
3412 * xmlXPathNodeSetCreateSize:
3413 * @size:  the initial size of the set
3414 *
3415 * Create a new xmlNodeSetPtr of type double and of value @val
3416 *
3417 * Returns the newly created object.
3418 */
3419static xmlNodeSetPtr
3420xmlXPathNodeSetCreateSize(int size) {
3421    xmlNodeSetPtr ret;
3422
3423    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3424    if (ret == NULL) {
3425        xmlXPathErrMemory(NULL, "creating nodeset\n");
3426	return(NULL);
3427    }
3428    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3429    if (size < XML_NODESET_DEFAULT)
3430	size = XML_NODESET_DEFAULT;
3431    ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3432    if (ret->nodeTab == NULL) {
3433	xmlXPathErrMemory(NULL, "creating nodeset\n");
3434	xmlFree(ret);
3435	return(NULL);
3436    }
3437    memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3438    ret->nodeMax = size;
3439    return(ret);
3440}
3441
3442/**
3443 * xmlXPathNodeSetContains:
3444 * @cur:  the node-set
3445 * @val:  the node
3446 *
3447 * checks whether @cur contains @val
3448 *
3449 * Returns true (1) if @cur contains @val, false (0) otherwise
3450 */
3451int
3452xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3453    int i;
3454
3455    if ((cur == NULL) || (val == NULL)) return(0);
3456    if (val->type == XML_NAMESPACE_DECL) {
3457	for (i = 0; i < cur->nodeNr; i++) {
3458	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3459		xmlNsPtr ns1, ns2;
3460
3461		ns1 = (xmlNsPtr) val;
3462		ns2 = (xmlNsPtr) cur->nodeTab[i];
3463		if (ns1 == ns2)
3464		    return(1);
3465		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3466	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3467		    return(1);
3468	    }
3469	}
3470    } else {
3471	for (i = 0; i < cur->nodeNr; i++) {
3472	    if (cur->nodeTab[i] == val)
3473		return(1);
3474	}
3475    }
3476    return(0);
3477}
3478
3479/**
3480 * xmlXPathNodeSetAddNs:
3481 * @cur:  the initial node set
3482 * @node:  the hosting node
3483 * @ns:  a the namespace node
3484 *
3485 * add a new namespace node to an existing NodeSet
3486 */
3487void
3488xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3489    int i;
3490
3491
3492    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3493        (ns->type != XML_NAMESPACE_DECL) ||
3494	(node->type != XML_ELEMENT_NODE))
3495	return;
3496
3497    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3498    /*
3499     * prevent duplicates
3500     */
3501    for (i = 0;i < cur->nodeNr;i++) {
3502        if ((cur->nodeTab[i] != NULL) &&
3503	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3504	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3505	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3506	    return;
3507    }
3508
3509    /*
3510     * grow the nodeTab if needed
3511     */
3512    if (cur->nodeMax == 0) {
3513        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3514					     sizeof(xmlNodePtr));
3515	if (cur->nodeTab == NULL) {
3516	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3517	    return;
3518	}
3519	memset(cur->nodeTab, 0 ,
3520	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3521        cur->nodeMax = XML_NODESET_DEFAULT;
3522    } else if (cur->nodeNr == cur->nodeMax) {
3523        xmlNodePtr *temp;
3524
3525        cur->nodeMax *= 2;
3526	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3527				      sizeof(xmlNodePtr));
3528	if (temp == NULL) {
3529	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3530	    return;
3531	}
3532	cur->nodeTab = temp;
3533    }
3534    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3535}
3536
3537/**
3538 * xmlXPathNodeSetAdd:
3539 * @cur:  the initial node set
3540 * @val:  a new xmlNodePtr
3541 *
3542 * add a new xmlNodePtr to an existing NodeSet
3543 */
3544void
3545xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3546    int i;
3547
3548    if ((cur == NULL) || (val == NULL)) return;
3549
3550#if 0
3551    if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3552	return;	/* an XSLT fake node */
3553#endif
3554
3555    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3556    /*
3557     * prevent duplcates
3558     */
3559    for (i = 0;i < cur->nodeNr;i++)
3560        if (cur->nodeTab[i] == val) return;
3561
3562    /*
3563     * grow the nodeTab if needed
3564     */
3565    if (cur->nodeMax == 0) {
3566        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3567					     sizeof(xmlNodePtr));
3568	if (cur->nodeTab == NULL) {
3569	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3570	    return;
3571	}
3572	memset(cur->nodeTab, 0 ,
3573	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3574        cur->nodeMax = XML_NODESET_DEFAULT;
3575    } else if (cur->nodeNr == cur->nodeMax) {
3576        xmlNodePtr *temp;
3577
3578        cur->nodeMax *= 2;
3579	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3580				      sizeof(xmlNodePtr));
3581	if (temp == NULL) {
3582	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3583	    return;
3584	}
3585	cur->nodeTab = temp;
3586    }
3587    if (val->type == XML_NAMESPACE_DECL) {
3588	xmlNsPtr ns = (xmlNsPtr) val;
3589
3590	cur->nodeTab[cur->nodeNr++] =
3591	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3592    } else
3593	cur->nodeTab[cur->nodeNr++] = val;
3594}
3595
3596/**
3597 * xmlXPathNodeSetAddUnique:
3598 * @cur:  the initial node set
3599 * @val:  a new xmlNodePtr
3600 *
3601 * add a new xmlNodePtr to an existing NodeSet, optimized version
3602 * when we are sure the node is not already in the set.
3603 */
3604void
3605xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3606    if ((cur == NULL) || (val == NULL)) return;
3607
3608#if 0
3609    if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3610	return;	/* an XSLT fake node */
3611#endif
3612
3613    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3614    /*
3615     * grow the nodeTab if needed
3616     */
3617    if (cur->nodeMax == 0) {
3618        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3619					     sizeof(xmlNodePtr));
3620	if (cur->nodeTab == NULL) {
3621	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3622	    return;
3623	}
3624	memset(cur->nodeTab, 0 ,
3625	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3626        cur->nodeMax = XML_NODESET_DEFAULT;
3627    } else if (cur->nodeNr == cur->nodeMax) {
3628        xmlNodePtr *temp;
3629
3630        cur->nodeMax *= 2;
3631	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3632				      sizeof(xmlNodePtr));
3633	if (temp == NULL) {
3634	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3635	    return;
3636	}
3637	cur->nodeTab = temp;
3638    }
3639    if (val->type == XML_NAMESPACE_DECL) {
3640	xmlNsPtr ns = (xmlNsPtr) val;
3641
3642	cur->nodeTab[cur->nodeNr++] =
3643	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3644    } else
3645	cur->nodeTab[cur->nodeNr++] = val;
3646}
3647
3648/**
3649 * xmlXPathNodeSetMerge:
3650 * @val1:  the first NodeSet or NULL
3651 * @val2:  the second NodeSet
3652 *
3653 * Merges two nodesets, all nodes from @val2 are added to @val1
3654 * if @val1 is NULL, a new set is created and copied from @val2
3655 *
3656 * Returns @val1 once extended or NULL in case of error.
3657 */
3658xmlNodeSetPtr
3659xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3660    int i, j, initNr, skip;
3661    xmlNodePtr n1, n2;
3662
3663    if (val2 == NULL) return(val1);
3664    if (val1 == NULL) {
3665	val1 = xmlXPathNodeSetCreate(NULL);
3666    if (val1 == NULL)
3667        return (NULL);
3668#if 0
3669	/*
3670	* TODO: The optimization won't work in every case, since
3671	*  those nasty namespace nodes need to be added with
3672	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3673	*  memcpy is not possible.
3674	*  If there was a flag on the nodesetval, indicating that
3675	*  some temporary nodes are in, that would be helpfull.
3676	*/
3677	/*
3678	* Optimization: Create an equally sized node-set
3679	* and memcpy the content.
3680	*/
3681	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3682	if (val1 == NULL)
3683	    return(NULL);
3684	if (val2->nodeNr != 0) {
3685	    if (val2->nodeNr == 1)
3686		*(val1->nodeTab) = *(val2->nodeTab);
3687	    else {
3688		memcpy(val1->nodeTab, val2->nodeTab,
3689		    val2->nodeNr * sizeof(xmlNodePtr));
3690	    }
3691	    val1->nodeNr = val2->nodeNr;
3692	}
3693	return(val1);
3694#endif
3695    }
3696
3697    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3698    initNr = val1->nodeNr;
3699
3700    for (i = 0;i < val2->nodeNr;i++) {
3701	n2 = val2->nodeTab[i];
3702	/*
3703	 * check against duplicates
3704	 */
3705	skip = 0;
3706	for (j = 0; j < initNr; j++) {
3707	    n1 = val1->nodeTab[j];
3708	    if (n1 == n2) {
3709		skip = 1;
3710		break;
3711	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3712		       (n2->type == XML_NAMESPACE_DECL)) {
3713		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3714		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3715			((xmlNsPtr) n2)->prefix)))
3716		{
3717		    skip = 1;
3718		    break;
3719		}
3720	    }
3721	}
3722	if (skip)
3723	    continue;
3724
3725	/*
3726	 * grow the nodeTab if needed
3727	 */
3728	if (val1->nodeMax == 0) {
3729	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3730						    sizeof(xmlNodePtr));
3731	    if (val1->nodeTab == NULL) {
3732	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3733		return(NULL);
3734	    }
3735	    memset(val1->nodeTab, 0 ,
3736		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3737	    val1->nodeMax = XML_NODESET_DEFAULT;
3738	} else if (val1->nodeNr == val1->nodeMax) {
3739	    xmlNodePtr *temp;
3740
3741	    val1->nodeMax *= 2;
3742	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3743					     sizeof(xmlNodePtr));
3744	    if (temp == NULL) {
3745	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3746		return(NULL);
3747	    }
3748	    val1->nodeTab = temp;
3749	}
3750	if (n2->type == XML_NAMESPACE_DECL) {
3751	    xmlNsPtr ns = (xmlNsPtr) n2;
3752
3753	    val1->nodeTab[val1->nodeNr++] =
3754		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3755	} else
3756	    val1->nodeTab[val1->nodeNr++] = n2;
3757    }
3758
3759    return(val1);
3760}
3761
3762#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3763/**
3764 * xmlXPathNodeSetMergeUnique:
3765 * @val1:  the first NodeSet or NULL
3766 * @val2:  the second NodeSet
3767 *
3768 * Merges two nodesets, all nodes from @val2 are added to @val1
3769 * if @val1 is NULL, a new set is created and copied from @val2
3770 *
3771 * Returns @val1 once extended or NULL in case of error.
3772 */
3773static xmlNodeSetPtr
3774xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3775    int i;
3776
3777    if (val2 == NULL) return(val1);
3778    if (val1 == NULL) {
3779	val1 = xmlXPathNodeSetCreate(NULL);
3780    }
3781    if (val1 == NULL)
3782        return (NULL);
3783
3784    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3785
3786    for (i = 0;i < val2->nodeNr;i++) {
3787	/*
3788	 * grow the nodeTab if needed
3789	 */
3790	if (val1->nodeMax == 0) {
3791	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3792						    sizeof(xmlNodePtr));
3793	    if (val1->nodeTab == NULL) {
3794	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3795		return(NULL);
3796	    }
3797	    memset(val1->nodeTab, 0 ,
3798		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3799	    val1->nodeMax = XML_NODESET_DEFAULT;
3800	} else if (val1->nodeNr == val1->nodeMax) {
3801	    xmlNodePtr *temp;
3802
3803	    val1->nodeMax *= 2;
3804	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3805					     sizeof(xmlNodePtr));
3806	    if (temp == NULL) {
3807	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3808		return(NULL);
3809	    }
3810	    val1->nodeTab = temp;
3811	}
3812	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3813	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3814
3815	    val1->nodeTab[val1->nodeNr++] =
3816		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3817	} else
3818	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3819    }
3820
3821    return(val1);
3822}
3823#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3824
3825/**
3826 * xmlXPathNodeSetMergeAndClear:
3827 * @set1:  the first NodeSet or NULL
3828 * @set2:  the second NodeSet
3829 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3830 *
3831 * Merges two nodesets, all nodes from @set2 are added to @set1
3832 * if @set1 is NULL, a new set is created and copied from @set2.
3833 * Checks for duplicate nodes. Clears set2.
3834 *
3835 * Returns @set1 once extended or NULL in case of error.
3836 */
3837static xmlNodeSetPtr
3838xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3839			     int hasNullEntries)
3840{
3841    if ((set1 == NULL) && (hasNullEntries == 0)) {
3842	/*
3843	* Note that doing a memcpy of the list, namespace nodes are
3844	* just assigned to set1, since set2 is cleared anyway.
3845	*/
3846	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3847	if (set1 == NULL)
3848	    return(NULL);
3849	if (set2->nodeNr != 0) {
3850	    memcpy(set1->nodeTab, set2->nodeTab,
3851		set2->nodeNr * sizeof(xmlNodePtr));
3852	    set1->nodeNr = set2->nodeNr;
3853	}
3854    } else {
3855	int i, j, initNbSet1;
3856	xmlNodePtr n1, n2;
3857
3858	if (set1 == NULL)
3859            set1 = xmlXPathNodeSetCreate(NULL);
3860        if (set1 == NULL)
3861            return (NULL);
3862
3863	initNbSet1 = set1->nodeNr;
3864	for (i = 0;i < set2->nodeNr;i++) {
3865	    n2 = set2->nodeTab[i];
3866	    /*
3867	    * Skip NULLed entries.
3868	    */
3869	    if (n2 == NULL)
3870		continue;
3871	    /*
3872	    * Skip duplicates.
3873	    */
3874	    for (j = 0; j < initNbSet1; j++) {
3875		n1 = set1->nodeTab[j];
3876		if (n1 == n2) {
3877		    goto skip_node;
3878		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3879		    (n2->type == XML_NAMESPACE_DECL))
3880		{
3881		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3882			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3883			((xmlNsPtr) n2)->prefix)))
3884		    {
3885			/*
3886			* Free the namespace node.
3887			*/
3888			set2->nodeTab[i] = NULL;
3889			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3890			goto skip_node;
3891		    }
3892		}
3893	    }
3894	    /*
3895	    * grow the nodeTab if needed
3896	    */
3897	    if (set1->nodeMax == 0) {
3898		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3899		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3900		if (set1->nodeTab == NULL) {
3901		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3902		    return(NULL);
3903		}
3904		memset(set1->nodeTab, 0,
3905		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3906		set1->nodeMax = XML_NODESET_DEFAULT;
3907	    } else if (set1->nodeNr >= set1->nodeMax) {
3908		xmlNodePtr *temp;
3909
3910		set1->nodeMax *= 2;
3911		temp = (xmlNodePtr *) xmlRealloc(
3912		    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3913		if (temp == NULL) {
3914		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3915		    return(NULL);
3916		}
3917		set1->nodeTab = temp;
3918	    }
3919	    if (n2->type == XML_NAMESPACE_DECL) {
3920		xmlNsPtr ns = (xmlNsPtr) n2;
3921
3922		set1->nodeTab[set1->nodeNr++] =
3923		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3924	    } else
3925		set1->nodeTab[set1->nodeNr++] = n2;
3926skip_node:
3927	    {}
3928	}
3929    }
3930    set2->nodeNr = 0;
3931    return(set1);
3932}
3933
3934/**
3935 * xmlXPathNodeSetMergeAndClearNoDupls:
3936 * @set1:  the first NodeSet or NULL
3937 * @set2:  the second NodeSet
3938 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3939 *
3940 * Merges two nodesets, all nodes from @set2 are added to @set1
3941 * if @set1 is NULL, a new set is created and copied from @set2.
3942 * Doesn't chack for duplicate nodes. Clears set2.
3943 *
3944 * Returns @set1 once extended or NULL in case of error.
3945 */
3946static xmlNodeSetPtr
3947xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3948				    int hasNullEntries)
3949{
3950    if (set2 == NULL)
3951	return(set1);
3952    if ((set1 == NULL) && (hasNullEntries == 0)) {
3953	/*
3954	* Note that doing a memcpy of the list, namespace nodes are
3955	* just assigned to set1, since set2 is cleared anyway.
3956	*/
3957	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3958	if (set1 == NULL)
3959	    return(NULL);
3960	if (set2->nodeNr != 0) {
3961	    memcpy(set1->nodeTab, set2->nodeTab,
3962		set2->nodeNr * sizeof(xmlNodePtr));
3963	    set1->nodeNr = set2->nodeNr;
3964	}
3965    } else {
3966	int i;
3967	xmlNodePtr n2;
3968
3969	if (set1 == NULL)
3970	    set1 = xmlXPathNodeSetCreate(NULL);
3971        if (set1 == NULL)
3972            return (NULL);
3973
3974	for (i = 0;i < set2->nodeNr;i++) {
3975	    n2 = set2->nodeTab[i];
3976	    /*
3977	    * Skip NULLed entries.
3978	    */
3979	    if (n2 == NULL)
3980		continue;
3981	    if (set1->nodeMax == 0) {
3982		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3983		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3984		if (set1->nodeTab == NULL) {
3985		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3986		    return(NULL);
3987		}
3988		memset(set1->nodeTab, 0,
3989		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3990		set1->nodeMax = XML_NODESET_DEFAULT;
3991	    } else if (set1->nodeNr >= set1->nodeMax) {
3992		xmlNodePtr *temp;
3993
3994		set1->nodeMax *= 2;
3995		temp = (xmlNodePtr *) xmlRealloc(
3996		    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3997		if (temp == NULL) {
3998		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3999		    return(NULL);
4000		}
4001		set1->nodeTab = temp;
4002	    }
4003	    set1->nodeTab[set1->nodeNr++] = n2;
4004	}
4005    }
4006    set2->nodeNr = 0;
4007    return(set1);
4008}
4009
4010/**
4011 * xmlXPathNodeSetDel:
4012 * @cur:  the initial node set
4013 * @val:  an xmlNodePtr
4014 *
4015 * Removes an xmlNodePtr from an existing NodeSet
4016 */
4017void
4018xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4019    int i;
4020
4021    if (cur == NULL) return;
4022    if (val == NULL) return;
4023
4024    /*
4025     * find node in nodeTab
4026     */
4027    for (i = 0;i < cur->nodeNr;i++)
4028        if (cur->nodeTab[i] == val) break;
4029
4030    if (i >= cur->nodeNr) {	/* not found */
4031#ifdef DEBUG
4032        xmlGenericError(xmlGenericErrorContext,
4033	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4034		val->name);
4035#endif
4036        return;
4037    }
4038    if ((cur->nodeTab[i] != NULL) &&
4039	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4040	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4041    cur->nodeNr--;
4042    for (;i < cur->nodeNr;i++)
4043        cur->nodeTab[i] = cur->nodeTab[i + 1];
4044    cur->nodeTab[cur->nodeNr] = NULL;
4045}
4046
4047/**
4048 * xmlXPathNodeSetRemove:
4049 * @cur:  the initial node set
4050 * @val:  the index to remove
4051 *
4052 * Removes an entry from an existing NodeSet list.
4053 */
4054void
4055xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4056    if (cur == NULL) return;
4057    if (val >= cur->nodeNr) return;
4058    if ((cur->nodeTab[val] != NULL) &&
4059	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4060	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4061    cur->nodeNr--;
4062    for (;val < cur->nodeNr;val++)
4063        cur->nodeTab[val] = cur->nodeTab[val + 1];
4064    cur->nodeTab[cur->nodeNr] = NULL;
4065}
4066
4067/**
4068 * xmlXPathFreeNodeSet:
4069 * @obj:  the xmlNodeSetPtr to free
4070 *
4071 * Free the NodeSet compound (not the actual nodes !).
4072 */
4073void
4074xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4075    if (obj == NULL) return;
4076    if (obj->nodeTab != NULL) {
4077	int i;
4078
4079	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4080	for (i = 0;i < obj->nodeNr;i++)
4081	    if ((obj->nodeTab[i] != NULL) &&
4082		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4083		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4084	xmlFree(obj->nodeTab);
4085    }
4086    xmlFree(obj);
4087}
4088
4089/**
4090 * xmlXPathNodeSetClear:
4091 * @set:  the node set to clear
4092 *
4093 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4094 * are feed), but does *not* free the list itself. Sets the length of the
4095 * list to 0.
4096 */
4097static void
4098xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4099{
4100    if ((set == NULL) || (set->nodeNr <= 0))
4101	return;
4102    else if (hasNsNodes) {
4103	int i;
4104	xmlNodePtr node;
4105
4106	for (i = 0; i < set->nodeNr; i++) {
4107	    node = set->nodeTab[i];
4108	    if ((node != NULL) &&
4109		(node->type == XML_NAMESPACE_DECL))
4110		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4111	}
4112    }
4113    set->nodeNr = 0;
4114}
4115
4116/**
4117 * xmlXPathNodeSetClearFromPos:
4118 * @set: the node set to be cleared
4119 * @pos: the start position to clear from
4120 *
4121 * Clears the list from temporary XPath objects (e.g. namespace nodes
4122 * are feed) starting with the entry at @pos, but does *not* free the list
4123 * itself. Sets the length of the list to @pos.
4124 */
4125static void
4126xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4127{
4128    if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4129	return;
4130    else if ((hasNsNodes)) {
4131	int i;
4132	xmlNodePtr node;
4133
4134	for (i = pos; i < set->nodeNr; i++) {
4135	    node = set->nodeTab[i];
4136	    if ((node != NULL) &&
4137		(node->type == XML_NAMESPACE_DECL))
4138		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4139	}
4140    }
4141    set->nodeNr = pos;
4142}
4143
4144/**
4145 * xmlXPathFreeValueTree:
4146 * @obj:  the xmlNodeSetPtr to free
4147 *
4148 * Free the NodeSet compound and the actual tree, this is different
4149 * from xmlXPathFreeNodeSet()
4150 */
4151static void
4152xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4153    int i;
4154
4155    if (obj == NULL) return;
4156
4157    if (obj->nodeTab != NULL) {
4158	for (i = 0;i < obj->nodeNr;i++) {
4159	    if (obj->nodeTab[i] != NULL) {
4160		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4161		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4162		} else {
4163		    xmlFreeNodeList(obj->nodeTab[i]);
4164		}
4165	    }
4166	}
4167	xmlFree(obj->nodeTab);
4168    }
4169    xmlFree(obj);
4170}
4171
4172#if defined(DEBUG) || defined(DEBUG_STEP)
4173/**
4174 * xmlGenericErrorContextNodeSet:
4175 * @output:  a FILE * for the output
4176 * @obj:  the xmlNodeSetPtr to display
4177 *
4178 * Quick display of a NodeSet
4179 */
4180void
4181xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4182    int i;
4183
4184    if (output == NULL) output = xmlGenericErrorContext;
4185    if (obj == NULL)  {
4186        fprintf(output, "NodeSet == NULL !\n");
4187	return;
4188    }
4189    if (obj->nodeNr == 0) {
4190        fprintf(output, "NodeSet is empty\n");
4191	return;
4192    }
4193    if (obj->nodeTab == NULL) {
4194	fprintf(output, " nodeTab == NULL !\n");
4195	return;
4196    }
4197    for (i = 0; i < obj->nodeNr; i++) {
4198        if (obj->nodeTab[i] == NULL) {
4199	    fprintf(output, " NULL !\n");
4200	    return;
4201        }
4202	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4203	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4204	    fprintf(output, " /");
4205	else if (obj->nodeTab[i]->name == NULL)
4206	    fprintf(output, " noname!");
4207	else fprintf(output, " %s", obj->nodeTab[i]->name);
4208    }
4209    fprintf(output, "\n");
4210}
4211#endif
4212
4213/**
4214 * xmlXPathNewNodeSet:
4215 * @val:  the NodePtr value
4216 *
4217 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4218 * it with the single Node @val
4219 *
4220 * Returns the newly created object.
4221 */
4222xmlXPathObjectPtr
4223xmlXPathNewNodeSet(xmlNodePtr val) {
4224    xmlXPathObjectPtr ret;
4225
4226    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4227    if (ret == NULL) {
4228        xmlXPathErrMemory(NULL, "creating nodeset\n");
4229	return(NULL);
4230    }
4231    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4232    ret->type = XPATH_NODESET;
4233    ret->boolval = 0;
4234    ret->nodesetval = xmlXPathNodeSetCreate(val);
4235    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4236#ifdef XP_DEBUG_OBJ_USAGE
4237    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4238#endif
4239    return(ret);
4240}
4241
4242/**
4243 * xmlXPathNewValueTree:
4244 * @val:  the NodePtr value
4245 *
4246 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4247 * it with the tree root @val
4248 *
4249 * Returns the newly created object.
4250 */
4251xmlXPathObjectPtr
4252xmlXPathNewValueTree(xmlNodePtr val) {
4253    xmlXPathObjectPtr ret;
4254
4255    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4256    if (ret == NULL) {
4257        xmlXPathErrMemory(NULL, "creating result value tree\n");
4258	return(NULL);
4259    }
4260    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4261    ret->type = XPATH_XSLT_TREE;
4262    ret->boolval = 1;
4263    ret->user = (void *) val;
4264    ret->nodesetval = xmlXPathNodeSetCreate(val);
4265#ifdef XP_DEBUG_OBJ_USAGE
4266    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4267#endif
4268    return(ret);
4269}
4270
4271/**
4272 * xmlXPathNewNodeSetList:
4273 * @val:  an existing NodeSet
4274 *
4275 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4276 * it with the Nodeset @val
4277 *
4278 * Returns the newly created object.
4279 */
4280xmlXPathObjectPtr
4281xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4282{
4283    xmlXPathObjectPtr ret;
4284    int i;
4285
4286    if (val == NULL)
4287        ret = NULL;
4288    else if (val->nodeTab == NULL)
4289        ret = xmlXPathNewNodeSet(NULL);
4290    else {
4291        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4292        if (ret)
4293            for (i = 1; i < val->nodeNr; ++i)
4294                xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4295    }
4296
4297    return (ret);
4298}
4299
4300/**
4301 * xmlXPathWrapNodeSet:
4302 * @val:  the NodePtr value
4303 *
4304 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4305 *
4306 * Returns the newly created object.
4307 */
4308xmlXPathObjectPtr
4309xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4310    xmlXPathObjectPtr ret;
4311
4312    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4313    if (ret == NULL) {
4314        xmlXPathErrMemory(NULL, "creating node set object\n");
4315	return(NULL);
4316    }
4317    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4318    ret->type = XPATH_NODESET;
4319    ret->nodesetval = val;
4320#ifdef XP_DEBUG_OBJ_USAGE
4321    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4322#endif
4323    return(ret);
4324}
4325
4326/**
4327 * xmlXPathFreeNodeSetList:
4328 * @obj:  an existing NodeSetList object
4329 *
4330 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4331 * the list contrary to xmlXPathFreeObject().
4332 */
4333void
4334xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4335    if (obj == NULL) return;
4336#ifdef XP_DEBUG_OBJ_USAGE
4337    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4338#endif
4339    xmlFree(obj);
4340}
4341
4342/**
4343 * xmlXPathDifference:
4344 * @nodes1:  a node-set
4345 * @nodes2:  a node-set
4346 *
4347 * Implements the EXSLT - Sets difference() function:
4348 *    node-set set:difference (node-set, node-set)
4349 *
4350 * Returns the difference between the two node sets, or nodes1 if
4351 *         nodes2 is empty
4352 */
4353xmlNodeSetPtr
4354xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4355    xmlNodeSetPtr ret;
4356    int i, l1;
4357    xmlNodePtr cur;
4358
4359    if (xmlXPathNodeSetIsEmpty(nodes2))
4360	return(nodes1);
4361
4362    ret = xmlXPathNodeSetCreate(NULL);
4363    if (xmlXPathNodeSetIsEmpty(nodes1))
4364	return(ret);
4365
4366    l1 = xmlXPathNodeSetGetLength(nodes1);
4367
4368    for (i = 0; i < l1; i++) {
4369	cur = xmlXPathNodeSetItem(nodes1, i);
4370	if (!xmlXPathNodeSetContains(nodes2, cur))
4371	    xmlXPathNodeSetAddUnique(ret, cur);
4372    }
4373    return(ret);
4374}
4375
4376/**
4377 * xmlXPathIntersection:
4378 * @nodes1:  a node-set
4379 * @nodes2:  a node-set
4380 *
4381 * Implements the EXSLT - Sets intersection() function:
4382 *    node-set set:intersection (node-set, node-set)
4383 *
4384 * Returns a node set comprising the nodes that are within both the
4385 *         node sets passed as arguments
4386 */
4387xmlNodeSetPtr
4388xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4389    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4390    int i, l1;
4391    xmlNodePtr cur;
4392
4393    if (ret == NULL)
4394        return(ret);
4395    if (xmlXPathNodeSetIsEmpty(nodes1))
4396	return(ret);
4397    if (xmlXPathNodeSetIsEmpty(nodes2))
4398	return(ret);
4399
4400    l1 = xmlXPathNodeSetGetLength(nodes1);
4401
4402    for (i = 0; i < l1; i++) {
4403	cur = xmlXPathNodeSetItem(nodes1, i);
4404	if (xmlXPathNodeSetContains(nodes2, cur))
4405	    xmlXPathNodeSetAddUnique(ret, cur);
4406    }
4407    return(ret);
4408}
4409
4410/**
4411 * xmlXPathDistinctSorted:
4412 * @nodes:  a node-set, sorted by document order
4413 *
4414 * Implements the EXSLT - Sets distinct() function:
4415 *    node-set set:distinct (node-set)
4416 *
4417 * Returns a subset of the nodes contained in @nodes, or @nodes if
4418 *         it is empty
4419 */
4420xmlNodeSetPtr
4421xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4422    xmlNodeSetPtr ret;
4423    xmlHashTablePtr hash;
4424    int i, l;
4425    xmlChar * strval;
4426    xmlNodePtr cur;
4427
4428    if (xmlXPathNodeSetIsEmpty(nodes))
4429	return(nodes);
4430
4431    ret = xmlXPathNodeSetCreate(NULL);
4432    if (ret == NULL)
4433        return(ret);
4434    l = xmlXPathNodeSetGetLength(nodes);
4435    hash = xmlHashCreate (l);
4436    for (i = 0; i < l; i++) {
4437	cur = xmlXPathNodeSetItem(nodes, i);
4438	strval = xmlXPathCastNodeToString(cur);
4439	if (xmlHashLookup(hash, strval) == NULL) {
4440	    xmlHashAddEntry(hash, strval, strval);
4441	    xmlXPathNodeSetAddUnique(ret, cur);
4442	} else {
4443	    xmlFree(strval);
4444	}
4445    }
4446    xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4447    return(ret);
4448}
4449
4450/**
4451 * xmlXPathDistinct:
4452 * @nodes:  a node-set
4453 *
4454 * Implements the EXSLT - Sets distinct() function:
4455 *    node-set set:distinct (node-set)
4456 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4457 * is called with the sorted node-set
4458 *
4459 * Returns a subset of the nodes contained in @nodes, or @nodes if
4460 *         it is empty
4461 */
4462xmlNodeSetPtr
4463xmlXPathDistinct (xmlNodeSetPtr nodes) {
4464    if (xmlXPathNodeSetIsEmpty(nodes))
4465	return(nodes);
4466
4467    xmlXPathNodeSetSort(nodes);
4468    return(xmlXPathDistinctSorted(nodes));
4469}
4470
4471/**
4472 * xmlXPathHasSameNodes:
4473 * @nodes1:  a node-set
4474 * @nodes2:  a node-set
4475 *
4476 * Implements the EXSLT - Sets has-same-nodes function:
4477 *    boolean set:has-same-node(node-set, node-set)
4478 *
4479 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4480 *         otherwise
4481 */
4482int
4483xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4484    int i, l;
4485    xmlNodePtr cur;
4486
4487    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4488	xmlXPathNodeSetIsEmpty(nodes2))
4489	return(0);
4490
4491    l = xmlXPathNodeSetGetLength(nodes1);
4492    for (i = 0; i < l; i++) {
4493	cur = xmlXPathNodeSetItem(nodes1, i);
4494	if (xmlXPathNodeSetContains(nodes2, cur))
4495	    return(1);
4496    }
4497    return(0);
4498}
4499
4500/**
4501 * xmlXPathNodeLeadingSorted:
4502 * @nodes: a node-set, sorted by document order
4503 * @node: a node
4504 *
4505 * Implements the EXSLT - Sets leading() function:
4506 *    node-set set:leading (node-set, node-set)
4507 *
4508 * Returns the nodes in @nodes that precede @node in document order,
4509 *         @nodes if @node is NULL or an empty node-set if @nodes
4510 *         doesn't contain @node
4511 */
4512xmlNodeSetPtr
4513xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4514    int i, l;
4515    xmlNodePtr cur;
4516    xmlNodeSetPtr ret;
4517
4518    if (node == NULL)
4519	return(nodes);
4520
4521    ret = xmlXPathNodeSetCreate(NULL);
4522    if (ret == NULL)
4523        return(ret);
4524    if (xmlXPathNodeSetIsEmpty(nodes) ||
4525	(!xmlXPathNodeSetContains(nodes, node)))
4526	return(ret);
4527
4528    l = xmlXPathNodeSetGetLength(nodes);
4529    for (i = 0; i < l; i++) {
4530	cur = xmlXPathNodeSetItem(nodes, i);
4531	if (cur == node)
4532	    break;
4533	xmlXPathNodeSetAddUnique(ret, cur);
4534    }
4535    return(ret);
4536}
4537
4538/**
4539 * xmlXPathNodeLeading:
4540 * @nodes:  a node-set
4541 * @node:  a node
4542 *
4543 * Implements the EXSLT - Sets leading() function:
4544 *    node-set set:leading (node-set, node-set)
4545 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4546 * is called.
4547 *
4548 * Returns the nodes in @nodes that precede @node in document order,
4549 *         @nodes if @node is NULL or an empty node-set if @nodes
4550 *         doesn't contain @node
4551 */
4552xmlNodeSetPtr
4553xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4554    xmlXPathNodeSetSort(nodes);
4555    return(xmlXPathNodeLeadingSorted(nodes, node));
4556}
4557
4558/**
4559 * xmlXPathLeadingSorted:
4560 * @nodes1:  a node-set, sorted by document order
4561 * @nodes2:  a node-set, sorted by document order
4562 *
4563 * Implements the EXSLT - Sets leading() function:
4564 *    node-set set:leading (node-set, node-set)
4565 *
4566 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4567 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4568 *         an empty node-set if @nodes1 doesn't contain @nodes2
4569 */
4570xmlNodeSetPtr
4571xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4572    if (xmlXPathNodeSetIsEmpty(nodes2))
4573	return(nodes1);
4574    return(xmlXPathNodeLeadingSorted(nodes1,
4575				     xmlXPathNodeSetItem(nodes2, 1)));
4576}
4577
4578/**
4579 * xmlXPathLeading:
4580 * @nodes1:  a node-set
4581 * @nodes2:  a node-set
4582 *
4583 * Implements the EXSLT - Sets leading() function:
4584 *    node-set set:leading (node-set, node-set)
4585 * @nodes1 and @nodes2 are sorted by document order, then
4586 * #exslSetsLeadingSorted is called.
4587 *
4588 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4589 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4590 *         an empty node-set if @nodes1 doesn't contain @nodes2
4591 */
4592xmlNodeSetPtr
4593xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4594    if (xmlXPathNodeSetIsEmpty(nodes2))
4595	return(nodes1);
4596    if (xmlXPathNodeSetIsEmpty(nodes1))
4597	return(xmlXPathNodeSetCreate(NULL));
4598    xmlXPathNodeSetSort(nodes1);
4599    xmlXPathNodeSetSort(nodes2);
4600    return(xmlXPathNodeLeadingSorted(nodes1,
4601				     xmlXPathNodeSetItem(nodes2, 1)));
4602}
4603
4604/**
4605 * xmlXPathNodeTrailingSorted:
4606 * @nodes: a node-set, sorted by document order
4607 * @node: a node
4608 *
4609 * Implements the EXSLT - Sets trailing() function:
4610 *    node-set set:trailing (node-set, node-set)
4611 *
4612 * Returns the nodes in @nodes that follow @node in document order,
4613 *         @nodes if @node is NULL or an empty node-set if @nodes
4614 *         doesn't contain @node
4615 */
4616xmlNodeSetPtr
4617xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4618    int i, l;
4619    xmlNodePtr cur;
4620    xmlNodeSetPtr ret;
4621
4622    if (node == NULL)
4623	return(nodes);
4624
4625    ret = xmlXPathNodeSetCreate(NULL);
4626    if (ret == NULL)
4627        return(ret);
4628    if (xmlXPathNodeSetIsEmpty(nodes) ||
4629	(!xmlXPathNodeSetContains(nodes, node)))
4630	return(ret);
4631
4632    l = xmlXPathNodeSetGetLength(nodes);
4633    for (i = l - 1; i >= 0; i--) {
4634	cur = xmlXPathNodeSetItem(nodes, i);
4635	if (cur == node)
4636	    break;
4637	xmlXPathNodeSetAddUnique(ret, cur);
4638    }
4639    xmlXPathNodeSetSort(ret);	/* bug 413451 */
4640    return(ret);
4641}
4642
4643/**
4644 * xmlXPathNodeTrailing:
4645 * @nodes:  a node-set
4646 * @node:  a node
4647 *
4648 * Implements the EXSLT - Sets trailing() function:
4649 *    node-set set:trailing (node-set, node-set)
4650 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4651 * is called.
4652 *
4653 * Returns the nodes in @nodes that follow @node in document order,
4654 *         @nodes if @node is NULL or an empty node-set if @nodes
4655 *         doesn't contain @node
4656 */
4657xmlNodeSetPtr
4658xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4659    xmlXPathNodeSetSort(nodes);
4660    return(xmlXPathNodeTrailingSorted(nodes, node));
4661}
4662
4663/**
4664 * xmlXPathTrailingSorted:
4665 * @nodes1:  a node-set, sorted by document order
4666 * @nodes2:  a node-set, sorted by document order
4667 *
4668 * Implements the EXSLT - Sets trailing() function:
4669 *    node-set set:trailing (node-set, node-set)
4670 *
4671 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4672 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4673 *         an empty node-set if @nodes1 doesn't contain @nodes2
4674 */
4675xmlNodeSetPtr
4676xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4677    if (xmlXPathNodeSetIsEmpty(nodes2))
4678	return(nodes1);
4679    return(xmlXPathNodeTrailingSorted(nodes1,
4680				      xmlXPathNodeSetItem(nodes2, 0)));
4681}
4682
4683/**
4684 * xmlXPathTrailing:
4685 * @nodes1:  a node-set
4686 * @nodes2:  a node-set
4687 *
4688 * Implements the EXSLT - Sets trailing() function:
4689 *    node-set set:trailing (node-set, node-set)
4690 * @nodes1 and @nodes2 are sorted by document order, then
4691 * #xmlXPathTrailingSorted is called.
4692 *
4693 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4694 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4695 *         an empty node-set if @nodes1 doesn't contain @nodes2
4696 */
4697xmlNodeSetPtr
4698xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4699    if (xmlXPathNodeSetIsEmpty(nodes2))
4700	return(nodes1);
4701    if (xmlXPathNodeSetIsEmpty(nodes1))
4702	return(xmlXPathNodeSetCreate(NULL));
4703    xmlXPathNodeSetSort(nodes1);
4704    xmlXPathNodeSetSort(nodes2);
4705    return(xmlXPathNodeTrailingSorted(nodes1,
4706				      xmlXPathNodeSetItem(nodes2, 0)));
4707}
4708
4709/************************************************************************
4710 *									*
4711 *		Routines to handle extra functions			*
4712 *									*
4713 ************************************************************************/
4714
4715/**
4716 * xmlXPathRegisterFunc:
4717 * @ctxt:  the XPath context
4718 * @name:  the function name
4719 * @f:  the function implementation or NULL
4720 *
4721 * Register a new function. If @f is NULL it unregisters the function
4722 *
4723 * Returns 0 in case of success, -1 in case of error
4724 */
4725int
4726xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4727		     xmlXPathFunction f) {
4728    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4729}
4730
4731/**
4732 * xmlXPathRegisterFuncNS:
4733 * @ctxt:  the XPath context
4734 * @name:  the function name
4735 * @ns_uri:  the function namespace URI
4736 * @f:  the function implementation or NULL
4737 *
4738 * Register a new function. If @f is NULL it unregisters the function
4739 *
4740 * Returns 0 in case of success, -1 in case of error
4741 */
4742int
4743xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4744		       const xmlChar *ns_uri, xmlXPathFunction f) {
4745    if (ctxt == NULL)
4746	return(-1);
4747    if (name == NULL)
4748	return(-1);
4749
4750    if (ctxt->funcHash == NULL)
4751	ctxt->funcHash = xmlHashCreate(0);
4752    if (ctxt->funcHash == NULL)
4753	return(-1);
4754    if (f == NULL)
4755        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4756    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4757}
4758
4759/**
4760 * xmlXPathRegisterFuncLookup:
4761 * @ctxt:  the XPath context
4762 * @f:  the lookup function
4763 * @funcCtxt:  the lookup data
4764 *
4765 * Registers an external mechanism to do function lookup.
4766 */
4767void
4768xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4769			    xmlXPathFuncLookupFunc f,
4770			    void *funcCtxt) {
4771    if (ctxt == NULL)
4772	return;
4773    ctxt->funcLookupFunc = f;
4774    ctxt->funcLookupData = funcCtxt;
4775}
4776
4777/**
4778 * xmlXPathFunctionLookup:
4779 * @ctxt:  the XPath context
4780 * @name:  the function name
4781 *
4782 * Search in the Function array of the context for the given
4783 * function.
4784 *
4785 * Returns the xmlXPathFunction or NULL if not found
4786 */
4787xmlXPathFunction
4788xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4789    if (ctxt == NULL)
4790	return (NULL);
4791
4792    if (ctxt->funcLookupFunc != NULL) {
4793	xmlXPathFunction ret;
4794	xmlXPathFuncLookupFunc f;
4795
4796	f = ctxt->funcLookupFunc;
4797	ret = f(ctxt->funcLookupData, name, NULL);
4798	if (ret != NULL)
4799	    return(ret);
4800    }
4801    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4802}
4803
4804/**
4805 * xmlXPathFunctionLookupNS:
4806 * @ctxt:  the XPath context
4807 * @name:  the function name
4808 * @ns_uri:  the function namespace URI
4809 *
4810 * Search in the Function array of the context for the given
4811 * function.
4812 *
4813 * Returns the xmlXPathFunction or NULL if not found
4814 */
4815xmlXPathFunction
4816xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4817			 const xmlChar *ns_uri) {
4818    xmlXPathFunction ret;
4819
4820    if (ctxt == NULL)
4821	return(NULL);
4822    if (name == NULL)
4823	return(NULL);
4824
4825    if (ctxt->funcLookupFunc != NULL) {
4826	xmlXPathFuncLookupFunc f;
4827
4828	f = ctxt->funcLookupFunc;
4829	ret = f(ctxt->funcLookupData, name, ns_uri);
4830	if (ret != NULL)
4831	    return(ret);
4832    }
4833
4834    if (ctxt->funcHash == NULL)
4835	return(NULL);
4836
4837    XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4838    return(ret);
4839}
4840
4841/**
4842 * xmlXPathRegisteredFuncsCleanup:
4843 * @ctxt:  the XPath context
4844 *
4845 * Cleanup the XPath context data associated to registered functions
4846 */
4847void
4848xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4849    if (ctxt == NULL)
4850	return;
4851
4852    xmlHashFree(ctxt->funcHash, NULL);
4853    ctxt->funcHash = NULL;
4854}
4855
4856/************************************************************************
4857 *									*
4858 *			Routines to handle Variables			*
4859 *									*
4860 ************************************************************************/
4861
4862/**
4863 * xmlXPathRegisterVariable:
4864 * @ctxt:  the XPath context
4865 * @name:  the variable name
4866 * @value:  the variable value or NULL
4867 *
4868 * Register a new variable value. If @value is NULL it unregisters
4869 * the variable
4870 *
4871 * Returns 0 in case of success, -1 in case of error
4872 */
4873int
4874xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4875			 xmlXPathObjectPtr value) {
4876    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4877}
4878
4879/**
4880 * xmlXPathRegisterVariableNS:
4881 * @ctxt:  the XPath context
4882 * @name:  the variable name
4883 * @ns_uri:  the variable namespace URI
4884 * @value:  the variable value or NULL
4885 *
4886 * Register a new variable value. If @value is NULL it unregisters
4887 * the variable
4888 *
4889 * Returns 0 in case of success, -1 in case of error
4890 */
4891int
4892xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4893			   const xmlChar *ns_uri,
4894			   xmlXPathObjectPtr value) {
4895    if (ctxt == NULL)
4896	return(-1);
4897    if (name == NULL)
4898	return(-1);
4899
4900    if (ctxt->varHash == NULL)
4901	ctxt->varHash = xmlHashCreate(0);
4902    if (ctxt->varHash == NULL)
4903	return(-1);
4904    if (value == NULL)
4905        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4906	                           (xmlHashDeallocator)xmlXPathFreeObject));
4907    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4908			       (void *) value,
4909			       (xmlHashDeallocator)xmlXPathFreeObject));
4910}
4911
4912/**
4913 * xmlXPathRegisterVariableLookup:
4914 * @ctxt:  the XPath context
4915 * @f:  the lookup function
4916 * @data:  the lookup data
4917 *
4918 * register an external mechanism to do variable lookup
4919 */
4920void
4921xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4922	 xmlXPathVariableLookupFunc f, void *data) {
4923    if (ctxt == NULL)
4924	return;
4925    ctxt->varLookupFunc = f;
4926    ctxt->varLookupData = data;
4927}
4928
4929/**
4930 * xmlXPathVariableLookup:
4931 * @ctxt:  the XPath context
4932 * @name:  the variable name
4933 *
4934 * Search in the Variable array of the context for the given
4935 * variable value.
4936 *
4937 * Returns a copy of the value or NULL if not found
4938 */
4939xmlXPathObjectPtr
4940xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4941    if (ctxt == NULL)
4942	return(NULL);
4943
4944    if (ctxt->varLookupFunc != NULL) {
4945	xmlXPathObjectPtr ret;
4946
4947	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4948	        (ctxt->varLookupData, name, NULL);
4949	return(ret);
4950    }
4951    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4952}
4953
4954/**
4955 * xmlXPathVariableLookupNS:
4956 * @ctxt:  the XPath context
4957 * @name:  the variable name
4958 * @ns_uri:  the variable namespace URI
4959 *
4960 * Search in the Variable array of the context for the given
4961 * variable value.
4962 *
4963 * Returns the a copy of the value or NULL if not found
4964 */
4965xmlXPathObjectPtr
4966xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4967			 const xmlChar *ns_uri) {
4968    if (ctxt == NULL)
4969	return(NULL);
4970
4971    if (ctxt->varLookupFunc != NULL) {
4972	xmlXPathObjectPtr ret;
4973
4974	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4975	        (ctxt->varLookupData, name, ns_uri);
4976	if (ret != NULL) return(ret);
4977    }
4978
4979    if (ctxt->varHash == NULL)
4980	return(NULL);
4981    if (name == NULL)
4982	return(NULL);
4983
4984    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
4985		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4986}
4987
4988/**
4989 * xmlXPathRegisteredVariablesCleanup:
4990 * @ctxt:  the XPath context
4991 *
4992 * Cleanup the XPath context data associated to registered variables
4993 */
4994void
4995xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4996    if (ctxt == NULL)
4997	return;
4998
4999    xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5000    ctxt->varHash = NULL;
5001}
5002
5003/**
5004 * xmlXPathRegisterNs:
5005 * @ctxt:  the XPath context
5006 * @prefix:  the namespace prefix cannot be NULL or empty string
5007 * @ns_uri:  the namespace name
5008 *
5009 * Register a new namespace. If @ns_uri is NULL it unregisters
5010 * the namespace
5011 *
5012 * Returns 0 in case of success, -1 in case of error
5013 */
5014int
5015xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5016			   const xmlChar *ns_uri) {
5017    if (ctxt == NULL)
5018	return(-1);
5019    if (prefix == NULL)
5020	return(-1);
5021    if (prefix[0] == 0)
5022	return(-1);
5023
5024    if (ctxt->nsHash == NULL)
5025	ctxt->nsHash = xmlHashCreate(10);
5026    if (ctxt->nsHash == NULL)
5027	return(-1);
5028    if (ns_uri == NULL)
5029        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5030	                          (xmlHashDeallocator)xmlFree));
5031    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5032			      (xmlHashDeallocator)xmlFree));
5033}
5034
5035/**
5036 * xmlXPathNsLookup:
5037 * @ctxt:  the XPath context
5038 * @prefix:  the namespace prefix value
5039 *
5040 * Search in the namespace declaration array of the context for the given
5041 * namespace name associated to the given prefix
5042 *
5043 * Returns the value or NULL if not found
5044 */
5045const xmlChar *
5046xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5047    if (ctxt == NULL)
5048	return(NULL);
5049    if (prefix == NULL)
5050	return(NULL);
5051
5052#ifdef XML_XML_NAMESPACE
5053    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5054	return(XML_XML_NAMESPACE);
5055#endif
5056
5057    if (ctxt->namespaces != NULL) {
5058	int i;
5059
5060	for (i = 0;i < ctxt->nsNr;i++) {
5061	    if ((ctxt->namespaces[i] != NULL) &&
5062		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5063		return(ctxt->namespaces[i]->href);
5064	}
5065    }
5066
5067    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5068}
5069
5070/**
5071 * xmlXPathRegisteredNsCleanup:
5072 * @ctxt:  the XPath context
5073 *
5074 * Cleanup the XPath context data associated to registered variables
5075 */
5076void
5077xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5078    if (ctxt == NULL)
5079	return;
5080
5081    xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5082    ctxt->nsHash = NULL;
5083}
5084
5085/************************************************************************
5086 *									*
5087 *			Routines to handle Values			*
5088 *									*
5089 ************************************************************************/
5090
5091/* Allocations are terrible, one needs to optimize all this !!! */
5092
5093/**
5094 * xmlXPathNewFloat:
5095 * @val:  the double value
5096 *
5097 * Create a new xmlXPathObjectPtr of type double and of value @val
5098 *
5099 * Returns the newly created object.
5100 */
5101xmlXPathObjectPtr
5102xmlXPathNewFloat(double val) {
5103    xmlXPathObjectPtr ret;
5104
5105    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5106    if (ret == NULL) {
5107        xmlXPathErrMemory(NULL, "creating float object\n");
5108	return(NULL);
5109    }
5110    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5111    ret->type = XPATH_NUMBER;
5112    ret->floatval = val;
5113#ifdef XP_DEBUG_OBJ_USAGE
5114    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5115#endif
5116    return(ret);
5117}
5118
5119/**
5120 * xmlXPathNewBoolean:
5121 * @val:  the boolean value
5122 *
5123 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5124 *
5125 * Returns the newly created object.
5126 */
5127xmlXPathObjectPtr
5128xmlXPathNewBoolean(int val) {
5129    xmlXPathObjectPtr ret;
5130
5131    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5132    if (ret == NULL) {
5133        xmlXPathErrMemory(NULL, "creating boolean object\n");
5134	return(NULL);
5135    }
5136    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5137    ret->type = XPATH_BOOLEAN;
5138    ret->boolval = (val != 0);
5139#ifdef XP_DEBUG_OBJ_USAGE
5140    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5141#endif
5142    return(ret);
5143}
5144
5145/**
5146 * xmlXPathNewString:
5147 * @val:  the xmlChar * value
5148 *
5149 * Create a new xmlXPathObjectPtr of type string and of value @val
5150 *
5151 * Returns the newly created object.
5152 */
5153xmlXPathObjectPtr
5154xmlXPathNewString(const xmlChar *val) {
5155    xmlXPathObjectPtr ret;
5156
5157    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5158    if (ret == NULL) {
5159        xmlXPathErrMemory(NULL, "creating string object\n");
5160	return(NULL);
5161    }
5162    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5163    ret->type = XPATH_STRING;
5164    if (val != NULL)
5165	ret->stringval = xmlStrdup(val);
5166    else
5167	ret->stringval = xmlStrdup((const xmlChar *)"");
5168#ifdef XP_DEBUG_OBJ_USAGE
5169    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5170#endif
5171    return(ret);
5172}
5173
5174/**
5175 * xmlXPathWrapString:
5176 * @val:  the xmlChar * value
5177 *
5178 * Wraps the @val string into an XPath object.
5179 *
5180 * Returns the newly created object.
5181 */
5182xmlXPathObjectPtr
5183xmlXPathWrapString (xmlChar *val) {
5184    xmlXPathObjectPtr ret;
5185
5186    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5187    if (ret == NULL) {
5188        xmlXPathErrMemory(NULL, "creating string object\n");
5189	return(NULL);
5190    }
5191    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5192    ret->type = XPATH_STRING;
5193    ret->stringval = val;
5194#ifdef XP_DEBUG_OBJ_USAGE
5195    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5196#endif
5197    return(ret);
5198}
5199
5200/**
5201 * xmlXPathNewCString:
5202 * @val:  the char * value
5203 *
5204 * Create a new xmlXPathObjectPtr of type string and of value @val
5205 *
5206 * Returns the newly created object.
5207 */
5208xmlXPathObjectPtr
5209xmlXPathNewCString(const char *val) {
5210    xmlXPathObjectPtr ret;
5211
5212    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5213    if (ret == NULL) {
5214        xmlXPathErrMemory(NULL, "creating string object\n");
5215	return(NULL);
5216    }
5217    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5218    ret->type = XPATH_STRING;
5219    ret->stringval = xmlStrdup(BAD_CAST val);
5220#ifdef XP_DEBUG_OBJ_USAGE
5221    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5222#endif
5223    return(ret);
5224}
5225
5226/**
5227 * xmlXPathWrapCString:
5228 * @val:  the char * value
5229 *
5230 * Wraps a string into an XPath object.
5231 *
5232 * Returns the newly created object.
5233 */
5234xmlXPathObjectPtr
5235xmlXPathWrapCString (char * val) {
5236    return(xmlXPathWrapString((xmlChar *)(val)));
5237}
5238
5239/**
5240 * xmlXPathWrapExternal:
5241 * @val:  the user data
5242 *
5243 * Wraps the @val data into an XPath object.
5244 *
5245 * Returns the newly created object.
5246 */
5247xmlXPathObjectPtr
5248xmlXPathWrapExternal (void *val) {
5249    xmlXPathObjectPtr ret;
5250
5251    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5252    if (ret == NULL) {
5253        xmlXPathErrMemory(NULL, "creating user object\n");
5254	return(NULL);
5255    }
5256    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5257    ret->type = XPATH_USERS;
5258    ret->user = val;
5259#ifdef XP_DEBUG_OBJ_USAGE
5260    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5261#endif
5262    return(ret);
5263}
5264
5265/**
5266 * xmlXPathObjectCopy:
5267 * @val:  the original object
5268 *
5269 * allocate a new copy of a given object
5270 *
5271 * Returns the newly created object.
5272 */
5273xmlXPathObjectPtr
5274xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5275    xmlXPathObjectPtr ret;
5276
5277    if (val == NULL)
5278	return(NULL);
5279
5280    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5281    if (ret == NULL) {
5282        xmlXPathErrMemory(NULL, "copying object\n");
5283	return(NULL);
5284    }
5285    memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5286#ifdef XP_DEBUG_OBJ_USAGE
5287    xmlXPathDebugObjUsageRequested(NULL, val->type);
5288#endif
5289    switch (val->type) {
5290	case XPATH_BOOLEAN:
5291	case XPATH_NUMBER:
5292	case XPATH_POINT:
5293	case XPATH_RANGE:
5294	    break;
5295	case XPATH_STRING:
5296	    ret->stringval = xmlStrdup(val->stringval);
5297	    break;
5298	case XPATH_XSLT_TREE:
5299#if 0
5300/*
5301  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5302  this previous handling is no longer correct, and can cause some serious
5303  problems (ref. bug 145547)
5304*/
5305	    if ((val->nodesetval != NULL) &&
5306		(val->nodesetval->nodeTab != NULL)) {
5307		xmlNodePtr cur, tmp;
5308		xmlDocPtr top;
5309
5310		ret->boolval = 1;
5311		top =  xmlNewDoc(NULL);
5312		top->name = (char *)
5313		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5314		ret->user = top;
5315		if (top != NULL) {
5316		    top->doc = top;
5317		    cur = val->nodesetval->nodeTab[0]->children;
5318		    while (cur != NULL) {
5319			tmp = xmlDocCopyNode(cur, top, 1);
5320			xmlAddChild((xmlNodePtr) top, tmp);
5321			cur = cur->next;
5322		    }
5323		}
5324
5325		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5326	    } else
5327		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5328	    /* Deallocate the copied tree value */
5329	    break;
5330#endif
5331	case XPATH_NODESET:
5332	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5333	    /* Do not deallocate the copied tree value */
5334	    ret->boolval = 0;
5335	    break;
5336	case XPATH_LOCATIONSET:
5337#ifdef LIBXML_XPTR_ENABLED
5338	{
5339	    xmlLocationSetPtr loc = val->user;
5340	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5341	    break;
5342	}
5343#endif
5344        case XPATH_USERS:
5345	    ret->user = val->user;
5346	    break;
5347        case XPATH_UNDEFINED:
5348	    xmlGenericError(xmlGenericErrorContext,
5349		    "xmlXPathObjectCopy: unsupported type %d\n",
5350		    val->type);
5351	    break;
5352    }
5353    return(ret);
5354}
5355
5356/**
5357 * xmlXPathFreeObject:
5358 * @obj:  the object to free
5359 *
5360 * Free up an xmlXPathObjectPtr object.
5361 */
5362void
5363xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5364    if (obj == NULL) return;
5365    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5366	if (obj->boolval) {
5367#if 0
5368	    if (obj->user != NULL) {
5369                xmlXPathFreeNodeSet(obj->nodesetval);
5370		xmlFreeNodeList((xmlNodePtr) obj->user);
5371	    } else
5372#endif
5373	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5374	    if (obj->nodesetval != NULL)
5375		xmlXPathFreeValueTree(obj->nodesetval);
5376	} else {
5377	    if (obj->nodesetval != NULL)
5378		xmlXPathFreeNodeSet(obj->nodesetval);
5379	}
5380#ifdef LIBXML_XPTR_ENABLED
5381    } else if (obj->type == XPATH_LOCATIONSET) {
5382	if (obj->user != NULL)
5383	    xmlXPtrFreeLocationSet(obj->user);
5384#endif
5385    } else if (obj->type == XPATH_STRING) {
5386	if (obj->stringval != NULL)
5387	    xmlFree(obj->stringval);
5388    }
5389#ifdef XP_DEBUG_OBJ_USAGE
5390    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5391#endif
5392    xmlFree(obj);
5393}
5394
5395/**
5396 * xmlXPathReleaseObject:
5397 * @obj:  the xmlXPathObjectPtr to free or to cache
5398 *
5399 * Depending on the state of the cache this frees the given
5400 * XPath object or stores it in the cache.
5401 */
5402static void
5403xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5404{
5405#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5406	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5407    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5408
5409#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5410
5411    if (obj == NULL)
5412	return;
5413    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5414	 xmlXPathFreeObject(obj);
5415    } else {
5416	xmlXPathContextCachePtr cache =
5417	    (xmlXPathContextCachePtr) ctxt->cache;
5418
5419	switch (obj->type) {
5420	    case XPATH_NODESET:
5421	    case XPATH_XSLT_TREE:
5422		if (obj->nodesetval != NULL) {
5423		    if (obj->boolval) {
5424			/*
5425			* It looks like the @boolval is used for
5426			* evaluation if this an XSLT Result Tree Fragment.
5427			* TODO: Check if this assumption is correct.
5428			*/
5429			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5430			xmlXPathFreeValueTree(obj->nodesetval);
5431			obj->nodesetval = NULL;
5432		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5433			(XP_CACHE_WANTS(cache->nodesetObjs,
5434					cache->maxNodeset)))
5435		    {
5436			XP_CACHE_ADD(cache->nodesetObjs, obj);
5437			goto obj_cached;
5438		    } else {
5439			xmlXPathFreeNodeSet(obj->nodesetval);
5440			obj->nodesetval = NULL;
5441		    }
5442		}
5443		break;
5444	    case XPATH_STRING:
5445		if (obj->stringval != NULL)
5446		    xmlFree(obj->stringval);
5447
5448		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5449		    XP_CACHE_ADD(cache->stringObjs, obj);
5450		    goto obj_cached;
5451		}
5452		break;
5453	    case XPATH_BOOLEAN:
5454		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5455		    XP_CACHE_ADD(cache->booleanObjs, obj);
5456		    goto obj_cached;
5457		}
5458		break;
5459	    case XPATH_NUMBER:
5460		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5461		    XP_CACHE_ADD(cache->numberObjs, obj);
5462		    goto obj_cached;
5463		}
5464		break;
5465#ifdef LIBXML_XPTR_ENABLED
5466	    case XPATH_LOCATIONSET:
5467		if (obj->user != NULL) {
5468		    xmlXPtrFreeLocationSet(obj->user);
5469		}
5470		goto free_obj;
5471#endif
5472	    default:
5473		goto free_obj;
5474	}
5475
5476	/*
5477	* Fallback to adding to the misc-objects slot.
5478	*/
5479	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5480	    XP_CACHE_ADD(cache->miscObjs, obj);
5481	} else
5482	    goto free_obj;
5483
5484obj_cached:
5485
5486#ifdef XP_DEBUG_OBJ_USAGE
5487	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5488#endif
5489
5490	if (obj->nodesetval != NULL) {
5491	    xmlNodeSetPtr tmpset = obj->nodesetval;
5492
5493	    /*
5494	    * TODO: Due to those nasty ns-nodes, we need to traverse
5495	    *  the list and free the ns-nodes.
5496	    * URGENT TODO: Check if it's actually slowing things down.
5497	    *  Maybe we shouldn't try to preserve the list.
5498	    */
5499	    if (tmpset->nodeNr > 1) {
5500		int i;
5501		xmlNodePtr node;
5502
5503		for (i = 0; i < tmpset->nodeNr; i++) {
5504		    node = tmpset->nodeTab[i];
5505		    if ((node != NULL) &&
5506			(node->type == XML_NAMESPACE_DECL))
5507		    {
5508			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5509		    }
5510		}
5511	    } else if (tmpset->nodeNr == 1) {
5512		if ((tmpset->nodeTab[0] != NULL) &&
5513		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5514		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5515	    }
5516	    tmpset->nodeNr = 0;
5517	    memset(obj, 0, sizeof(xmlXPathObject));
5518	    obj->nodesetval = tmpset;
5519	} else
5520	    memset(obj, 0, sizeof(xmlXPathObject));
5521
5522	return;
5523
5524free_obj:
5525	/*
5526	* Cache is full; free the object.
5527	*/
5528	if (obj->nodesetval != NULL)
5529	    xmlXPathFreeNodeSet(obj->nodesetval);
5530#ifdef XP_DEBUG_OBJ_USAGE
5531	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5532#endif
5533	xmlFree(obj);
5534    }
5535    return;
5536}
5537
5538
5539/************************************************************************
5540 *									*
5541 *			Type Casting Routines				*
5542 *									*
5543 ************************************************************************/
5544
5545/**
5546 * xmlXPathCastBooleanToString:
5547 * @val:  a boolean
5548 *
5549 * Converts a boolean to its string value.
5550 *
5551 * Returns a newly allocated string.
5552 */
5553xmlChar *
5554xmlXPathCastBooleanToString (int val) {
5555    xmlChar *ret;
5556    if (val)
5557	ret = xmlStrdup((const xmlChar *) "true");
5558    else
5559	ret = xmlStrdup((const xmlChar *) "false");
5560    return(ret);
5561}
5562
5563/**
5564 * xmlXPathCastNumberToString:
5565 * @val:  a number
5566 *
5567 * Converts a number to its string value.
5568 *
5569 * Returns a newly allocated string.
5570 */
5571xmlChar *
5572xmlXPathCastNumberToString (double val) {
5573    xmlChar *ret;
5574    switch (xmlXPathIsInf(val)) {
5575    case 1:
5576	ret = xmlStrdup((const xmlChar *) "Infinity");
5577	break;
5578    case -1:
5579	ret = xmlStrdup((const xmlChar *) "-Infinity");
5580	break;
5581    default:
5582	if (xmlXPathIsNaN(val)) {
5583	    ret = xmlStrdup((const xmlChar *) "NaN");
5584	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
5585	    ret = xmlStrdup((const xmlChar *) "0");
5586	} else {
5587	    /* could be improved */
5588	    char buf[100];
5589	    xmlXPathFormatNumber(val, buf, 99);
5590	    buf[99] = 0;
5591	    ret = xmlStrdup((const xmlChar *) buf);
5592	}
5593    }
5594    return(ret);
5595}
5596
5597/**
5598 * xmlXPathCastNodeToString:
5599 * @node:  a node
5600 *
5601 * Converts a node to its string value.
5602 *
5603 * Returns a newly allocated string.
5604 */
5605xmlChar *
5606xmlXPathCastNodeToString (xmlNodePtr node) {
5607xmlChar *ret;
5608    if ((ret = xmlNodeGetContent(node)) == NULL)
5609	ret = xmlStrdup((const xmlChar *) "");
5610    return(ret);
5611}
5612
5613/**
5614 * xmlXPathCastNodeSetToString:
5615 * @ns:  a node-set
5616 *
5617 * Converts a node-set to its string value.
5618 *
5619 * Returns a newly allocated string.
5620 */
5621xmlChar *
5622xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5623    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5624	return(xmlStrdup((const xmlChar *) ""));
5625
5626    if (ns->nodeNr > 1)
5627	xmlXPathNodeSetSort(ns);
5628    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5629}
5630
5631/**
5632 * xmlXPathCastToString:
5633 * @val:  an XPath object
5634 *
5635 * Converts an existing object to its string() equivalent
5636 *
5637 * Returns the allocated string value of the object, NULL in case of error.
5638 *         It's up to the caller to free the string memory with xmlFree().
5639 */
5640xmlChar *
5641xmlXPathCastToString(xmlXPathObjectPtr val) {
5642    xmlChar *ret = NULL;
5643
5644    if (val == NULL)
5645	return(xmlStrdup((const xmlChar *) ""));
5646    switch (val->type) {
5647	case XPATH_UNDEFINED:
5648#ifdef DEBUG_EXPR
5649	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5650#endif
5651	    ret = xmlStrdup((const xmlChar *) "");
5652	    break;
5653        case XPATH_NODESET:
5654        case XPATH_XSLT_TREE:
5655	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5656	    break;
5657	case XPATH_STRING:
5658	    return(xmlStrdup(val->stringval));
5659        case XPATH_BOOLEAN:
5660	    ret = xmlXPathCastBooleanToString(val->boolval);
5661	    break;
5662	case XPATH_NUMBER: {
5663	    ret = xmlXPathCastNumberToString(val->floatval);
5664	    break;
5665	}
5666	case XPATH_USERS:
5667	case XPATH_POINT:
5668	case XPATH_RANGE:
5669	case XPATH_LOCATIONSET:
5670	    TODO
5671	    ret = xmlStrdup((const xmlChar *) "");
5672	    break;
5673    }
5674    return(ret);
5675}
5676
5677/**
5678 * xmlXPathConvertString:
5679 * @val:  an XPath object
5680 *
5681 * Converts an existing object to its string() equivalent
5682 *
5683 * Returns the new object, the old one is freed (or the operation
5684 *         is done directly on @val)
5685 */
5686xmlXPathObjectPtr
5687xmlXPathConvertString(xmlXPathObjectPtr val) {
5688    xmlChar *res = NULL;
5689
5690    if (val == NULL)
5691	return(xmlXPathNewCString(""));
5692
5693    switch (val->type) {
5694    case XPATH_UNDEFINED:
5695#ifdef DEBUG_EXPR
5696	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5697#endif
5698	break;
5699    case XPATH_NODESET:
5700    case XPATH_XSLT_TREE:
5701	res = xmlXPathCastNodeSetToString(val->nodesetval);
5702	break;
5703    case XPATH_STRING:
5704	return(val);
5705    case XPATH_BOOLEAN:
5706	res = xmlXPathCastBooleanToString(val->boolval);
5707	break;
5708    case XPATH_NUMBER:
5709	res = xmlXPathCastNumberToString(val->floatval);
5710	break;
5711    case XPATH_USERS:
5712    case XPATH_POINT:
5713    case XPATH_RANGE:
5714    case XPATH_LOCATIONSET:
5715	TODO;
5716	break;
5717    }
5718    xmlXPathFreeObject(val);
5719    if (res == NULL)
5720	return(xmlXPathNewCString(""));
5721    return(xmlXPathWrapString(res));
5722}
5723
5724/**
5725 * xmlXPathCastBooleanToNumber:
5726 * @val:  a boolean
5727 *
5728 * Converts a boolean to its number value
5729 *
5730 * Returns the number value
5731 */
5732double
5733xmlXPathCastBooleanToNumber(int val) {
5734    if (val)
5735	return(1.0);
5736    return(0.0);
5737}
5738
5739/**
5740 * xmlXPathCastStringToNumber:
5741 * @val:  a string
5742 *
5743 * Converts a string to its number value
5744 *
5745 * Returns the number value
5746 */
5747double
5748xmlXPathCastStringToNumber(const xmlChar * val) {
5749    return(xmlXPathStringEvalNumber(val));
5750}
5751
5752/**
5753 * xmlXPathCastNodeToNumber:
5754 * @node:  a node
5755 *
5756 * Converts a node to its number value
5757 *
5758 * Returns the number value
5759 */
5760double
5761xmlXPathCastNodeToNumber (xmlNodePtr node) {
5762    xmlChar *strval;
5763    double ret;
5764
5765    if (node == NULL)
5766	return(xmlXPathNAN);
5767    strval = xmlXPathCastNodeToString(node);
5768    if (strval == NULL)
5769	return(xmlXPathNAN);
5770    ret = xmlXPathCastStringToNumber(strval);
5771    xmlFree(strval);
5772
5773    return(ret);
5774}
5775
5776/**
5777 * xmlXPathCastNodeSetToNumber:
5778 * @ns:  a node-set
5779 *
5780 * Converts a node-set to its number value
5781 *
5782 * Returns the number value
5783 */
5784double
5785xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5786    xmlChar *str;
5787    double ret;
5788
5789    if (ns == NULL)
5790	return(xmlXPathNAN);
5791    str = xmlXPathCastNodeSetToString(ns);
5792    ret = xmlXPathCastStringToNumber(str);
5793    xmlFree(str);
5794    return(ret);
5795}
5796
5797/**
5798 * xmlXPathCastToNumber:
5799 * @val:  an XPath object
5800 *
5801 * Converts an XPath object to its number value
5802 *
5803 * Returns the number value
5804 */
5805double
5806xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5807    double ret = 0.0;
5808
5809    if (val == NULL)
5810	return(xmlXPathNAN);
5811    switch (val->type) {
5812    case XPATH_UNDEFINED:
5813#ifdef DEGUB_EXPR
5814	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5815#endif
5816	ret = xmlXPathNAN;
5817	break;
5818    case XPATH_NODESET:
5819    case XPATH_XSLT_TREE:
5820	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5821	break;
5822    case XPATH_STRING:
5823	ret = xmlXPathCastStringToNumber(val->stringval);
5824	break;
5825    case XPATH_NUMBER:
5826	ret = val->floatval;
5827	break;
5828    case XPATH_BOOLEAN:
5829	ret = xmlXPathCastBooleanToNumber(val->boolval);
5830	break;
5831    case XPATH_USERS:
5832    case XPATH_POINT:
5833    case XPATH_RANGE:
5834    case XPATH_LOCATIONSET:
5835	TODO;
5836	ret = xmlXPathNAN;
5837	break;
5838    }
5839    return(ret);
5840}
5841
5842/**
5843 * xmlXPathConvertNumber:
5844 * @val:  an XPath object
5845 *
5846 * Converts an existing object to its number() equivalent
5847 *
5848 * Returns the new object, the old one is freed (or the operation
5849 *         is done directly on @val)
5850 */
5851xmlXPathObjectPtr
5852xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5853    xmlXPathObjectPtr ret;
5854
5855    if (val == NULL)
5856	return(xmlXPathNewFloat(0.0));
5857    if (val->type == XPATH_NUMBER)
5858	return(val);
5859    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5860    xmlXPathFreeObject(val);
5861    return(ret);
5862}
5863
5864/**
5865 * xmlXPathCastNumberToBoolean:
5866 * @val:  a number
5867 *
5868 * Converts a number to its boolean value
5869 *
5870 * Returns the boolean value
5871 */
5872int
5873xmlXPathCastNumberToBoolean (double val) {
5874     if (xmlXPathIsNaN(val) || (val == 0.0))
5875	 return(0);
5876     return(1);
5877}
5878
5879/**
5880 * xmlXPathCastStringToBoolean:
5881 * @val:  a string
5882 *
5883 * Converts a string to its boolean value
5884 *
5885 * Returns the boolean value
5886 */
5887int
5888xmlXPathCastStringToBoolean (const xmlChar *val) {
5889    if ((val == NULL) || (xmlStrlen(val) == 0))
5890	return(0);
5891    return(1);
5892}
5893
5894/**
5895 * xmlXPathCastNodeSetToBoolean:
5896 * @ns:  a node-set
5897 *
5898 * Converts a node-set to its boolean value
5899 *
5900 * Returns the boolean value
5901 */
5902int
5903xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5904    if ((ns == NULL) || (ns->nodeNr == 0))
5905	return(0);
5906    return(1);
5907}
5908
5909/**
5910 * xmlXPathCastToBoolean:
5911 * @val:  an XPath object
5912 *
5913 * Converts an XPath object to its boolean value
5914 *
5915 * Returns the boolean value
5916 */
5917int
5918xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5919    int ret = 0;
5920
5921    if (val == NULL)
5922	return(0);
5923    switch (val->type) {
5924    case XPATH_UNDEFINED:
5925#ifdef DEBUG_EXPR
5926	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5927#endif
5928	ret = 0;
5929	break;
5930    case XPATH_NODESET:
5931    case XPATH_XSLT_TREE:
5932	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5933	break;
5934    case XPATH_STRING:
5935	ret = xmlXPathCastStringToBoolean(val->stringval);
5936	break;
5937    case XPATH_NUMBER:
5938	ret = xmlXPathCastNumberToBoolean(val->floatval);
5939	break;
5940    case XPATH_BOOLEAN:
5941	ret = val->boolval;
5942	break;
5943    case XPATH_USERS:
5944    case XPATH_POINT:
5945    case XPATH_RANGE:
5946    case XPATH_LOCATIONSET:
5947	TODO;
5948	ret = 0;
5949	break;
5950    }
5951    return(ret);
5952}
5953
5954
5955/**
5956 * xmlXPathConvertBoolean:
5957 * @val:  an XPath object
5958 *
5959 * Converts an existing object to its boolean() equivalent
5960 *
5961 * Returns the new object, the old one is freed (or the operation
5962 *         is done directly on @val)
5963 */
5964xmlXPathObjectPtr
5965xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5966    xmlXPathObjectPtr ret;
5967
5968    if (val == NULL)
5969	return(xmlXPathNewBoolean(0));
5970    if (val->type == XPATH_BOOLEAN)
5971	return(val);
5972    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5973    xmlXPathFreeObject(val);
5974    return(ret);
5975}
5976
5977/************************************************************************
5978 *									*
5979 *		Routines to handle XPath contexts			*
5980 *									*
5981 ************************************************************************/
5982
5983/**
5984 * xmlXPathNewContext:
5985 * @doc:  the XML document
5986 *
5987 * Create a new xmlXPathContext
5988 *
5989 * Returns the xmlXPathContext just allocated. The caller will need to free it.
5990 */
5991xmlXPathContextPtr
5992xmlXPathNewContext(xmlDocPtr doc) {
5993    xmlXPathContextPtr ret;
5994
5995    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5996    if (ret == NULL) {
5997        xmlXPathErrMemory(NULL, "creating context\n");
5998	return(NULL);
5999    }
6000    memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6001    ret->doc = doc;
6002    ret->node = NULL;
6003
6004    ret->varHash = NULL;
6005
6006    ret->nb_types = 0;
6007    ret->max_types = 0;
6008    ret->types = NULL;
6009
6010    ret->funcHash = xmlHashCreate(0);
6011
6012    ret->nb_axis = 0;
6013    ret->max_axis = 0;
6014    ret->axis = NULL;
6015
6016    ret->nsHash = NULL;
6017    ret->user = NULL;
6018
6019    ret->contextSize = -1;
6020    ret->proximityPosition = -1;
6021
6022#ifdef XP_DEFAULT_CACHE_ON
6023    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6024	xmlXPathFreeContext(ret);
6025	return(NULL);
6026    }
6027#endif
6028
6029    xmlXPathRegisterAllFunctions(ret);
6030
6031    return(ret);
6032}
6033
6034/**
6035 * xmlXPathFreeContext:
6036 * @ctxt:  the context to free
6037 *
6038 * Free up an xmlXPathContext
6039 */
6040void
6041xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6042    if (ctxt == NULL) return;
6043
6044    if (ctxt->cache != NULL)
6045	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6046    xmlXPathRegisteredNsCleanup(ctxt);
6047    xmlXPathRegisteredFuncsCleanup(ctxt);
6048    xmlXPathRegisteredVariablesCleanup(ctxt);
6049    xmlResetError(&ctxt->lastError);
6050    xmlFree(ctxt);
6051}
6052
6053/************************************************************************
6054 *									*
6055 *		Routines to handle XPath parser contexts		*
6056 *									*
6057 ************************************************************************/
6058
6059#define CHECK_CTXT(ctxt)						\
6060    if (ctxt == NULL) {						\
6061	__xmlRaiseError(NULL, NULL, NULL,				\
6062		NULL, NULL, XML_FROM_XPATH,				\
6063		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6064		__FILE__, __LINE__,					\
6065		NULL, NULL, NULL, 0, 0,					\
6066		"NULL context pointer\n");				\
6067	return(NULL);							\
6068    }									\
6069
6070#define CHECK_CTXT_NEG(ctxt)						\
6071    if (ctxt == NULL) {						\
6072	__xmlRaiseError(NULL, NULL, NULL,				\
6073		NULL, NULL, XML_FROM_XPATH,				\
6074		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6075		__FILE__, __LINE__,					\
6076		NULL, NULL, NULL, 0, 0,					\
6077		"NULL context pointer\n");				\
6078	return(-1);							\
6079    }									\
6080
6081
6082#define CHECK_CONTEXT(ctxt)						\
6083    if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6084        (ctxt->doc->children == NULL)) {				\
6085	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6086	return(NULL);							\
6087    }
6088
6089
6090/**
6091 * xmlXPathNewParserContext:
6092 * @str:  the XPath expression
6093 * @ctxt:  the XPath context
6094 *
6095 * Create a new xmlXPathParserContext
6096 *
6097 * Returns the xmlXPathParserContext just allocated.
6098 */
6099xmlXPathParserContextPtr
6100xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6101    xmlXPathParserContextPtr ret;
6102
6103    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6104    if (ret == NULL) {
6105        xmlXPathErrMemory(ctxt, "creating parser context\n");
6106	return(NULL);
6107    }
6108    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6109    ret->cur = ret->base = str;
6110    ret->context = ctxt;
6111
6112    ret->comp = xmlXPathNewCompExpr();
6113    if (ret->comp == NULL) {
6114	xmlFree(ret->valueTab);
6115	xmlFree(ret);
6116	return(NULL);
6117    }
6118    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6119        ret->comp->dict = ctxt->dict;
6120	xmlDictReference(ret->comp->dict);
6121    }
6122
6123    return(ret);
6124}
6125
6126/**
6127 * xmlXPathCompParserContext:
6128 * @comp:  the XPath compiled expression
6129 * @ctxt:  the XPath context
6130 *
6131 * Create a new xmlXPathParserContext when processing a compiled expression
6132 *
6133 * Returns the xmlXPathParserContext just allocated.
6134 */
6135static xmlXPathParserContextPtr
6136xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6137    xmlXPathParserContextPtr ret;
6138
6139    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6140    if (ret == NULL) {
6141        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6142	return(NULL);
6143    }
6144    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6145
6146    /* Allocate the value stack */
6147    ret->valueTab = (xmlXPathObjectPtr *)
6148                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6149    if (ret->valueTab == NULL) {
6150	xmlFree(ret);
6151	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6152	return(NULL);
6153    }
6154    ret->valueNr = 0;
6155    ret->valueMax = 10;
6156    ret->value = NULL;
6157
6158    ret->context = ctxt;
6159    ret->comp = comp;
6160
6161    return(ret);
6162}
6163
6164/**
6165 * xmlXPathFreeParserContext:
6166 * @ctxt:  the context to free
6167 *
6168 * Free up an xmlXPathParserContext
6169 */
6170void
6171xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6172    if (ctxt->valueTab != NULL) {
6173        xmlFree(ctxt->valueTab);
6174    }
6175    if (ctxt->comp != NULL) {
6176#ifdef XPATH_STREAMING
6177	if (ctxt->comp->stream != NULL) {
6178	    xmlFreePatternList(ctxt->comp->stream);
6179	    ctxt->comp->stream = NULL;
6180	}
6181#endif
6182	xmlXPathFreeCompExpr(ctxt->comp);
6183    }
6184    xmlFree(ctxt);
6185}
6186
6187/************************************************************************
6188 *									*
6189 *		The implicit core function library			*
6190 *									*
6191 ************************************************************************/
6192
6193/**
6194 * xmlXPathNodeValHash:
6195 * @node:  a node pointer
6196 *
6197 * Function computing the beginning of the string value of the node,
6198 * used to speed up comparisons
6199 *
6200 * Returns an int usable as a hash
6201 */
6202static unsigned int
6203xmlXPathNodeValHash(xmlNodePtr node) {
6204    int len = 2;
6205    const xmlChar * string = NULL;
6206    xmlNodePtr tmp = NULL;
6207    unsigned int ret = 0;
6208
6209    if (node == NULL)
6210	return(0);
6211
6212    if (node->type == XML_DOCUMENT_NODE) {
6213	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6214	if (tmp == NULL)
6215	    node = node->children;
6216	else
6217	    node = tmp;
6218
6219	if (node == NULL)
6220	    return(0);
6221    }
6222
6223    switch (node->type) {
6224	case XML_COMMENT_NODE:
6225	case XML_PI_NODE:
6226	case XML_CDATA_SECTION_NODE:
6227	case XML_TEXT_NODE:
6228	    string = node->content;
6229	    if (string == NULL)
6230		return(0);
6231	    if (string[0] == 0)
6232		return(0);
6233	    return(((unsigned int) string[0]) +
6234		   (((unsigned int) string[1]) << 8));
6235	case XML_NAMESPACE_DECL:
6236	    string = ((xmlNsPtr)node)->href;
6237	    if (string == NULL)
6238		return(0);
6239	    if (string[0] == 0)
6240		return(0);
6241	    return(((unsigned int) string[0]) +
6242		   (((unsigned int) string[1]) << 8));
6243	case XML_ATTRIBUTE_NODE:
6244	    tmp = ((xmlAttrPtr) node)->children;
6245	    break;
6246	case XML_ELEMENT_NODE:
6247	    tmp = node->children;
6248	    break;
6249	default:
6250	    return(0);
6251    }
6252    while (tmp != NULL) {
6253	switch (tmp->type) {
6254	    case XML_COMMENT_NODE:
6255	    case XML_PI_NODE:
6256	    case XML_CDATA_SECTION_NODE:
6257	    case XML_TEXT_NODE:
6258		string = tmp->content;
6259		break;
6260	    case XML_NAMESPACE_DECL:
6261		string = ((xmlNsPtr)tmp)->href;
6262		break;
6263	    default:
6264		break;
6265	}
6266	if ((string != NULL) && (string[0] != 0)) {
6267	    if (len == 1) {
6268		return(ret + (((unsigned int) string[0]) << 8));
6269	    }
6270	    if (string[1] == 0) {
6271		len = 1;
6272		ret = (unsigned int) string[0];
6273	    } else {
6274		return(((unsigned int) string[0]) +
6275		       (((unsigned int) string[1]) << 8));
6276	    }
6277	}
6278	/*
6279	 * Skip to next node
6280	 */
6281	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6282	    if (tmp->children->type != XML_ENTITY_DECL) {
6283		tmp = tmp->children;
6284		continue;
6285	    }
6286	}
6287	if (tmp == node)
6288	    break;
6289
6290	if (tmp->next != NULL) {
6291	    tmp = tmp->next;
6292	    continue;
6293	}
6294
6295	do {
6296	    tmp = tmp->parent;
6297	    if (tmp == NULL)
6298		break;
6299	    if (tmp == node) {
6300		tmp = NULL;
6301		break;
6302	    }
6303	    if (tmp->next != NULL) {
6304		tmp = tmp->next;
6305		break;
6306	    }
6307	} while (tmp != NULL);
6308    }
6309    return(ret);
6310}
6311
6312/**
6313 * xmlXPathStringHash:
6314 * @string:  a string
6315 *
6316 * Function computing the beginning of the string value of the node,
6317 * used to speed up comparisons
6318 *
6319 * Returns an int usable as a hash
6320 */
6321static unsigned int
6322xmlXPathStringHash(const xmlChar * string) {
6323    if (string == NULL)
6324	return((unsigned int) 0);
6325    if (string[0] == 0)
6326	return(0);
6327    return(((unsigned int) string[0]) +
6328	   (((unsigned int) string[1]) << 8));
6329}
6330
6331/**
6332 * xmlXPathCompareNodeSetFloat:
6333 * @ctxt:  the XPath Parser context
6334 * @inf:  less than (1) or greater than (0)
6335 * @strict:  is the comparison strict
6336 * @arg:  the node set
6337 * @f:  the value
6338 *
6339 * Implement the compare operation between a nodeset and a number
6340 *     @ns < @val    (1, 1, ...
6341 *     @ns <= @val   (1, 0, ...
6342 *     @ns > @val    (0, 1, ...
6343 *     @ns >= @val   (0, 0, ...
6344 *
6345 * If one object to be compared is a node-set and the other is a number,
6346 * then the comparison will be true if and only if there is a node in the
6347 * node-set such that the result of performing the comparison on the number
6348 * to be compared and on the result of converting the string-value of that
6349 * node to a number using the number function is true.
6350 *
6351 * Returns 0 or 1 depending on the results of the test.
6352 */
6353static int
6354xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6355	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6356    int i, ret = 0;
6357    xmlNodeSetPtr ns;
6358    xmlChar *str2;
6359
6360    if ((f == NULL) || (arg == NULL) ||
6361	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6362	xmlXPathReleaseObject(ctxt->context, arg);
6363	xmlXPathReleaseObject(ctxt->context, f);
6364        return(0);
6365    }
6366    ns = arg->nodesetval;
6367    if (ns != NULL) {
6368	for (i = 0;i < ns->nodeNr;i++) {
6369	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6370	     if (str2 != NULL) {
6371		 valuePush(ctxt,
6372			   xmlXPathCacheNewString(ctxt->context, str2));
6373		 xmlFree(str2);
6374		 xmlXPathNumberFunction(ctxt, 1);
6375		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6376		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6377		 if (ret)
6378		     break;
6379	     }
6380	}
6381    }
6382    xmlXPathReleaseObject(ctxt->context, arg);
6383    xmlXPathReleaseObject(ctxt->context, f);
6384    return(ret);
6385}
6386
6387/**
6388 * xmlXPathCompareNodeSetString:
6389 * @ctxt:  the XPath Parser context
6390 * @inf:  less than (1) or greater than (0)
6391 * @strict:  is the comparison strict
6392 * @arg:  the node set
6393 * @s:  the value
6394 *
6395 * Implement the compare operation between a nodeset and a string
6396 *     @ns < @val    (1, 1, ...
6397 *     @ns <= @val   (1, 0, ...
6398 *     @ns > @val    (0, 1, ...
6399 *     @ns >= @val   (0, 0, ...
6400 *
6401 * If one object to be compared is a node-set and the other is a string,
6402 * then the comparison will be true if and only if there is a node in
6403 * the node-set such that the result of performing the comparison on the
6404 * string-value of the node and the other string is true.
6405 *
6406 * Returns 0 or 1 depending on the results of the test.
6407 */
6408static int
6409xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6410	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6411    int i, ret = 0;
6412    xmlNodeSetPtr ns;
6413    xmlChar *str2;
6414
6415    if ((s == NULL) || (arg == NULL) ||
6416	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6417	xmlXPathReleaseObject(ctxt->context, arg);
6418	xmlXPathReleaseObject(ctxt->context, s);
6419        return(0);
6420    }
6421    ns = arg->nodesetval;
6422    if (ns != NULL) {
6423	for (i = 0;i < ns->nodeNr;i++) {
6424	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6425	     if (str2 != NULL) {
6426		 valuePush(ctxt,
6427			   xmlXPathCacheNewString(ctxt->context, str2));
6428		 xmlFree(str2);
6429		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6430		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6431		 if (ret)
6432		     break;
6433	     }
6434	}
6435    }
6436    xmlXPathReleaseObject(ctxt->context, arg);
6437    xmlXPathReleaseObject(ctxt->context, s);
6438    return(ret);
6439}
6440
6441/**
6442 * xmlXPathCompareNodeSets:
6443 * @inf:  less than (1) or greater than (0)
6444 * @strict:  is the comparison strict
6445 * @arg1:  the first node set object
6446 * @arg2:  the second node set object
6447 *
6448 * Implement the compare operation on nodesets:
6449 *
6450 * If both objects to be compared are node-sets, then the comparison
6451 * will be true if and only if there is a node in the first node-set
6452 * and a node in the second node-set such that the result of performing
6453 * the comparison on the string-values of the two nodes is true.
6454 * ....
6455 * When neither object to be compared is a node-set and the operator
6456 * is <=, <, >= or >, then the objects are compared by converting both
6457 * objects to numbers and comparing the numbers according to IEEE 754.
6458 * ....
6459 * The number function converts its argument to a number as follows:
6460 *  - a string that consists of optional whitespace followed by an
6461 *    optional minus sign followed by a Number followed by whitespace
6462 *    is converted to the IEEE 754 number that is nearest (according
6463 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6464 *    represented by the string; any other string is converted to NaN
6465 *
6466 * Conclusion all nodes need to be converted first to their string value
6467 * and then the comparison must be done when possible
6468 */
6469static int
6470xmlXPathCompareNodeSets(int inf, int strict,
6471	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6472    int i, j, init = 0;
6473    double val1;
6474    double *values2;
6475    int ret = 0;
6476    xmlNodeSetPtr ns1;
6477    xmlNodeSetPtr ns2;
6478
6479    if ((arg1 == NULL) ||
6480	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6481	xmlXPathFreeObject(arg2);
6482        return(0);
6483    }
6484    if ((arg2 == NULL) ||
6485	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6486	xmlXPathFreeObject(arg1);
6487	xmlXPathFreeObject(arg2);
6488        return(0);
6489    }
6490
6491    ns1 = arg1->nodesetval;
6492    ns2 = arg2->nodesetval;
6493
6494    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6495	xmlXPathFreeObject(arg1);
6496	xmlXPathFreeObject(arg2);
6497	return(0);
6498    }
6499    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6500	xmlXPathFreeObject(arg1);
6501	xmlXPathFreeObject(arg2);
6502	return(0);
6503    }
6504
6505    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6506    if (values2 == NULL) {
6507        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6508	xmlXPathFreeObject(arg1);
6509	xmlXPathFreeObject(arg2);
6510	return(0);
6511    }
6512    for (i = 0;i < ns1->nodeNr;i++) {
6513	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6514	if (xmlXPathIsNaN(val1))
6515	    continue;
6516	for (j = 0;j < ns2->nodeNr;j++) {
6517	    if (init == 0) {
6518		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6519	    }
6520	    if (xmlXPathIsNaN(values2[j]))
6521		continue;
6522	    if (inf && strict)
6523		ret = (val1 < values2[j]);
6524	    else if (inf && !strict)
6525		ret = (val1 <= values2[j]);
6526	    else if (!inf && strict)
6527		ret = (val1 > values2[j]);
6528	    else if (!inf && !strict)
6529		ret = (val1 >= values2[j]);
6530	    if (ret)
6531		break;
6532	}
6533	if (ret)
6534	    break;
6535	init = 1;
6536    }
6537    xmlFree(values2);
6538    xmlXPathFreeObject(arg1);
6539    xmlXPathFreeObject(arg2);
6540    return(ret);
6541}
6542
6543/**
6544 * xmlXPathCompareNodeSetValue:
6545 * @ctxt:  the XPath Parser context
6546 * @inf:  less than (1) or greater than (0)
6547 * @strict:  is the comparison strict
6548 * @arg:  the node set
6549 * @val:  the value
6550 *
6551 * Implement the compare operation between a nodeset and a value
6552 *     @ns < @val    (1, 1, ...
6553 *     @ns <= @val   (1, 0, ...
6554 *     @ns > @val    (0, 1, ...
6555 *     @ns >= @val   (0, 0, ...
6556 *
6557 * If one object to be compared is a node-set and the other is a boolean,
6558 * then the comparison will be true if and only if the result of performing
6559 * the comparison on the boolean and on the result of converting
6560 * the node-set to a boolean using the boolean function is true.
6561 *
6562 * Returns 0 or 1 depending on the results of the test.
6563 */
6564static int
6565xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6566	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6567    if ((val == NULL) || (arg == NULL) ||
6568	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6569        return(0);
6570
6571    switch(val->type) {
6572        case XPATH_NUMBER:
6573	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6574        case XPATH_NODESET:
6575        case XPATH_XSLT_TREE:
6576	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6577        case XPATH_STRING:
6578	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6579        case XPATH_BOOLEAN:
6580	    valuePush(ctxt, arg);
6581	    xmlXPathBooleanFunction(ctxt, 1);
6582	    valuePush(ctxt, val);
6583	    return(xmlXPathCompareValues(ctxt, inf, strict));
6584	default:
6585	    TODO
6586    }
6587    return(0);
6588}
6589
6590/**
6591 * xmlXPathEqualNodeSetString:
6592 * @arg:  the nodeset object argument
6593 * @str:  the string to compare to.
6594 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6595 *
6596 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6597 * If one object to be compared is a node-set and the other is a string,
6598 * then the comparison will be true if and only if there is a node in
6599 * the node-set such that the result of performing the comparison on the
6600 * string-value of the node and the other string is true.
6601 *
6602 * Returns 0 or 1 depending on the results of the test.
6603 */
6604static int
6605xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6606{
6607    int i;
6608    xmlNodeSetPtr ns;
6609    xmlChar *str2;
6610    unsigned int hash;
6611
6612    if ((str == NULL) || (arg == NULL) ||
6613        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6614        return (0);
6615    ns = arg->nodesetval;
6616    /*
6617     * A NULL nodeset compared with a string is always false
6618     * (since there is no node equal, and no node not equal)
6619     */
6620    if ((ns == NULL) || (ns->nodeNr <= 0) )
6621        return (0);
6622    hash = xmlXPathStringHash(str);
6623    for (i = 0; i < ns->nodeNr; i++) {
6624        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6625            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6626            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6627                xmlFree(str2);
6628		if (neq)
6629		    continue;
6630                return (1);
6631	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6632		if (neq)
6633		    continue;
6634                return (1);
6635            } else if (neq) {
6636		if (str2 != NULL)
6637		    xmlFree(str2);
6638		return (1);
6639	    }
6640            if (str2 != NULL)
6641                xmlFree(str2);
6642        } else if (neq)
6643	    return (1);
6644    }
6645    return (0);
6646}
6647
6648/**
6649 * xmlXPathEqualNodeSetFloat:
6650 * @arg:  the nodeset object argument
6651 * @f:  the float to compare to
6652 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6653 *
6654 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6655 * If one object to be compared is a node-set and the other is a number,
6656 * then the comparison will be true if and only if there is a node in
6657 * the node-set such that the result of performing the comparison on the
6658 * number to be compared and on the result of converting the string-value
6659 * of that node to a number using the number function is true.
6660 *
6661 * Returns 0 or 1 depending on the results of the test.
6662 */
6663static int
6664xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6665    xmlXPathObjectPtr arg, double f, int neq) {
6666  int i, ret=0;
6667  xmlNodeSetPtr ns;
6668  xmlChar *str2;
6669  xmlXPathObjectPtr val;
6670  double v;
6671
6672    if ((arg == NULL) ||
6673	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6674        return(0);
6675
6676    ns = arg->nodesetval;
6677    if (ns != NULL) {
6678	for (i=0;i<ns->nodeNr;i++) {
6679	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6680	    if (str2 != NULL) {
6681		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6682		xmlFree(str2);
6683		xmlXPathNumberFunction(ctxt, 1);
6684		val = valuePop(ctxt);
6685		v = val->floatval;
6686		xmlXPathReleaseObject(ctxt->context, val);
6687		if (!xmlXPathIsNaN(v)) {
6688		    if ((!neq) && (v==f)) {
6689			ret = 1;
6690			break;
6691		    } else if ((neq) && (v!=f)) {
6692			ret = 1;
6693			break;
6694		    }
6695		} else {	/* NaN is unequal to any value */
6696		    if (neq)
6697			ret = 1;
6698		}
6699	    }
6700	}
6701    }
6702
6703    return(ret);
6704}
6705
6706
6707/**
6708 * xmlXPathEqualNodeSets:
6709 * @arg1:  first nodeset object argument
6710 * @arg2:  second nodeset object argument
6711 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6712 *
6713 * Implement the equal / not equal operation on XPath nodesets:
6714 * @arg1 == @arg2  or  @arg1 != @arg2
6715 * If both objects to be compared are node-sets, then the comparison
6716 * will be true if and only if there is a node in the first node-set and
6717 * a node in the second node-set such that the result of performing the
6718 * comparison on the string-values of the two nodes is true.
6719 *
6720 * (needless to say, this is a costly operation)
6721 *
6722 * Returns 0 or 1 depending on the results of the test.
6723 */
6724static int
6725xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6726    int i, j;
6727    unsigned int *hashs1;
6728    unsigned int *hashs2;
6729    xmlChar **values1;
6730    xmlChar **values2;
6731    int ret = 0;
6732    xmlNodeSetPtr ns1;
6733    xmlNodeSetPtr ns2;
6734
6735    if ((arg1 == NULL) ||
6736	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6737        return(0);
6738    if ((arg2 == NULL) ||
6739	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6740        return(0);
6741
6742    ns1 = arg1->nodesetval;
6743    ns2 = arg2->nodesetval;
6744
6745    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6746	return(0);
6747    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6748	return(0);
6749
6750    /*
6751     * for equal, check if there is a node pertaining to both sets
6752     */
6753    if (neq == 0)
6754	for (i = 0;i < ns1->nodeNr;i++)
6755	    for (j = 0;j < ns2->nodeNr;j++)
6756		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6757		    return(1);
6758
6759    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6760    if (values1 == NULL) {
6761        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6762	return(0);
6763    }
6764    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6765    if (hashs1 == NULL) {
6766        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6767	xmlFree(values1);
6768	return(0);
6769    }
6770    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6771    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6772    if (values2 == NULL) {
6773        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6774	xmlFree(hashs1);
6775	xmlFree(values1);
6776	return(0);
6777    }
6778    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6779    if (hashs2 == NULL) {
6780        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6781	xmlFree(hashs1);
6782	xmlFree(values1);
6783	xmlFree(values2);
6784	return(0);
6785    }
6786    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6787    for (i = 0;i < ns1->nodeNr;i++) {
6788	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6789	for (j = 0;j < ns2->nodeNr;j++) {
6790	    if (i == 0)
6791		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6792	    if (hashs1[i] != hashs2[j]) {
6793		if (neq) {
6794		    ret = 1;
6795		    break;
6796		}
6797	    }
6798	    else {
6799		if (values1[i] == NULL)
6800		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6801		if (values2[j] == NULL)
6802		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6803		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6804		if (ret)
6805		    break;
6806	    }
6807	}
6808	if (ret)
6809	    break;
6810    }
6811    for (i = 0;i < ns1->nodeNr;i++)
6812	if (values1[i] != NULL)
6813	    xmlFree(values1[i]);
6814    for (j = 0;j < ns2->nodeNr;j++)
6815	if (values2[j] != NULL)
6816	    xmlFree(values2[j]);
6817    xmlFree(values1);
6818    xmlFree(values2);
6819    xmlFree(hashs1);
6820    xmlFree(hashs2);
6821    return(ret);
6822}
6823
6824static int
6825xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6826  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6827    int ret = 0;
6828    /*
6829     *At this point we are assured neither arg1 nor arg2
6830     *is a nodeset, so we can just pick the appropriate routine.
6831     */
6832    switch (arg1->type) {
6833        case XPATH_UNDEFINED:
6834#ifdef DEBUG_EXPR
6835	    xmlGenericError(xmlGenericErrorContext,
6836		    "Equal: undefined\n");
6837#endif
6838	    break;
6839        case XPATH_BOOLEAN:
6840	    switch (arg2->type) {
6841	        case XPATH_UNDEFINED:
6842#ifdef DEBUG_EXPR
6843		    xmlGenericError(xmlGenericErrorContext,
6844			    "Equal: undefined\n");
6845#endif
6846		    break;
6847		case XPATH_BOOLEAN:
6848#ifdef DEBUG_EXPR
6849		    xmlGenericError(xmlGenericErrorContext,
6850			    "Equal: %d boolean %d \n",
6851			    arg1->boolval, arg2->boolval);
6852#endif
6853		    ret = (arg1->boolval == arg2->boolval);
6854		    break;
6855		case XPATH_NUMBER:
6856		    ret = (arg1->boolval ==
6857			   xmlXPathCastNumberToBoolean(arg2->floatval));
6858		    break;
6859		case XPATH_STRING:
6860		    if ((arg2->stringval == NULL) ||
6861			(arg2->stringval[0] == 0)) ret = 0;
6862		    else
6863			ret = 1;
6864		    ret = (arg1->boolval == ret);
6865		    break;
6866		case XPATH_USERS:
6867		case XPATH_POINT:
6868		case XPATH_RANGE:
6869		case XPATH_LOCATIONSET:
6870		    TODO
6871		    break;
6872		case XPATH_NODESET:
6873		case XPATH_XSLT_TREE:
6874		    break;
6875	    }
6876	    break;
6877        case XPATH_NUMBER:
6878	    switch (arg2->type) {
6879	        case XPATH_UNDEFINED:
6880#ifdef DEBUG_EXPR
6881		    xmlGenericError(xmlGenericErrorContext,
6882			    "Equal: undefined\n");
6883#endif
6884		    break;
6885		case XPATH_BOOLEAN:
6886		    ret = (arg2->boolval==
6887			   xmlXPathCastNumberToBoolean(arg1->floatval));
6888		    break;
6889		case XPATH_STRING:
6890		    valuePush(ctxt, arg2);
6891		    xmlXPathNumberFunction(ctxt, 1);
6892		    arg2 = valuePop(ctxt);
6893		    /* no break on purpose */
6894		case XPATH_NUMBER:
6895		    /* Hand check NaN and Infinity equalities */
6896		    if (xmlXPathIsNaN(arg1->floatval) ||
6897			    xmlXPathIsNaN(arg2->floatval)) {
6898		        ret = 0;
6899		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6900		        if (xmlXPathIsInf(arg2->floatval) == 1)
6901			    ret = 1;
6902			else
6903			    ret = 0;
6904		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6905			if (xmlXPathIsInf(arg2->floatval) == -1)
6906			    ret = 1;
6907			else
6908			    ret = 0;
6909		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6910			if (xmlXPathIsInf(arg1->floatval) == 1)
6911			    ret = 1;
6912			else
6913			    ret = 0;
6914		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6915			if (xmlXPathIsInf(arg1->floatval) == -1)
6916			    ret = 1;
6917			else
6918			    ret = 0;
6919		    } else {
6920		        ret = (arg1->floatval == arg2->floatval);
6921		    }
6922		    break;
6923		case XPATH_USERS:
6924		case XPATH_POINT:
6925		case XPATH_RANGE:
6926		case XPATH_LOCATIONSET:
6927		    TODO
6928		    break;
6929		case XPATH_NODESET:
6930		case XPATH_XSLT_TREE:
6931		    break;
6932	    }
6933	    break;
6934        case XPATH_STRING:
6935	    switch (arg2->type) {
6936	        case XPATH_UNDEFINED:
6937#ifdef DEBUG_EXPR
6938		    xmlGenericError(xmlGenericErrorContext,
6939			    "Equal: undefined\n");
6940#endif
6941		    break;
6942		case XPATH_BOOLEAN:
6943		    if ((arg1->stringval == NULL) ||
6944			(arg1->stringval[0] == 0)) ret = 0;
6945		    else
6946			ret = 1;
6947		    ret = (arg2->boolval == ret);
6948		    break;
6949		case XPATH_STRING:
6950		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6951		    break;
6952		case XPATH_NUMBER:
6953		    valuePush(ctxt, arg1);
6954		    xmlXPathNumberFunction(ctxt, 1);
6955		    arg1 = valuePop(ctxt);
6956		    /* Hand check NaN and Infinity equalities */
6957		    if (xmlXPathIsNaN(arg1->floatval) ||
6958			    xmlXPathIsNaN(arg2->floatval)) {
6959		        ret = 0;
6960		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6961			if (xmlXPathIsInf(arg2->floatval) == 1)
6962			    ret = 1;
6963			else
6964			    ret = 0;
6965		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6966			if (xmlXPathIsInf(arg2->floatval) == -1)
6967			    ret = 1;
6968			else
6969			    ret = 0;
6970		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6971			if (xmlXPathIsInf(arg1->floatval) == 1)
6972			    ret = 1;
6973			else
6974			    ret = 0;
6975		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6976			if (xmlXPathIsInf(arg1->floatval) == -1)
6977			    ret = 1;
6978			else
6979			    ret = 0;
6980		    } else {
6981		        ret = (arg1->floatval == arg2->floatval);
6982		    }
6983		    break;
6984		case XPATH_USERS:
6985		case XPATH_POINT:
6986		case XPATH_RANGE:
6987		case XPATH_LOCATIONSET:
6988		    TODO
6989		    break;
6990		case XPATH_NODESET:
6991		case XPATH_XSLT_TREE:
6992		    break;
6993	    }
6994	    break;
6995        case XPATH_USERS:
6996	case XPATH_POINT:
6997	case XPATH_RANGE:
6998	case XPATH_LOCATIONSET:
6999	    TODO
7000	    break;
7001	case XPATH_NODESET:
7002	case XPATH_XSLT_TREE:
7003	    break;
7004    }
7005    xmlXPathReleaseObject(ctxt->context, arg1);
7006    xmlXPathReleaseObject(ctxt->context, arg2);
7007    return(ret);
7008}
7009
7010/**
7011 * xmlXPathEqualValues:
7012 * @ctxt:  the XPath Parser context
7013 *
7014 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7015 *
7016 * Returns 0 or 1 depending on the results of the test.
7017 */
7018int
7019xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7020    xmlXPathObjectPtr arg1, arg2, argtmp;
7021    int ret = 0;
7022
7023    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7024    arg2 = valuePop(ctxt);
7025    arg1 = valuePop(ctxt);
7026    if ((arg1 == NULL) || (arg2 == NULL)) {
7027	if (arg1 != NULL)
7028	    xmlXPathReleaseObject(ctxt->context, arg1);
7029	else
7030	    xmlXPathReleaseObject(ctxt->context, arg2);
7031	XP_ERROR0(XPATH_INVALID_OPERAND);
7032    }
7033
7034    if (arg1 == arg2) {
7035#ifdef DEBUG_EXPR
7036        xmlGenericError(xmlGenericErrorContext,
7037		"Equal: by pointer\n");
7038#endif
7039	xmlXPathFreeObject(arg1);
7040        return(1);
7041    }
7042
7043    /*
7044     *If either argument is a nodeset, it's a 'special case'
7045     */
7046    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7047      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7048	/*
7049	 *Hack it to assure arg1 is the nodeset
7050	 */
7051	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7052		argtmp = arg2;
7053		arg2 = arg1;
7054		arg1 = argtmp;
7055	}
7056	switch (arg2->type) {
7057	    case XPATH_UNDEFINED:
7058#ifdef DEBUG_EXPR
7059		xmlGenericError(xmlGenericErrorContext,
7060			"Equal: undefined\n");
7061#endif
7062		break;
7063	    case XPATH_NODESET:
7064	    case XPATH_XSLT_TREE:
7065		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7066		break;
7067	    case XPATH_BOOLEAN:
7068		if ((arg1->nodesetval == NULL) ||
7069		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7070		else
7071		    ret = 1;
7072		ret = (ret == arg2->boolval);
7073		break;
7074	    case XPATH_NUMBER:
7075		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7076		break;
7077	    case XPATH_STRING:
7078		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7079		break;
7080	    case XPATH_USERS:
7081	    case XPATH_POINT:
7082	    case XPATH_RANGE:
7083	    case XPATH_LOCATIONSET:
7084		TODO
7085		break;
7086	}
7087	xmlXPathReleaseObject(ctxt->context, arg1);
7088	xmlXPathReleaseObject(ctxt->context, arg2);
7089	return(ret);
7090    }
7091
7092    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7093}
7094
7095/**
7096 * xmlXPathNotEqualValues:
7097 * @ctxt:  the XPath Parser context
7098 *
7099 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7100 *
7101 * Returns 0 or 1 depending on the results of the test.
7102 */
7103int
7104xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7105    xmlXPathObjectPtr arg1, arg2, argtmp;
7106    int ret = 0;
7107
7108    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7109    arg2 = valuePop(ctxt);
7110    arg1 = valuePop(ctxt);
7111    if ((arg1 == NULL) || (arg2 == NULL)) {
7112	if (arg1 != NULL)
7113	    xmlXPathReleaseObject(ctxt->context, arg1);
7114	else
7115	    xmlXPathReleaseObject(ctxt->context, arg2);
7116	XP_ERROR0(XPATH_INVALID_OPERAND);
7117    }
7118
7119    if (arg1 == arg2) {
7120#ifdef DEBUG_EXPR
7121        xmlGenericError(xmlGenericErrorContext,
7122		"NotEqual: by pointer\n");
7123#endif
7124	xmlXPathReleaseObject(ctxt->context, arg1);
7125        return(0);
7126    }
7127
7128    /*
7129     *If either argument is a nodeset, it's a 'special case'
7130     */
7131    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7132      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7133	/*
7134	 *Hack it to assure arg1 is the nodeset
7135	 */
7136	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7137		argtmp = arg2;
7138		arg2 = arg1;
7139		arg1 = argtmp;
7140	}
7141	switch (arg2->type) {
7142	    case XPATH_UNDEFINED:
7143#ifdef DEBUG_EXPR
7144		xmlGenericError(xmlGenericErrorContext,
7145			"NotEqual: undefined\n");
7146#endif
7147		break;
7148	    case XPATH_NODESET:
7149	    case XPATH_XSLT_TREE:
7150		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7151		break;
7152	    case XPATH_BOOLEAN:
7153		if ((arg1->nodesetval == NULL) ||
7154		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7155		else
7156		    ret = 1;
7157		ret = (ret != arg2->boolval);
7158		break;
7159	    case XPATH_NUMBER:
7160		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7161		break;
7162	    case XPATH_STRING:
7163		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7164		break;
7165	    case XPATH_USERS:
7166	    case XPATH_POINT:
7167	    case XPATH_RANGE:
7168	    case XPATH_LOCATIONSET:
7169		TODO
7170		break;
7171	}
7172	xmlXPathReleaseObject(ctxt->context, arg1);
7173	xmlXPathReleaseObject(ctxt->context, arg2);
7174	return(ret);
7175    }
7176
7177    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7178}
7179
7180/**
7181 * xmlXPathCompareValues:
7182 * @ctxt:  the XPath Parser context
7183 * @inf:  less than (1) or greater than (0)
7184 * @strict:  is the comparison strict
7185 *
7186 * Implement the compare operation on XPath objects:
7187 *     @arg1 < @arg2    (1, 1, ...
7188 *     @arg1 <= @arg2   (1, 0, ...
7189 *     @arg1 > @arg2    (0, 1, ...
7190 *     @arg1 >= @arg2   (0, 0, ...
7191 *
7192 * When neither object to be compared is a node-set and the operator is
7193 * <=, <, >=, >, then the objects are compared by converted both objects
7194 * to numbers and comparing the numbers according to IEEE 754. The <
7195 * comparison will be true if and only if the first number is less than the
7196 * second number. The <= comparison will be true if and only if the first
7197 * number is less than or equal to the second number. The > comparison
7198 * will be true if and only if the first number is greater than the second
7199 * number. The >= comparison will be true if and only if the first number
7200 * is greater than or equal to the second number.
7201 *
7202 * Returns 1 if the comparison succeeded, 0 if it failed
7203 */
7204int
7205xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7206    int ret = 0, arg1i = 0, arg2i = 0;
7207    xmlXPathObjectPtr arg1, arg2;
7208
7209    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7210    arg2 = valuePop(ctxt);
7211    arg1 = valuePop(ctxt);
7212    if ((arg1 == NULL) || (arg2 == NULL)) {
7213	if (arg1 != NULL)
7214	    xmlXPathReleaseObject(ctxt->context, arg1);
7215	else
7216	    xmlXPathReleaseObject(ctxt->context, arg2);
7217	XP_ERROR0(XPATH_INVALID_OPERAND);
7218    }
7219
7220    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7221      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7222	/*
7223	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7224	 * are not freed from within this routine; they will be freed from the
7225	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7226	 */
7227	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7228	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7229	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7230	} else {
7231	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7232		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7233			                          arg1, arg2);
7234	    } else {
7235		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7236			                          arg2, arg1);
7237	    }
7238	}
7239	return(ret);
7240    }
7241
7242    if (arg1->type != XPATH_NUMBER) {
7243	valuePush(ctxt, arg1);
7244	xmlXPathNumberFunction(ctxt, 1);
7245	arg1 = valuePop(ctxt);
7246    }
7247    if (arg1->type != XPATH_NUMBER) {
7248	xmlXPathFreeObject(arg1);
7249	xmlXPathFreeObject(arg2);
7250	XP_ERROR0(XPATH_INVALID_OPERAND);
7251    }
7252    if (arg2->type != XPATH_NUMBER) {
7253	valuePush(ctxt, arg2);
7254	xmlXPathNumberFunction(ctxt, 1);
7255	arg2 = valuePop(ctxt);
7256    }
7257    if (arg2->type != XPATH_NUMBER) {
7258	xmlXPathReleaseObject(ctxt->context, arg1);
7259	xmlXPathReleaseObject(ctxt->context, arg2);
7260	XP_ERROR0(XPATH_INVALID_OPERAND);
7261    }
7262    /*
7263     * Add tests for infinity and nan
7264     * => feedback on 3.4 for Inf and NaN
7265     */
7266    /* Hand check NaN and Infinity comparisons */
7267    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7268	ret=0;
7269    } else {
7270	arg1i=xmlXPathIsInf(arg1->floatval);
7271	arg2i=xmlXPathIsInf(arg2->floatval);
7272	if (inf && strict) {
7273	    if ((arg1i == -1 && arg2i != -1) ||
7274		(arg2i == 1 && arg1i != 1)) {
7275		ret = 1;
7276	    } else if (arg1i == 0 && arg2i == 0) {
7277		ret = (arg1->floatval < arg2->floatval);
7278	    } else {
7279		ret = 0;
7280	    }
7281	}
7282	else if (inf && !strict) {
7283	    if (arg1i == -1 || arg2i == 1) {
7284		ret = 1;
7285	    } else if (arg1i == 0 && arg2i == 0) {
7286		ret = (arg1->floatval <= arg2->floatval);
7287	    } else {
7288		ret = 0;
7289	    }
7290	}
7291	else if (!inf && strict) {
7292	    if ((arg1i == 1 && arg2i != 1) ||
7293		(arg2i == -1 && arg1i != -1)) {
7294		ret = 1;
7295	    } else if (arg1i == 0 && arg2i == 0) {
7296		ret = (arg1->floatval > arg2->floatval);
7297	    } else {
7298		ret = 0;
7299	    }
7300	}
7301	else if (!inf && !strict) {
7302	    if (arg1i == 1 || arg2i == -1) {
7303		ret = 1;
7304	    } else if (arg1i == 0 && arg2i == 0) {
7305		ret = (arg1->floatval >= arg2->floatval);
7306	    } else {
7307		ret = 0;
7308	    }
7309	}
7310    }
7311    xmlXPathReleaseObject(ctxt->context, arg1);
7312    xmlXPathReleaseObject(ctxt->context, arg2);
7313    return(ret);
7314}
7315
7316/**
7317 * xmlXPathValueFlipSign:
7318 * @ctxt:  the XPath Parser context
7319 *
7320 * Implement the unary - operation on an XPath object
7321 * The numeric operators convert their operands to numbers as if
7322 * by calling the number function.
7323 */
7324void
7325xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7326    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7327    CAST_TO_NUMBER;
7328    CHECK_TYPE(XPATH_NUMBER);
7329    if (xmlXPathIsNaN(ctxt->value->floatval))
7330        ctxt->value->floatval=xmlXPathNAN;
7331    else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7332        ctxt->value->floatval=xmlXPathNINF;
7333    else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7334        ctxt->value->floatval=xmlXPathPINF;
7335    else if (ctxt->value->floatval == 0) {
7336        if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7337	    ctxt->value->floatval = xmlXPathNZERO;
7338	else
7339	    ctxt->value->floatval = 0;
7340    }
7341    else
7342        ctxt->value->floatval = - ctxt->value->floatval;
7343}
7344
7345/**
7346 * xmlXPathAddValues:
7347 * @ctxt:  the XPath Parser context
7348 *
7349 * Implement the add operation on XPath objects:
7350 * The numeric operators convert their operands to numbers as if
7351 * by calling the number function.
7352 */
7353void
7354xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7355    xmlXPathObjectPtr arg;
7356    double val;
7357
7358    arg = valuePop(ctxt);
7359    if (arg == NULL)
7360	XP_ERROR(XPATH_INVALID_OPERAND);
7361    val = xmlXPathCastToNumber(arg);
7362    xmlXPathReleaseObject(ctxt->context, arg);
7363    CAST_TO_NUMBER;
7364    CHECK_TYPE(XPATH_NUMBER);
7365    ctxt->value->floatval += val;
7366}
7367
7368/**
7369 * xmlXPathSubValues:
7370 * @ctxt:  the XPath Parser context
7371 *
7372 * Implement the subtraction operation on XPath objects:
7373 * The numeric operators convert their operands to numbers as if
7374 * by calling the number function.
7375 */
7376void
7377xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7378    xmlXPathObjectPtr arg;
7379    double val;
7380
7381    arg = valuePop(ctxt);
7382    if (arg == NULL)
7383	XP_ERROR(XPATH_INVALID_OPERAND);
7384    val = xmlXPathCastToNumber(arg);
7385    xmlXPathReleaseObject(ctxt->context, arg);
7386    CAST_TO_NUMBER;
7387    CHECK_TYPE(XPATH_NUMBER);
7388    ctxt->value->floatval -= val;
7389}
7390
7391/**
7392 * xmlXPathMultValues:
7393 * @ctxt:  the XPath Parser context
7394 *
7395 * Implement the multiply operation on XPath objects:
7396 * The numeric operators convert their operands to numbers as if
7397 * by calling the number function.
7398 */
7399void
7400xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7401    xmlXPathObjectPtr arg;
7402    double val;
7403
7404    arg = valuePop(ctxt);
7405    if (arg == NULL)
7406	XP_ERROR(XPATH_INVALID_OPERAND);
7407    val = xmlXPathCastToNumber(arg);
7408    xmlXPathReleaseObject(ctxt->context, arg);
7409    CAST_TO_NUMBER;
7410    CHECK_TYPE(XPATH_NUMBER);
7411    ctxt->value->floatval *= val;
7412}
7413
7414/**
7415 * xmlXPathDivValues:
7416 * @ctxt:  the XPath Parser context
7417 *
7418 * Implement the div operation on XPath objects @arg1 / @arg2:
7419 * The numeric operators convert their operands to numbers as if
7420 * by calling the number function.
7421 */
7422void
7423xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7424    xmlXPathObjectPtr arg;
7425    double val;
7426
7427    arg = valuePop(ctxt);
7428    if (arg == NULL)
7429	XP_ERROR(XPATH_INVALID_OPERAND);
7430    val = xmlXPathCastToNumber(arg);
7431    xmlXPathReleaseObject(ctxt->context, arg);
7432    CAST_TO_NUMBER;
7433    CHECK_TYPE(XPATH_NUMBER);
7434    if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7435	ctxt->value->floatval = xmlXPathNAN;
7436    else if (val == 0 && xmlXPathGetSign(val) != 0) {
7437	if (ctxt->value->floatval == 0)
7438	    ctxt->value->floatval = xmlXPathNAN;
7439	else if (ctxt->value->floatval > 0)
7440	    ctxt->value->floatval = xmlXPathNINF;
7441	else if (ctxt->value->floatval < 0)
7442	    ctxt->value->floatval = xmlXPathPINF;
7443    }
7444    else if (val == 0) {
7445	if (ctxt->value->floatval == 0)
7446	    ctxt->value->floatval = xmlXPathNAN;
7447	else if (ctxt->value->floatval > 0)
7448	    ctxt->value->floatval = xmlXPathPINF;
7449	else if (ctxt->value->floatval < 0)
7450	    ctxt->value->floatval = xmlXPathNINF;
7451    } else
7452	ctxt->value->floatval /= val;
7453}
7454
7455/**
7456 * xmlXPathModValues:
7457 * @ctxt:  the XPath Parser context
7458 *
7459 * Implement the mod operation on XPath objects: @arg1 / @arg2
7460 * The numeric operators convert their operands to numbers as if
7461 * by calling the number function.
7462 */
7463void
7464xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7465    xmlXPathObjectPtr arg;
7466    double arg1, arg2;
7467
7468    arg = valuePop(ctxt);
7469    if (arg == NULL)
7470	XP_ERROR(XPATH_INVALID_OPERAND);
7471    arg2 = xmlXPathCastToNumber(arg);
7472    xmlXPathReleaseObject(ctxt->context, arg);
7473    CAST_TO_NUMBER;
7474    CHECK_TYPE(XPATH_NUMBER);
7475    arg1 = ctxt->value->floatval;
7476    if (arg2 == 0)
7477	ctxt->value->floatval = xmlXPathNAN;
7478    else {
7479	ctxt->value->floatval = fmod(arg1, arg2);
7480    }
7481}
7482
7483/************************************************************************
7484 *									*
7485 *		The traversal functions					*
7486 *									*
7487 ************************************************************************/
7488
7489/*
7490 * A traversal function enumerates nodes along an axis.
7491 * Initially it must be called with NULL, and it indicates
7492 * termination on the axis by returning NULL.
7493 */
7494typedef xmlNodePtr (*xmlXPathTraversalFunction)
7495                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7496
7497/*
7498 * xmlXPathTraversalFunctionExt:
7499 * A traversal function enumerates nodes along an axis.
7500 * Initially it must be called with NULL, and it indicates
7501 * termination on the axis by returning NULL.
7502 * The context node of the traversal is specified via @contextNode.
7503 */
7504typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7505                    (xmlNodePtr cur, xmlNodePtr contextNode);
7506
7507/*
7508 * xmlXPathNodeSetMergeFunction:
7509 * Used for merging node sets in xmlXPathCollectAndTest().
7510 */
7511typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7512		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
7513
7514
7515/**
7516 * xmlXPathNextSelf:
7517 * @ctxt:  the XPath Parser context
7518 * @cur:  the current node in the traversal
7519 *
7520 * Traversal function for the "self" direction
7521 * The self axis contains just the context node itself
7522 *
7523 * Returns the next element following that axis
7524 */
7525xmlNodePtr
7526xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7527    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7528    if (cur == NULL)
7529        return(ctxt->context->node);
7530    return(NULL);
7531}
7532
7533/**
7534 * xmlXPathNextChild:
7535 * @ctxt:  the XPath Parser context
7536 * @cur:  the current node in the traversal
7537 *
7538 * Traversal function for the "child" direction
7539 * The child axis contains the children of the context node in document order.
7540 *
7541 * Returns the next element following that axis
7542 */
7543xmlNodePtr
7544xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7545    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7546    if (cur == NULL) {
7547	if (ctxt->context->node == NULL) return(NULL);
7548	switch (ctxt->context->node->type) {
7549            case XML_ELEMENT_NODE:
7550            case XML_TEXT_NODE:
7551            case XML_CDATA_SECTION_NODE:
7552            case XML_ENTITY_REF_NODE:
7553            case XML_ENTITY_NODE:
7554            case XML_PI_NODE:
7555            case XML_COMMENT_NODE:
7556            case XML_NOTATION_NODE:
7557            case XML_DTD_NODE:
7558		return(ctxt->context->node->children);
7559            case XML_DOCUMENT_NODE:
7560            case XML_DOCUMENT_TYPE_NODE:
7561            case XML_DOCUMENT_FRAG_NODE:
7562            case XML_HTML_DOCUMENT_NODE:
7563#ifdef LIBXML_DOCB_ENABLED
7564	    case XML_DOCB_DOCUMENT_NODE:
7565#endif
7566		return(((xmlDocPtr) ctxt->context->node)->children);
7567	    case XML_ELEMENT_DECL:
7568	    case XML_ATTRIBUTE_DECL:
7569	    case XML_ENTITY_DECL:
7570            case XML_ATTRIBUTE_NODE:
7571	    case XML_NAMESPACE_DECL:
7572	    case XML_XINCLUDE_START:
7573	    case XML_XINCLUDE_END:
7574		return(NULL);
7575	}
7576	return(NULL);
7577    }
7578    if ((cur->type == XML_DOCUMENT_NODE) ||
7579        (cur->type == XML_HTML_DOCUMENT_NODE))
7580	return(NULL);
7581    return(cur->next);
7582}
7583
7584/**
7585 * xmlXPathNextChildElement:
7586 * @ctxt:  the XPath Parser context
7587 * @cur:  the current node in the traversal
7588 *
7589 * Traversal function for the "child" direction and nodes of type element.
7590 * The child axis contains the children of the context node in document order.
7591 *
7592 * Returns the next element following that axis
7593 */
7594static xmlNodePtr
7595xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7596    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7597    if (cur == NULL) {
7598	cur = ctxt->context->node;
7599	if (cur == NULL) return(NULL);
7600	/*
7601	* Get the first element child.
7602	*/
7603	switch (cur->type) {
7604            case XML_ELEMENT_NODE:
7605	    case XML_DOCUMENT_FRAG_NODE:
7606	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7607            case XML_ENTITY_NODE:
7608		cur = cur->children;
7609		if (cur != NULL) {
7610		    if (cur->type == XML_ELEMENT_NODE)
7611			return(cur);
7612		    do {
7613			cur = cur->next;
7614		    } while ((cur != NULL) &&
7615			(cur->type != XML_ELEMENT_NODE));
7616		    return(cur);
7617		}
7618		return(NULL);
7619            case XML_DOCUMENT_NODE:
7620            case XML_HTML_DOCUMENT_NODE:
7621#ifdef LIBXML_DOCB_ENABLED
7622	    case XML_DOCB_DOCUMENT_NODE:
7623#endif
7624		return(xmlDocGetRootElement((xmlDocPtr) cur));
7625	    default:
7626		return(NULL);
7627	}
7628	return(NULL);
7629    }
7630    /*
7631    * Get the next sibling element node.
7632    */
7633    switch (cur->type) {
7634	case XML_ELEMENT_NODE:
7635	case XML_TEXT_NODE:
7636	case XML_ENTITY_REF_NODE:
7637	case XML_ENTITY_NODE:
7638	case XML_CDATA_SECTION_NODE:
7639	case XML_PI_NODE:
7640	case XML_COMMENT_NODE:
7641	case XML_XINCLUDE_END:
7642	    break;
7643	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7644	default:
7645	    return(NULL);
7646    }
7647    if (cur->next != NULL) {
7648	if (cur->next->type == XML_ELEMENT_NODE)
7649	    return(cur->next);
7650	cur = cur->next;
7651	do {
7652	    cur = cur->next;
7653	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7654	return(cur);
7655    }
7656    return(NULL);
7657}
7658
7659/**
7660 * xmlXPathNextDescendantOrSelfElemParent:
7661 * @ctxt:  the XPath Parser context
7662 * @cur:  the current node in the traversal
7663 *
7664 * Traversal function for the "descendant-or-self" axis.
7665 * Additionally it returns only nodes which can be parents of
7666 * element nodes.
7667 *
7668 *
7669 * Returns the next element following that axis
7670 */
7671static xmlNodePtr
7672xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7673				       xmlNodePtr contextNode)
7674{
7675    if (cur == NULL) {
7676	if (contextNode == NULL)
7677	    return(NULL);
7678	switch (contextNode->type) {
7679	    case XML_ELEMENT_NODE:
7680	    case XML_XINCLUDE_START:
7681	    case XML_DOCUMENT_FRAG_NODE:
7682	    case XML_DOCUMENT_NODE:
7683#ifdef LIBXML_DOCB_ENABLED
7684	    case XML_DOCB_DOCUMENT_NODE:
7685#endif
7686	    case XML_HTML_DOCUMENT_NODE:
7687		return(contextNode);
7688	    default:
7689		return(NULL);
7690	}
7691	return(NULL);
7692    } else {
7693	xmlNodePtr start = cur;
7694
7695	while (cur != NULL) {
7696	    switch (cur->type) {
7697		case XML_ELEMENT_NODE:
7698		/* TODO: OK to have XInclude here? */
7699		case XML_XINCLUDE_START:
7700		case XML_DOCUMENT_FRAG_NODE:
7701		    if (cur != start)
7702			return(cur);
7703		    if (cur->children != NULL) {
7704			cur = cur->children;
7705			continue;
7706		    }
7707		    break;
7708		/* Not sure if we need those here. */
7709		case XML_DOCUMENT_NODE:
7710#ifdef LIBXML_DOCB_ENABLED
7711		case XML_DOCB_DOCUMENT_NODE:
7712#endif
7713		case XML_HTML_DOCUMENT_NODE:
7714		    if (cur != start)
7715			return(cur);
7716		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7717		default:
7718		    break;
7719	    }
7720
7721next_sibling:
7722	    if ((cur == NULL) || (cur == contextNode))
7723		return(NULL);
7724	    if (cur->next != NULL) {
7725		cur = cur->next;
7726	    } else {
7727		cur = cur->parent;
7728		goto next_sibling;
7729	    }
7730	}
7731    }
7732    return(NULL);
7733}
7734
7735/**
7736 * xmlXPathNextDescendant:
7737 * @ctxt:  the XPath Parser context
7738 * @cur:  the current node in the traversal
7739 *
7740 * Traversal function for the "descendant" direction
7741 * the descendant axis contains the descendants of the context node in document
7742 * order; a descendant is a child or a child of a child and so on.
7743 *
7744 * Returns the next element following that axis
7745 */
7746xmlNodePtr
7747xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7748    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7749    if (cur == NULL) {
7750	if (ctxt->context->node == NULL)
7751	    return(NULL);
7752	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7753	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7754	    return(NULL);
7755
7756        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7757	    return(ctxt->context->doc->children);
7758        return(ctxt->context->node->children);
7759    }
7760
7761    if (cur->children != NULL) {
7762	/*
7763	 * Do not descend on entities declarations
7764	 */
7765	if (cur->children->type != XML_ENTITY_DECL) {
7766	    cur = cur->children;
7767	    /*
7768	     * Skip DTDs
7769	     */
7770	    if (cur->type != XML_DTD_NODE)
7771		return(cur);
7772	}
7773    }
7774
7775    if (cur == ctxt->context->node) return(NULL);
7776
7777    while (cur->next != NULL) {
7778	cur = cur->next;
7779	if ((cur->type != XML_ENTITY_DECL) &&
7780	    (cur->type != XML_DTD_NODE))
7781	    return(cur);
7782    }
7783
7784    do {
7785        cur = cur->parent;
7786	if (cur == NULL) break;
7787	if (cur == ctxt->context->node) return(NULL);
7788	if (cur->next != NULL) {
7789	    cur = cur->next;
7790	    return(cur);
7791	}
7792    } while (cur != NULL);
7793    return(cur);
7794}
7795
7796/**
7797 * xmlXPathNextDescendantOrSelf:
7798 * @ctxt:  the XPath Parser context
7799 * @cur:  the current node in the traversal
7800 *
7801 * Traversal function for the "descendant-or-self" direction
7802 * the descendant-or-self axis contains the context node and the descendants
7803 * of the context node in document order; thus the context node is the first
7804 * node on the axis, and the first child of the context node is the second node
7805 * on the axis
7806 *
7807 * Returns the next element following that axis
7808 */
7809xmlNodePtr
7810xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7811    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7812    if (cur == NULL) {
7813	if (ctxt->context->node == NULL)
7814	    return(NULL);
7815	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7816	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7817	    return(NULL);
7818        return(ctxt->context->node);
7819    }
7820
7821    return(xmlXPathNextDescendant(ctxt, cur));
7822}
7823
7824/**
7825 * xmlXPathNextParent:
7826 * @ctxt:  the XPath Parser context
7827 * @cur:  the current node in the traversal
7828 *
7829 * Traversal function for the "parent" direction
7830 * The parent axis contains the parent of the context node, if there is one.
7831 *
7832 * Returns the next element following that axis
7833 */
7834xmlNodePtr
7835xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7836    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7837    /*
7838     * the parent of an attribute or namespace node is the element
7839     * to which the attribute or namespace node is attached
7840     * Namespace handling !!!
7841     */
7842    if (cur == NULL) {
7843	if (ctxt->context->node == NULL) return(NULL);
7844	switch (ctxt->context->node->type) {
7845            case XML_ELEMENT_NODE:
7846            case XML_TEXT_NODE:
7847            case XML_CDATA_SECTION_NODE:
7848            case XML_ENTITY_REF_NODE:
7849            case XML_ENTITY_NODE:
7850            case XML_PI_NODE:
7851            case XML_COMMENT_NODE:
7852            case XML_NOTATION_NODE:
7853            case XML_DTD_NODE:
7854	    case XML_ELEMENT_DECL:
7855	    case XML_ATTRIBUTE_DECL:
7856	    case XML_XINCLUDE_START:
7857	    case XML_XINCLUDE_END:
7858	    case XML_ENTITY_DECL:
7859		if (ctxt->context->node->parent == NULL)
7860		    return((xmlNodePtr) ctxt->context->doc);
7861		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7862		    ((ctxt->context->node->parent->name[0] == ' ') ||
7863		     (xmlStrEqual(ctxt->context->node->parent->name,
7864				 BAD_CAST "fake node libxslt"))))
7865		    return(NULL);
7866		return(ctxt->context->node->parent);
7867            case XML_ATTRIBUTE_NODE: {
7868		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7869
7870		return(att->parent);
7871	    }
7872            case XML_DOCUMENT_NODE:
7873            case XML_DOCUMENT_TYPE_NODE:
7874            case XML_DOCUMENT_FRAG_NODE:
7875            case XML_HTML_DOCUMENT_NODE:
7876#ifdef LIBXML_DOCB_ENABLED
7877	    case XML_DOCB_DOCUMENT_NODE:
7878#endif
7879                return(NULL);
7880	    case XML_NAMESPACE_DECL: {
7881		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7882
7883		if ((ns->next != NULL) &&
7884		    (ns->next->type != XML_NAMESPACE_DECL))
7885		    return((xmlNodePtr) ns->next);
7886                return(NULL);
7887	    }
7888	}
7889    }
7890    return(NULL);
7891}
7892
7893/**
7894 * xmlXPathNextAncestor:
7895 * @ctxt:  the XPath Parser context
7896 * @cur:  the current node in the traversal
7897 *
7898 * Traversal function for the "ancestor" direction
7899 * the ancestor axis contains the ancestors of the context node; the ancestors
7900 * of the context node consist of the parent of context node and the parent's
7901 * parent and so on; the nodes are ordered in reverse document order; thus the
7902 * parent is the first node on the axis, and the parent's parent is the second
7903 * node on the axis
7904 *
7905 * Returns the next element following that axis
7906 */
7907xmlNodePtr
7908xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7909    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7910    /*
7911     * the parent of an attribute or namespace node is the element
7912     * to which the attribute or namespace node is attached
7913     * !!!!!!!!!!!!!
7914     */
7915    if (cur == NULL) {
7916	if (ctxt->context->node == NULL) return(NULL);
7917	switch (ctxt->context->node->type) {
7918            case XML_ELEMENT_NODE:
7919            case XML_TEXT_NODE:
7920            case XML_CDATA_SECTION_NODE:
7921            case XML_ENTITY_REF_NODE:
7922            case XML_ENTITY_NODE:
7923            case XML_PI_NODE:
7924            case XML_COMMENT_NODE:
7925	    case XML_DTD_NODE:
7926	    case XML_ELEMENT_DECL:
7927	    case XML_ATTRIBUTE_DECL:
7928	    case XML_ENTITY_DECL:
7929            case XML_NOTATION_NODE:
7930	    case XML_XINCLUDE_START:
7931	    case XML_XINCLUDE_END:
7932		if (ctxt->context->node->parent == NULL)
7933		    return((xmlNodePtr) ctxt->context->doc);
7934		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7935		    ((ctxt->context->node->parent->name[0] == ' ') ||
7936		     (xmlStrEqual(ctxt->context->node->parent->name,
7937				 BAD_CAST "fake node libxslt"))))
7938		    return(NULL);
7939		return(ctxt->context->node->parent);
7940            case XML_ATTRIBUTE_NODE: {
7941		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7942
7943		return(tmp->parent);
7944	    }
7945            case XML_DOCUMENT_NODE:
7946            case XML_DOCUMENT_TYPE_NODE:
7947            case XML_DOCUMENT_FRAG_NODE:
7948            case XML_HTML_DOCUMENT_NODE:
7949#ifdef LIBXML_DOCB_ENABLED
7950	    case XML_DOCB_DOCUMENT_NODE:
7951#endif
7952                return(NULL);
7953	    case XML_NAMESPACE_DECL: {
7954		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7955
7956		if ((ns->next != NULL) &&
7957		    (ns->next->type != XML_NAMESPACE_DECL))
7958		    return((xmlNodePtr) ns->next);
7959		/* Bad, how did that namespace end up here ? */
7960                return(NULL);
7961	    }
7962	}
7963	return(NULL);
7964    }
7965    if (cur == ctxt->context->doc->children)
7966	return((xmlNodePtr) ctxt->context->doc);
7967    if (cur == (xmlNodePtr) ctxt->context->doc)
7968	return(NULL);
7969    switch (cur->type) {
7970	case XML_ELEMENT_NODE:
7971	case XML_TEXT_NODE:
7972	case XML_CDATA_SECTION_NODE:
7973	case XML_ENTITY_REF_NODE:
7974	case XML_ENTITY_NODE:
7975	case XML_PI_NODE:
7976	case XML_COMMENT_NODE:
7977	case XML_NOTATION_NODE:
7978	case XML_DTD_NODE:
7979        case XML_ELEMENT_DECL:
7980        case XML_ATTRIBUTE_DECL:
7981        case XML_ENTITY_DECL:
7982	case XML_XINCLUDE_START:
7983	case XML_XINCLUDE_END:
7984	    if (cur->parent == NULL)
7985		return(NULL);
7986	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
7987		((cur->parent->name[0] == ' ') ||
7988		 (xmlStrEqual(cur->parent->name,
7989			      BAD_CAST "fake node libxslt"))))
7990		return(NULL);
7991	    return(cur->parent);
7992	case XML_ATTRIBUTE_NODE: {
7993	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7994
7995	    return(att->parent);
7996	}
7997	case XML_NAMESPACE_DECL: {
7998	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7999
8000	    if ((ns->next != NULL) &&
8001	        (ns->next->type != XML_NAMESPACE_DECL))
8002	        return((xmlNodePtr) ns->next);
8003	    /* Bad, how did that namespace end up here ? */
8004            return(NULL);
8005	}
8006	case XML_DOCUMENT_NODE:
8007	case XML_DOCUMENT_TYPE_NODE:
8008	case XML_DOCUMENT_FRAG_NODE:
8009	case XML_HTML_DOCUMENT_NODE:
8010#ifdef LIBXML_DOCB_ENABLED
8011	case XML_DOCB_DOCUMENT_NODE:
8012#endif
8013	    return(NULL);
8014    }
8015    return(NULL);
8016}
8017
8018/**
8019 * xmlXPathNextAncestorOrSelf:
8020 * @ctxt:  the XPath Parser context
8021 * @cur:  the current node in the traversal
8022 *
8023 * Traversal function for the "ancestor-or-self" direction
8024 * he ancestor-or-self axis contains the context node and ancestors of
8025 * the context node in reverse document order; thus the context node is
8026 * the first node on the axis, and the context node's parent the second;
8027 * parent here is defined the same as with the parent axis.
8028 *
8029 * Returns the next element following that axis
8030 */
8031xmlNodePtr
8032xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8033    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8034    if (cur == NULL)
8035        return(ctxt->context->node);
8036    return(xmlXPathNextAncestor(ctxt, cur));
8037}
8038
8039/**
8040 * xmlXPathNextFollowingSibling:
8041 * @ctxt:  the XPath Parser context
8042 * @cur:  the current node in the traversal
8043 *
8044 * Traversal function for the "following-sibling" direction
8045 * The following-sibling axis contains the following siblings of the context
8046 * node in document order.
8047 *
8048 * Returns the next element following that axis
8049 */
8050xmlNodePtr
8051xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8052    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8053    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8054	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8055	return(NULL);
8056    if (cur == (xmlNodePtr) ctxt->context->doc)
8057        return(NULL);
8058    if (cur == NULL)
8059        return(ctxt->context->node->next);
8060    return(cur->next);
8061}
8062
8063/**
8064 * xmlXPathNextPrecedingSibling:
8065 * @ctxt:  the XPath Parser context
8066 * @cur:  the current node in the traversal
8067 *
8068 * Traversal function for the "preceding-sibling" direction
8069 * The preceding-sibling axis contains the preceding siblings of the context
8070 * node in reverse document order; the first preceding sibling is first on the
8071 * axis; the sibling preceding that node is the second on the axis and so on.
8072 *
8073 * Returns the next element following that axis
8074 */
8075xmlNodePtr
8076xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8077    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8078    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8079	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8080	return(NULL);
8081    if (cur == (xmlNodePtr) ctxt->context->doc)
8082        return(NULL);
8083    if (cur == NULL)
8084        return(ctxt->context->node->prev);
8085    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8086	cur = cur->prev;
8087	if (cur == NULL)
8088	    return(ctxt->context->node->prev);
8089    }
8090    return(cur->prev);
8091}
8092
8093/**
8094 * xmlXPathNextFollowing:
8095 * @ctxt:  the XPath Parser context
8096 * @cur:  the current node in the traversal
8097 *
8098 * Traversal function for the "following" direction
8099 * The following axis contains all nodes in the same document as the context
8100 * node that are after the context node in document order, excluding any
8101 * descendants and excluding attribute nodes and namespace nodes; the nodes
8102 * are ordered in document order
8103 *
8104 * Returns the next element following that axis
8105 */
8106xmlNodePtr
8107xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8108    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8109    if (cur != NULL && cur->children != NULL)
8110        return cur->children ;
8111    if (cur == NULL) cur = ctxt->context->node;
8112    if (cur == NULL) return(NULL) ; /* ERROR */
8113    if (cur->next != NULL) return(cur->next) ;
8114    do {
8115        cur = cur->parent;
8116        if (cur == NULL) break;
8117        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8118        if (cur->next != NULL) return(cur->next);
8119    } while (cur != NULL);
8120    return(cur);
8121}
8122
8123/*
8124 * xmlXPathIsAncestor:
8125 * @ancestor:  the ancestor node
8126 * @node:  the current node
8127 *
8128 * Check that @ancestor is a @node's ancestor
8129 *
8130 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8131 */
8132static int
8133xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8134    if ((ancestor == NULL) || (node == NULL)) return(0);
8135    /* nodes need to be in the same document */
8136    if (ancestor->doc != node->doc) return(0);
8137    /* avoid searching if ancestor or node is the root node */
8138    if (ancestor == (xmlNodePtr) node->doc) return(1);
8139    if (node == (xmlNodePtr) ancestor->doc) return(0);
8140    while (node->parent != NULL) {
8141        if (node->parent == ancestor)
8142            return(1);
8143	node = node->parent;
8144    }
8145    return(0);
8146}
8147
8148/**
8149 * xmlXPathNextPreceding:
8150 * @ctxt:  the XPath Parser context
8151 * @cur:  the current node in the traversal
8152 *
8153 * Traversal function for the "preceding" direction
8154 * the preceding axis contains all nodes in the same document as the context
8155 * node that are before the context node in document order, excluding any
8156 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8157 * ordered in reverse document order
8158 *
8159 * Returns the next element following that axis
8160 */
8161xmlNodePtr
8162xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8163{
8164    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8165    if (cur == NULL)
8166        cur = ctxt->context->node;
8167    if (cur == NULL)
8168	return (NULL);
8169    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8170	cur = cur->prev;
8171    do {
8172        if (cur->prev != NULL) {
8173            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8174            return (cur);
8175        }
8176
8177        cur = cur->parent;
8178        if (cur == NULL)
8179            return (NULL);
8180        if (cur == ctxt->context->doc->children)
8181            return (NULL);
8182    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8183    return (cur);
8184}
8185
8186/**
8187 * xmlXPathNextPrecedingInternal:
8188 * @ctxt:  the XPath Parser context
8189 * @cur:  the current node in the traversal
8190 *
8191 * Traversal function for the "preceding" direction
8192 * the preceding axis contains all nodes in the same document as the context
8193 * node that are before the context node in document order, excluding any
8194 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8195 * ordered in reverse document order
8196 * This is a faster implementation but internal only since it requires a
8197 * state kept in the parser context: ctxt->ancestor.
8198 *
8199 * Returns the next element following that axis
8200 */
8201static xmlNodePtr
8202xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8203                              xmlNodePtr cur)
8204{
8205    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8206    if (cur == NULL) {
8207        cur = ctxt->context->node;
8208        if (cur == NULL)
8209            return (NULL);
8210	if (cur->type == XML_NAMESPACE_DECL)
8211	    cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
8212        ctxt->ancestor = cur->parent;
8213    }
8214    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8215	cur = cur->prev;
8216    while (cur->prev == NULL) {
8217        cur = cur->parent;
8218        if (cur == NULL)
8219            return (NULL);
8220        if (cur == ctxt->context->doc->children)
8221            return (NULL);
8222        if (cur != ctxt->ancestor)
8223            return (cur);
8224        ctxt->ancestor = cur->parent;
8225    }
8226    cur = cur->prev;
8227    while (cur->last != NULL)
8228        cur = cur->last;
8229    return (cur);
8230}
8231
8232/**
8233 * xmlXPathNextNamespace:
8234 * @ctxt:  the XPath Parser context
8235 * @cur:  the current attribute in the traversal
8236 *
8237 * Traversal function for the "namespace" direction
8238 * the namespace axis contains the namespace nodes of the context node;
8239 * the order of nodes on this axis is implementation-defined; the axis will
8240 * be empty unless the context node is an element
8241 *
8242 * We keep the XML namespace node at the end of the list.
8243 *
8244 * Returns the next element following that axis
8245 */
8246xmlNodePtr
8247xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8248    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8249    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8250    if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8251        if (ctxt->context->tmpNsList != NULL)
8252	    xmlFree(ctxt->context->tmpNsList);
8253	ctxt->context->tmpNsList =
8254	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8255	ctxt->context->tmpNsNr = 0;
8256	if (ctxt->context->tmpNsList != NULL) {
8257	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8258		ctxt->context->tmpNsNr++;
8259	    }
8260	}
8261	return((xmlNodePtr) xmlXPathXMLNamespace);
8262    }
8263    if (ctxt->context->tmpNsNr > 0) {
8264	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8265    } else {
8266	if (ctxt->context->tmpNsList != NULL)
8267	    xmlFree(ctxt->context->tmpNsList);
8268	ctxt->context->tmpNsList = NULL;
8269	return(NULL);
8270    }
8271}
8272
8273/**
8274 * xmlXPathNextAttribute:
8275 * @ctxt:  the XPath Parser context
8276 * @cur:  the current attribute in the traversal
8277 *
8278 * Traversal function for the "attribute" direction
8279 * TODO: support DTD inherited default attributes
8280 *
8281 * Returns the next element following that axis
8282 */
8283xmlNodePtr
8284xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8285    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8286    if (ctxt->context->node == NULL)
8287	return(NULL);
8288    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8289	return(NULL);
8290    if (cur == NULL) {
8291        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8292	    return(NULL);
8293        return((xmlNodePtr)ctxt->context->node->properties);
8294    }
8295    return((xmlNodePtr)cur->next);
8296}
8297
8298/************************************************************************
8299 *									*
8300 *		NodeTest Functions					*
8301 *									*
8302 ************************************************************************/
8303
8304#define IS_FUNCTION			200
8305
8306
8307/************************************************************************
8308 *									*
8309 *		Implicit tree core function library			*
8310 *									*
8311 ************************************************************************/
8312
8313/**
8314 * xmlXPathRoot:
8315 * @ctxt:  the XPath Parser context
8316 *
8317 * Initialize the context to the root of the document
8318 */
8319void
8320xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8321    if ((ctxt == NULL) || (ctxt->context == NULL))
8322	return;
8323    ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8324    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8325	ctxt->context->node));
8326}
8327
8328/************************************************************************
8329 *									*
8330 *		The explicit core function library			*
8331 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8332 *									*
8333 ************************************************************************/
8334
8335
8336/**
8337 * xmlXPathLastFunction:
8338 * @ctxt:  the XPath Parser context
8339 * @nargs:  the number of arguments
8340 *
8341 * Implement the last() XPath function
8342 *    number last()
8343 * The last function returns the number of nodes in the context node list.
8344 */
8345void
8346xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8347    CHECK_ARITY(0);
8348    if (ctxt->context->contextSize >= 0) {
8349	valuePush(ctxt,
8350	    xmlXPathCacheNewFloat(ctxt->context,
8351		(double) ctxt->context->contextSize));
8352#ifdef DEBUG_EXPR
8353	xmlGenericError(xmlGenericErrorContext,
8354		"last() : %d\n", ctxt->context->contextSize);
8355#endif
8356    } else {
8357	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8358    }
8359}
8360
8361/**
8362 * xmlXPathPositionFunction:
8363 * @ctxt:  the XPath Parser context
8364 * @nargs:  the number of arguments
8365 *
8366 * Implement the position() XPath function
8367 *    number position()
8368 * The position function returns the position of the context node in the
8369 * context node list. The first position is 1, and so the last position
8370 * will be equal to last().
8371 */
8372void
8373xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8374    CHECK_ARITY(0);
8375    if (ctxt->context->proximityPosition >= 0) {
8376	valuePush(ctxt,
8377	      xmlXPathCacheNewFloat(ctxt->context,
8378		(double) ctxt->context->proximityPosition));
8379#ifdef DEBUG_EXPR
8380	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8381		ctxt->context->proximityPosition);
8382#endif
8383    } else {
8384	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8385    }
8386}
8387
8388/**
8389 * xmlXPathCountFunction:
8390 * @ctxt:  the XPath Parser context
8391 * @nargs:  the number of arguments
8392 *
8393 * Implement the count() XPath function
8394 *    number count(node-set)
8395 */
8396void
8397xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8398    xmlXPathObjectPtr cur;
8399
8400    CHECK_ARITY(1);
8401    if ((ctxt->value == NULL) ||
8402	((ctxt->value->type != XPATH_NODESET) &&
8403	 (ctxt->value->type != XPATH_XSLT_TREE)))
8404	XP_ERROR(XPATH_INVALID_TYPE);
8405    cur = valuePop(ctxt);
8406
8407    if ((cur == NULL) || (cur->nodesetval == NULL))
8408	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8409    else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8410	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8411	    (double) cur->nodesetval->nodeNr));
8412    } else {
8413	if ((cur->nodesetval->nodeNr != 1) ||
8414	    (cur->nodesetval->nodeTab == NULL)) {
8415	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8416	} else {
8417	    xmlNodePtr tmp;
8418	    int i = 0;
8419
8420	    tmp = cur->nodesetval->nodeTab[0];
8421	    if (tmp != NULL) {
8422		tmp = tmp->children;
8423		while (tmp != NULL) {
8424		    tmp = tmp->next;
8425		    i++;
8426		}
8427	    }
8428	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8429	}
8430    }
8431    xmlXPathReleaseObject(ctxt->context, cur);
8432}
8433
8434/**
8435 * xmlXPathGetElementsByIds:
8436 * @doc:  the document
8437 * @ids:  a whitespace separated list of IDs
8438 *
8439 * Selects elements by their unique ID.
8440 *
8441 * Returns a node-set of selected elements.
8442 */
8443static xmlNodeSetPtr
8444xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8445    xmlNodeSetPtr ret;
8446    const xmlChar *cur = ids;
8447    xmlChar *ID;
8448    xmlAttrPtr attr;
8449    xmlNodePtr elem = NULL;
8450
8451    if (ids == NULL) return(NULL);
8452
8453    ret = xmlXPathNodeSetCreate(NULL);
8454    if (ret == NULL)
8455        return(ret);
8456
8457    while (IS_BLANK_CH(*cur)) cur++;
8458    while (*cur != 0) {
8459	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8460	    cur++;
8461
8462        ID = xmlStrndup(ids, cur - ids);
8463	if (ID != NULL) {
8464	    /*
8465	     * We used to check the fact that the value passed
8466	     * was an NCName, but this generated much troubles for
8467	     * me and Aleksey Sanin, people blatantly violated that
8468	     * constaint, like Visa3D spec.
8469	     * if (xmlValidateNCName(ID, 1) == 0)
8470	     */
8471	    attr = xmlGetID(doc, ID);
8472	    if (attr != NULL) {
8473		if (attr->type == XML_ATTRIBUTE_NODE)
8474		    elem = attr->parent;
8475		else if (attr->type == XML_ELEMENT_NODE)
8476		    elem = (xmlNodePtr) attr;
8477		else
8478		    elem = NULL;
8479		if (elem != NULL)
8480		    xmlXPathNodeSetAdd(ret, elem);
8481	    }
8482	    xmlFree(ID);
8483	}
8484
8485	while (IS_BLANK_CH(*cur)) cur++;
8486	ids = cur;
8487    }
8488    return(ret);
8489}
8490
8491/**
8492 * xmlXPathIdFunction:
8493 * @ctxt:  the XPath Parser context
8494 * @nargs:  the number of arguments
8495 *
8496 * Implement the id() XPath function
8497 *    node-set id(object)
8498 * The id function selects elements by their unique ID
8499 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8500 * then the result is the union of the result of applying id to the
8501 * string value of each of the nodes in the argument node-set. When the
8502 * argument to id is of any other type, the argument is converted to a
8503 * string as if by a call to the string function; the string is split
8504 * into a whitespace-separated list of tokens (whitespace is any sequence
8505 * of characters matching the production S); the result is a node-set
8506 * containing the elements in the same document as the context node that
8507 * have a unique ID equal to any of the tokens in the list.
8508 */
8509void
8510xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8511    xmlChar *tokens;
8512    xmlNodeSetPtr ret;
8513    xmlXPathObjectPtr obj;
8514
8515    CHECK_ARITY(1);
8516    obj = valuePop(ctxt);
8517    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8518    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8519	xmlNodeSetPtr ns;
8520	int i;
8521
8522	ret = xmlXPathNodeSetCreate(NULL);
8523        /*
8524         * FIXME -- in an out-of-memory condition this will behave badly.
8525         * The solution is not clear -- we already popped an item from
8526         * ctxt, so the object is in a corrupt state.
8527         */
8528
8529	if (obj->nodesetval != NULL) {
8530	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8531		tokens =
8532		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8533		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8534		ret = xmlXPathNodeSetMerge(ret, ns);
8535		xmlXPathFreeNodeSet(ns);
8536		if (tokens != NULL)
8537		    xmlFree(tokens);
8538	    }
8539	}
8540	xmlXPathReleaseObject(ctxt->context, obj);
8541	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8542	return;
8543    }
8544    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8545    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8546    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8547    xmlXPathReleaseObject(ctxt->context, obj);
8548    return;
8549}
8550
8551/**
8552 * xmlXPathLocalNameFunction:
8553 * @ctxt:  the XPath Parser context
8554 * @nargs:  the number of arguments
8555 *
8556 * Implement the local-name() XPath function
8557 *    string local-name(node-set?)
8558 * The local-name function returns a string containing the local part
8559 * of the name of the node in the argument node-set that is first in
8560 * document order. If the node-set is empty or the first node has no
8561 * name, an empty string is returned. If the argument is omitted it
8562 * defaults to the context node.
8563 */
8564void
8565xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8566    xmlXPathObjectPtr cur;
8567
8568    if (ctxt == NULL) return;
8569
8570    if (nargs == 0) {
8571	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8572	    ctxt->context->node));
8573	nargs = 1;
8574    }
8575
8576    CHECK_ARITY(1);
8577    if ((ctxt->value == NULL) ||
8578	((ctxt->value->type != XPATH_NODESET) &&
8579	 (ctxt->value->type != XPATH_XSLT_TREE)))
8580	XP_ERROR(XPATH_INVALID_TYPE);
8581    cur = valuePop(ctxt);
8582
8583    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8584	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8585    } else {
8586	int i = 0; /* Should be first in document order !!!!! */
8587	switch (cur->nodesetval->nodeTab[i]->type) {
8588	case XML_ELEMENT_NODE:
8589	case XML_ATTRIBUTE_NODE:
8590	case XML_PI_NODE:
8591	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8592		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8593	    else
8594		valuePush(ctxt,
8595		      xmlXPathCacheNewString(ctxt->context,
8596			cur->nodesetval->nodeTab[i]->name));
8597	    break;
8598	case XML_NAMESPACE_DECL:
8599	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8600			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8601	    break;
8602	default:
8603	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8604	}
8605    }
8606    xmlXPathReleaseObject(ctxt->context, cur);
8607}
8608
8609/**
8610 * xmlXPathNamespaceURIFunction:
8611 * @ctxt:  the XPath Parser context
8612 * @nargs:  the number of arguments
8613 *
8614 * Implement the namespace-uri() XPath function
8615 *    string namespace-uri(node-set?)
8616 * The namespace-uri function returns a string containing the
8617 * namespace URI of the expanded name of the node in the argument
8618 * node-set that is first in document order. If the node-set is empty,
8619 * the first node has no name, or the expanded name has no namespace
8620 * URI, an empty string is returned. If the argument is omitted it
8621 * defaults to the context node.
8622 */
8623void
8624xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8625    xmlXPathObjectPtr cur;
8626
8627    if (ctxt == NULL) return;
8628
8629    if (nargs == 0) {
8630	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8631	    ctxt->context->node));
8632	nargs = 1;
8633    }
8634    CHECK_ARITY(1);
8635    if ((ctxt->value == NULL) ||
8636	((ctxt->value->type != XPATH_NODESET) &&
8637	 (ctxt->value->type != XPATH_XSLT_TREE)))
8638	XP_ERROR(XPATH_INVALID_TYPE);
8639    cur = valuePop(ctxt);
8640
8641    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8642	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8643    } else {
8644	int i = 0; /* Should be first in document order !!!!! */
8645	switch (cur->nodesetval->nodeTab[i]->type) {
8646	case XML_ELEMENT_NODE:
8647	case XML_ATTRIBUTE_NODE:
8648	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8649		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8650	    else
8651		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8652			  cur->nodesetval->nodeTab[i]->ns->href));
8653	    break;
8654	default:
8655	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8656	}
8657    }
8658    xmlXPathReleaseObject(ctxt->context, cur);
8659}
8660
8661/**
8662 * xmlXPathNameFunction:
8663 * @ctxt:  the XPath Parser context
8664 * @nargs:  the number of arguments
8665 *
8666 * Implement the name() XPath function
8667 *    string name(node-set?)
8668 * The name function returns a string containing a QName representing
8669 * the name of the node in the argument node-set that is first in document
8670 * order. The QName must represent the name with respect to the namespace
8671 * declarations in effect on the node whose name is being represented.
8672 * Typically, this will be the form in which the name occurred in the XML
8673 * source. This need not be the case if there are namespace declarations
8674 * in effect on the node that associate multiple prefixes with the same
8675 * namespace. However, an implementation may include information about
8676 * the original prefix in its representation of nodes; in this case, an
8677 * implementation can ensure that the returned string is always the same
8678 * as the QName used in the XML source. If the argument it omitted it
8679 * defaults to the context node.
8680 * Libxml keep the original prefix so the "real qualified name" used is
8681 * returned.
8682 */
8683static void
8684xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8685{
8686    xmlXPathObjectPtr cur;
8687
8688    if (nargs == 0) {
8689	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8690	    ctxt->context->node));
8691        nargs = 1;
8692    }
8693
8694    CHECK_ARITY(1);
8695    if ((ctxt->value == NULL) ||
8696        ((ctxt->value->type != XPATH_NODESET) &&
8697         (ctxt->value->type != XPATH_XSLT_TREE)))
8698        XP_ERROR(XPATH_INVALID_TYPE);
8699    cur = valuePop(ctxt);
8700
8701    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8702        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8703    } else {
8704        int i = 0;              /* Should be first in document order !!!!! */
8705
8706        switch (cur->nodesetval->nodeTab[i]->type) {
8707            case XML_ELEMENT_NODE:
8708            case XML_ATTRIBUTE_NODE:
8709		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8710		    valuePush(ctxt,
8711			xmlXPathCacheNewCString(ctxt->context, ""));
8712		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8713                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8714		    valuePush(ctxt,
8715		        xmlXPathCacheNewString(ctxt->context,
8716			    cur->nodesetval->nodeTab[i]->name));
8717		} else {
8718		    xmlChar *fullname;
8719
8720		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8721				     cur->nodesetval->nodeTab[i]->ns->prefix,
8722				     NULL, 0);
8723		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8724			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8725		    if (fullname == NULL) {
8726			XP_ERROR(XPATH_MEMORY_ERROR);
8727		    }
8728		    valuePush(ctxt, xmlXPathCacheWrapString(
8729			ctxt->context, fullname));
8730                }
8731                break;
8732            default:
8733		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8734		    cur->nodesetval->nodeTab[i]));
8735                xmlXPathLocalNameFunction(ctxt, 1);
8736        }
8737    }
8738    xmlXPathReleaseObject(ctxt->context, cur);
8739}
8740
8741
8742/**
8743 * xmlXPathStringFunction:
8744 * @ctxt:  the XPath Parser context
8745 * @nargs:  the number of arguments
8746 *
8747 * Implement the string() XPath function
8748 *    string string(object?)
8749 * The string function converts an object to a string as follows:
8750 *    - A node-set is converted to a string by returning the value of
8751 *      the node in the node-set that is first in document order.
8752 *      If the node-set is empty, an empty string is returned.
8753 *    - A number is converted to a string as follows
8754 *      + NaN is converted to the string NaN
8755 *      + positive zero is converted to the string 0
8756 *      + negative zero is converted to the string 0
8757 *      + positive infinity is converted to the string Infinity
8758 *      + negative infinity is converted to the string -Infinity
8759 *      + if the number is an integer, the number is represented in
8760 *        decimal form as a Number with no decimal point and no leading
8761 *        zeros, preceded by a minus sign (-) if the number is negative
8762 *      + otherwise, the number is represented in decimal form as a
8763 *        Number including a decimal point with at least one digit
8764 *        before the decimal point and at least one digit after the
8765 *        decimal point, preceded by a minus sign (-) if the number
8766 *        is negative; there must be no leading zeros before the decimal
8767 *        point apart possibly from the one required digit immediately
8768 *        before the decimal point; beyond the one required digit
8769 *        after the decimal point there must be as many, but only as
8770 *        many, more digits as are needed to uniquely distinguish the
8771 *        number from all other IEEE 754 numeric values.
8772 *    - The boolean false value is converted to the string false.
8773 *      The boolean true value is converted to the string true.
8774 *
8775 * If the argument is omitted, it defaults to a node-set with the
8776 * context node as its only member.
8777 */
8778void
8779xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8780    xmlXPathObjectPtr cur;
8781
8782    if (ctxt == NULL) return;
8783    if (nargs == 0) {
8784    valuePush(ctxt,
8785	xmlXPathCacheWrapString(ctxt->context,
8786	    xmlXPathCastNodeToString(ctxt->context->node)));
8787	return;
8788    }
8789
8790    CHECK_ARITY(1);
8791    cur = valuePop(ctxt);
8792    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8793    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8794}
8795
8796/**
8797 * xmlXPathStringLengthFunction:
8798 * @ctxt:  the XPath Parser context
8799 * @nargs:  the number of arguments
8800 *
8801 * Implement the string-length() XPath function
8802 *    number string-length(string?)
8803 * The string-length returns the number of characters in the string
8804 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8805 * the context node converted to a string, in other words the value
8806 * of the context node.
8807 */
8808void
8809xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8810    xmlXPathObjectPtr cur;
8811
8812    if (nargs == 0) {
8813        if ((ctxt == NULL) || (ctxt->context == NULL))
8814	    return;
8815	if (ctxt->context->node == NULL) {
8816	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8817	} else {
8818	    xmlChar *content;
8819
8820	    content = xmlXPathCastNodeToString(ctxt->context->node);
8821	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8822		xmlUTF8Strlen(content)));
8823	    xmlFree(content);
8824	}
8825	return;
8826    }
8827    CHECK_ARITY(1);
8828    CAST_TO_STRING;
8829    CHECK_TYPE(XPATH_STRING);
8830    cur = valuePop(ctxt);
8831    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8832	xmlUTF8Strlen(cur->stringval)));
8833    xmlXPathReleaseObject(ctxt->context, cur);
8834}
8835
8836/**
8837 * xmlXPathConcatFunction:
8838 * @ctxt:  the XPath Parser context
8839 * @nargs:  the number of arguments
8840 *
8841 * Implement the concat() XPath function
8842 *    string concat(string, string, string*)
8843 * The concat function returns the concatenation of its arguments.
8844 */
8845void
8846xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8847    xmlXPathObjectPtr cur, newobj;
8848    xmlChar *tmp;
8849
8850    if (ctxt == NULL) return;
8851    if (nargs < 2) {
8852	CHECK_ARITY(2);
8853    }
8854
8855    CAST_TO_STRING;
8856    cur = valuePop(ctxt);
8857    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8858	xmlXPathReleaseObject(ctxt->context, cur);
8859	return;
8860    }
8861    nargs--;
8862
8863    while (nargs > 0) {
8864	CAST_TO_STRING;
8865	newobj = valuePop(ctxt);
8866	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8867	    xmlXPathReleaseObject(ctxt->context, newobj);
8868	    xmlXPathReleaseObject(ctxt->context, cur);
8869	    XP_ERROR(XPATH_INVALID_TYPE);
8870	}
8871	tmp = xmlStrcat(newobj->stringval, cur->stringval);
8872	newobj->stringval = cur->stringval;
8873	cur->stringval = tmp;
8874	xmlXPathReleaseObject(ctxt->context, newobj);
8875	nargs--;
8876    }
8877    valuePush(ctxt, cur);
8878}
8879
8880/**
8881 * xmlXPathContainsFunction:
8882 * @ctxt:  the XPath Parser context
8883 * @nargs:  the number of arguments
8884 *
8885 * Implement the contains() XPath function
8886 *    boolean contains(string, string)
8887 * The contains function returns true if the first argument string
8888 * contains the second argument string, and otherwise returns false.
8889 */
8890void
8891xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8892    xmlXPathObjectPtr hay, needle;
8893
8894    CHECK_ARITY(2);
8895    CAST_TO_STRING;
8896    CHECK_TYPE(XPATH_STRING);
8897    needle = valuePop(ctxt);
8898    CAST_TO_STRING;
8899    hay = valuePop(ctxt);
8900
8901    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8902	xmlXPathReleaseObject(ctxt->context, hay);
8903	xmlXPathReleaseObject(ctxt->context, needle);
8904	XP_ERROR(XPATH_INVALID_TYPE);
8905    }
8906    if (xmlStrstr(hay->stringval, needle->stringval))
8907	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8908    else
8909	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8910    xmlXPathReleaseObject(ctxt->context, hay);
8911    xmlXPathReleaseObject(ctxt->context, needle);
8912}
8913
8914/**
8915 * xmlXPathStartsWithFunction:
8916 * @ctxt:  the XPath Parser context
8917 * @nargs:  the number of arguments
8918 *
8919 * Implement the starts-with() XPath function
8920 *    boolean starts-with(string, string)
8921 * The starts-with function returns true if the first argument string
8922 * starts with the second argument string, and otherwise returns false.
8923 */
8924void
8925xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8926    xmlXPathObjectPtr hay, needle;
8927    int n;
8928
8929    CHECK_ARITY(2);
8930    CAST_TO_STRING;
8931    CHECK_TYPE(XPATH_STRING);
8932    needle = valuePop(ctxt);
8933    CAST_TO_STRING;
8934    hay = valuePop(ctxt);
8935
8936    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8937	xmlXPathReleaseObject(ctxt->context, hay);
8938	xmlXPathReleaseObject(ctxt->context, needle);
8939	XP_ERROR(XPATH_INVALID_TYPE);
8940    }
8941    n = xmlStrlen(needle->stringval);
8942    if (xmlStrncmp(hay->stringval, needle->stringval, n))
8943        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8944    else
8945        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8946    xmlXPathReleaseObject(ctxt->context, hay);
8947    xmlXPathReleaseObject(ctxt->context, needle);
8948}
8949
8950/**
8951 * xmlXPathSubstringFunction:
8952 * @ctxt:  the XPath Parser context
8953 * @nargs:  the number of arguments
8954 *
8955 * Implement the substring() XPath function
8956 *    string substring(string, number, number?)
8957 * The substring function returns the substring of the first argument
8958 * starting at the position specified in the second argument with
8959 * length specified in the third argument. For example,
8960 * substring("12345",2,3) returns "234". If the third argument is not
8961 * specified, it returns the substring starting at the position specified
8962 * in the second argument and continuing to the end of the string. For
8963 * example, substring("12345",2) returns "2345".  More precisely, each
8964 * character in the string (see [3.6 Strings]) is considered to have a
8965 * numeric position: the position of the first character is 1, the position
8966 * of the second character is 2 and so on. The returned substring contains
8967 * those characters for which the position of the character is greater than
8968 * or equal to the second argument and, if the third argument is specified,
8969 * less than the sum of the second and third arguments; the comparisons
8970 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8971 *  - substring("12345", 1.5, 2.6) returns "234"
8972 *  - substring("12345", 0, 3) returns "12"
8973 *  - substring("12345", 0 div 0, 3) returns ""
8974 *  - substring("12345", 1, 0 div 0) returns ""
8975 *  - substring("12345", -42, 1 div 0) returns "12345"
8976 *  - substring("12345", -1 div 0, 1 div 0) returns ""
8977 */
8978void
8979xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8980    xmlXPathObjectPtr str, start, len;
8981    double le=0, in;
8982    int i, l, m;
8983    xmlChar *ret;
8984
8985    if (nargs < 2) {
8986	CHECK_ARITY(2);
8987    }
8988    if (nargs > 3) {
8989	CHECK_ARITY(3);
8990    }
8991    /*
8992     * take care of possible last (position) argument
8993    */
8994    if (nargs == 3) {
8995	CAST_TO_NUMBER;
8996	CHECK_TYPE(XPATH_NUMBER);
8997	len = valuePop(ctxt);
8998	le = len->floatval;
8999	xmlXPathReleaseObject(ctxt->context, len);
9000    }
9001
9002    CAST_TO_NUMBER;
9003    CHECK_TYPE(XPATH_NUMBER);
9004    start = valuePop(ctxt);
9005    in = start->floatval;
9006    xmlXPathReleaseObject(ctxt->context, start);
9007    CAST_TO_STRING;
9008    CHECK_TYPE(XPATH_STRING);
9009    str = valuePop(ctxt);
9010    m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9011
9012    /*
9013     * If last pos not present, calculate last position
9014    */
9015    if (nargs != 3) {
9016	le = (double)m;
9017	if (in < 1.0)
9018	    in = 1.0;
9019    }
9020
9021    /* Need to check for the special cases where either
9022     * the index is NaN, the length is NaN, or both
9023     * arguments are infinity (relying on Inf + -Inf = NaN)
9024     */
9025    if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9026        /*
9027         * To meet the requirements of the spec, the arguments
9028	 * must be converted to integer format before
9029	 * initial index calculations are done
9030         *
9031         * First we go to integer form, rounding up
9032	 * and checking for special cases
9033         */
9034        i = (int) in;
9035        if (((double)i)+0.5 <= in) i++;
9036
9037	if (xmlXPathIsInf(le) == 1) {
9038	    l = m;
9039	    if (i < 1)
9040		i = 1;
9041	}
9042	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9043	    l = 0;
9044	else {
9045	    l = (int) le;
9046	    if (((double)l)+0.5 <= le) l++;
9047	}
9048
9049	/* Now we normalize inidices */
9050        i -= 1;
9051        l += i;
9052        if (i < 0)
9053            i = 0;
9054        if (l > m)
9055            l = m;
9056
9057        /* number of chars to copy */
9058        l -= i;
9059
9060        ret = xmlUTF8Strsub(str->stringval, i, l);
9061    }
9062    else {
9063        ret = NULL;
9064    }
9065    if (ret == NULL)
9066	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9067    else {
9068	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9069	xmlFree(ret);
9070    }
9071    xmlXPathReleaseObject(ctxt->context, str);
9072}
9073
9074/**
9075 * xmlXPathSubstringBeforeFunction:
9076 * @ctxt:  the XPath Parser context
9077 * @nargs:  the number of arguments
9078 *
9079 * Implement the substring-before() XPath function
9080 *    string substring-before(string, string)
9081 * The substring-before function returns the substring of the first
9082 * argument string that precedes the first occurrence of the second
9083 * argument string in the first argument string, or the empty string
9084 * if the first argument string does not contain the second argument
9085 * string. For example, substring-before("1999/04/01","/") returns 1999.
9086 */
9087void
9088xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9089  xmlXPathObjectPtr str;
9090  xmlXPathObjectPtr find;
9091  xmlBufferPtr target;
9092  const xmlChar *point;
9093  int offset;
9094
9095  CHECK_ARITY(2);
9096  CAST_TO_STRING;
9097  find = valuePop(ctxt);
9098  CAST_TO_STRING;
9099  str = valuePop(ctxt);
9100
9101  target = xmlBufferCreate();
9102  if (target) {
9103    point = xmlStrstr(str->stringval, find->stringval);
9104    if (point) {
9105      offset = (int)(point - str->stringval);
9106      xmlBufferAdd(target, str->stringval, offset);
9107    }
9108    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9109	xmlBufferContent(target)));
9110    xmlBufferFree(target);
9111  }
9112  xmlXPathReleaseObject(ctxt->context, str);
9113  xmlXPathReleaseObject(ctxt->context, find);
9114}
9115
9116/**
9117 * xmlXPathSubstringAfterFunction:
9118 * @ctxt:  the XPath Parser context
9119 * @nargs:  the number of arguments
9120 *
9121 * Implement the substring-after() XPath function
9122 *    string substring-after(string, string)
9123 * The substring-after function returns the substring of the first
9124 * argument string that follows the first occurrence of the second
9125 * argument string in the first argument string, or the empty stringi
9126 * if the first argument string does not contain the second argument
9127 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9128 * and substring-after("1999/04/01","19") returns 99/04/01.
9129 */
9130void
9131xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9132  xmlXPathObjectPtr str;
9133  xmlXPathObjectPtr find;
9134  xmlBufferPtr target;
9135  const xmlChar *point;
9136  int offset;
9137
9138  CHECK_ARITY(2);
9139  CAST_TO_STRING;
9140  find = valuePop(ctxt);
9141  CAST_TO_STRING;
9142  str = valuePop(ctxt);
9143
9144  target = xmlBufferCreate();
9145  if (target) {
9146    point = xmlStrstr(str->stringval, find->stringval);
9147    if (point) {
9148      offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9149      xmlBufferAdd(target, &str->stringval[offset],
9150		   xmlStrlen(str->stringval) - offset);
9151    }
9152    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9153	xmlBufferContent(target)));
9154    xmlBufferFree(target);
9155  }
9156  xmlXPathReleaseObject(ctxt->context, str);
9157  xmlXPathReleaseObject(ctxt->context, find);
9158}
9159
9160/**
9161 * xmlXPathNormalizeFunction:
9162 * @ctxt:  the XPath Parser context
9163 * @nargs:  the number of arguments
9164 *
9165 * Implement the normalize-space() XPath function
9166 *    string normalize-space(string?)
9167 * The normalize-space function returns the argument string with white
9168 * space normalized by stripping leading and trailing whitespace
9169 * and replacing sequences of whitespace characters by a single
9170 * space. Whitespace characters are the same allowed by the S production
9171 * in XML. If the argument is omitted, it defaults to the context
9172 * node converted to a string, in other words the value of the context node.
9173 */
9174void
9175xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9176  xmlXPathObjectPtr obj = NULL;
9177  xmlChar *source = NULL;
9178  xmlBufferPtr target;
9179  xmlChar blank;
9180
9181  if (ctxt == NULL) return;
9182  if (nargs == 0) {
9183    /* Use current context node */
9184      valuePush(ctxt,
9185	  xmlXPathCacheWrapString(ctxt->context,
9186	    xmlXPathCastNodeToString(ctxt->context->node)));
9187    nargs = 1;
9188  }
9189
9190  CHECK_ARITY(1);
9191  CAST_TO_STRING;
9192  CHECK_TYPE(XPATH_STRING);
9193  obj = valuePop(ctxt);
9194  source = obj->stringval;
9195
9196  target = xmlBufferCreate();
9197  if (target && source) {
9198
9199    /* Skip leading whitespaces */
9200    while (IS_BLANK_CH(*source))
9201      source++;
9202
9203    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9204    blank = 0;
9205    while (*source) {
9206      if (IS_BLANK_CH(*source)) {
9207	blank = 0x20;
9208      } else {
9209	if (blank) {
9210	  xmlBufferAdd(target, &blank, 1);
9211	  blank = 0;
9212	}
9213	xmlBufferAdd(target, source, 1);
9214      }
9215      source++;
9216    }
9217    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9218	xmlBufferContent(target)));
9219    xmlBufferFree(target);
9220  }
9221  xmlXPathReleaseObject(ctxt->context, obj);
9222}
9223
9224/**
9225 * xmlXPathTranslateFunction:
9226 * @ctxt:  the XPath Parser context
9227 * @nargs:  the number of arguments
9228 *
9229 * Implement the translate() XPath function
9230 *    string translate(string, string, string)
9231 * The translate function returns the first argument string with
9232 * occurrences of characters in the second argument string replaced
9233 * by the character at the corresponding position in the third argument
9234 * string. For example, translate("bar","abc","ABC") returns the string
9235 * BAr. If there is a character in the second argument string with no
9236 * character at a corresponding position in the third argument string
9237 * (because the second argument string is longer than the third argument
9238 * string), then occurrences of that character in the first argument
9239 * string are removed. For example, translate("--aaa--","abc-","ABC")
9240 * returns "AAA". If a character occurs more than once in second
9241 * argument string, then the first occurrence determines the replacement
9242 * character. If the third argument string is longer than the second
9243 * argument string, then excess characters are ignored.
9244 */
9245void
9246xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9247    xmlXPathObjectPtr str;
9248    xmlXPathObjectPtr from;
9249    xmlXPathObjectPtr to;
9250    xmlBufferPtr target;
9251    int offset, max;
9252    xmlChar ch;
9253    const xmlChar *point;
9254    xmlChar *cptr;
9255
9256    CHECK_ARITY(3);
9257
9258    CAST_TO_STRING;
9259    to = valuePop(ctxt);
9260    CAST_TO_STRING;
9261    from = valuePop(ctxt);
9262    CAST_TO_STRING;
9263    str = valuePop(ctxt);
9264
9265    target = xmlBufferCreate();
9266    if (target) {
9267	max = xmlUTF8Strlen(to->stringval);
9268	for (cptr = str->stringval; (ch=*cptr); ) {
9269	    offset = xmlUTF8Strloc(from->stringval, cptr);
9270	    if (offset >= 0) {
9271		if (offset < max) {
9272		    point = xmlUTF8Strpos(to->stringval, offset);
9273		    if (point)
9274			xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9275		}
9276	    } else
9277		xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9278
9279	    /* Step to next character in input */
9280	    cptr++;
9281	    if ( ch & 0x80 ) {
9282		/* if not simple ascii, verify proper format */
9283		if ( (ch & 0xc0) != 0xc0 ) {
9284		    xmlGenericError(xmlGenericErrorContext,
9285			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9286		    break;
9287		}
9288		/* then skip over remaining bytes for this char */
9289		while ( (ch <<= 1) & 0x80 )
9290		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9291			xmlGenericError(xmlGenericErrorContext,
9292			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9293			break;
9294		    }
9295		if (ch & 0x80) /* must have had error encountered */
9296		    break;
9297	    }
9298	}
9299    }
9300    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9301	xmlBufferContent(target)));
9302    xmlBufferFree(target);
9303    xmlXPathReleaseObject(ctxt->context, str);
9304    xmlXPathReleaseObject(ctxt->context, from);
9305    xmlXPathReleaseObject(ctxt->context, to);
9306}
9307
9308/**
9309 * xmlXPathBooleanFunction:
9310 * @ctxt:  the XPath Parser context
9311 * @nargs:  the number of arguments
9312 *
9313 * Implement the boolean() XPath function
9314 *    boolean boolean(object)
9315 * The boolean function converts its argument to a boolean as follows:
9316 *    - a number is true if and only if it is neither positive or
9317 *      negative zero nor NaN
9318 *    - a node-set is true if and only if it is non-empty
9319 *    - a string is true if and only if its length is non-zero
9320 */
9321void
9322xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9323    xmlXPathObjectPtr cur;
9324
9325    CHECK_ARITY(1);
9326    cur = valuePop(ctxt);
9327    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9328    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9329    valuePush(ctxt, cur);
9330}
9331
9332/**
9333 * xmlXPathNotFunction:
9334 * @ctxt:  the XPath Parser context
9335 * @nargs:  the number of arguments
9336 *
9337 * Implement the not() XPath function
9338 *    boolean not(boolean)
9339 * The not function returns true if its argument is false,
9340 * and false otherwise.
9341 */
9342void
9343xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9344    CHECK_ARITY(1);
9345    CAST_TO_BOOLEAN;
9346    CHECK_TYPE(XPATH_BOOLEAN);
9347    ctxt->value->boolval = ! ctxt->value->boolval;
9348}
9349
9350/**
9351 * xmlXPathTrueFunction:
9352 * @ctxt:  the XPath Parser context
9353 * @nargs:  the number of arguments
9354 *
9355 * Implement the true() XPath function
9356 *    boolean true()
9357 */
9358void
9359xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9360    CHECK_ARITY(0);
9361    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9362}
9363
9364/**
9365 * xmlXPathFalseFunction:
9366 * @ctxt:  the XPath Parser context
9367 * @nargs:  the number of arguments
9368 *
9369 * Implement the false() XPath function
9370 *    boolean false()
9371 */
9372void
9373xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9374    CHECK_ARITY(0);
9375    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9376}
9377
9378/**
9379 * xmlXPathLangFunction:
9380 * @ctxt:  the XPath Parser context
9381 * @nargs:  the number of arguments
9382 *
9383 * Implement the lang() XPath function
9384 *    boolean lang(string)
9385 * The lang function returns true or false depending on whether the
9386 * language of the context node as specified by xml:lang attributes
9387 * is the same as or is a sublanguage of the language specified by
9388 * the argument string. The language of the context node is determined
9389 * by the value of the xml:lang attribute on the context node, or, if
9390 * the context node has no xml:lang attribute, by the value of the
9391 * xml:lang attribute on the nearest ancestor of the context node that
9392 * has an xml:lang attribute. If there is no such attribute, then lang
9393 * returns false. If there is such an attribute, then lang returns
9394 * true if the attribute value is equal to the argument ignoring case,
9395 * or if there is some suffix starting with - such that the attribute
9396 * value is equal to the argument ignoring that suffix of the attribute
9397 * value and ignoring case.
9398 */
9399void
9400xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9401    xmlXPathObjectPtr val = NULL;
9402    const xmlChar *theLang = NULL;
9403    const xmlChar *lang;
9404    int ret = 0;
9405    int i;
9406
9407    CHECK_ARITY(1);
9408    CAST_TO_STRING;
9409    CHECK_TYPE(XPATH_STRING);
9410    val = valuePop(ctxt);
9411    lang = val->stringval;
9412    theLang = xmlNodeGetLang(ctxt->context->node);
9413    if ((theLang != NULL) && (lang != NULL)) {
9414        for (i = 0;lang[i] != 0;i++)
9415	    if (toupper(lang[i]) != toupper(theLang[i]))
9416	        goto not_equal;
9417	if ((theLang[i] == 0) || (theLang[i] == '-'))
9418	    ret = 1;
9419    }
9420not_equal:
9421    if (theLang != NULL)
9422	xmlFree((void *)theLang);
9423
9424    xmlXPathReleaseObject(ctxt->context, val);
9425    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9426}
9427
9428/**
9429 * xmlXPathNumberFunction:
9430 * @ctxt:  the XPath Parser context
9431 * @nargs:  the number of arguments
9432 *
9433 * Implement the number() XPath function
9434 *    number number(object?)
9435 */
9436void
9437xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9438    xmlXPathObjectPtr cur;
9439    double res;
9440
9441    if (ctxt == NULL) return;
9442    if (nargs == 0) {
9443	if (ctxt->context->node == NULL) {
9444	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9445	} else {
9446	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9447
9448	    res = xmlXPathStringEvalNumber(content);
9449	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9450	    xmlFree(content);
9451	}
9452	return;
9453    }
9454
9455    CHECK_ARITY(1);
9456    cur = valuePop(ctxt);
9457    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9458}
9459
9460/**
9461 * xmlXPathSumFunction:
9462 * @ctxt:  the XPath Parser context
9463 * @nargs:  the number of arguments
9464 *
9465 * Implement the sum() XPath function
9466 *    number sum(node-set)
9467 * The sum function returns the sum of the values of the nodes in
9468 * the argument node-set.
9469 */
9470void
9471xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9472    xmlXPathObjectPtr cur;
9473    int i;
9474    double res = 0.0;
9475
9476    CHECK_ARITY(1);
9477    if ((ctxt->value == NULL) ||
9478	((ctxt->value->type != XPATH_NODESET) &&
9479	 (ctxt->value->type != XPATH_XSLT_TREE)))
9480	XP_ERROR(XPATH_INVALID_TYPE);
9481    cur = valuePop(ctxt);
9482
9483    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9484	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9485	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9486	}
9487    }
9488    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9489    xmlXPathReleaseObject(ctxt->context, cur);
9490}
9491
9492/*
9493 * To assure working code on multiple platforms, we want to only depend
9494 * upon the characteristic truncation of converting a floating point value
9495 * to an integer.  Unfortunately, because of the different storage sizes
9496 * of our internal floating point value (double) and integer (int), we
9497 * can't directly convert (see bug 301162).  This macro is a messy
9498 * 'workaround'
9499 */
9500#define XTRUNC(f, v)            \
9501    f = fmod((v), INT_MAX);     \
9502    f = (v) - (f) + (double)((int)(f));
9503
9504/**
9505 * xmlXPathFloorFunction:
9506 * @ctxt:  the XPath Parser context
9507 * @nargs:  the number of arguments
9508 *
9509 * Implement the floor() XPath function
9510 *    number floor(number)
9511 * The floor function returns the largest (closest to positive infinity)
9512 * number that is not greater than the argument and that is an integer.
9513 */
9514void
9515xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9516    double f;
9517
9518    CHECK_ARITY(1);
9519    CAST_TO_NUMBER;
9520    CHECK_TYPE(XPATH_NUMBER);
9521
9522    XTRUNC(f, ctxt->value->floatval);
9523    if (f != ctxt->value->floatval) {
9524	if (ctxt->value->floatval > 0)
9525	    ctxt->value->floatval = f;
9526	else
9527	    ctxt->value->floatval = f - 1;
9528    }
9529}
9530
9531/**
9532 * xmlXPathCeilingFunction:
9533 * @ctxt:  the XPath Parser context
9534 * @nargs:  the number of arguments
9535 *
9536 * Implement the ceiling() XPath function
9537 *    number ceiling(number)
9538 * The ceiling function returns the smallest (closest to negative infinity)
9539 * number that is not less than the argument and that is an integer.
9540 */
9541void
9542xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9543    double f;
9544
9545    CHECK_ARITY(1);
9546    CAST_TO_NUMBER;
9547    CHECK_TYPE(XPATH_NUMBER);
9548
9549#if 0
9550    ctxt->value->floatval = ceil(ctxt->value->floatval);
9551#else
9552    XTRUNC(f, ctxt->value->floatval);
9553    if (f != ctxt->value->floatval) {
9554	if (ctxt->value->floatval > 0)
9555	    ctxt->value->floatval = f + 1;
9556	else {
9557	    if (ctxt->value->floatval < 0 && f == 0)
9558	        ctxt->value->floatval = xmlXPathNZERO;
9559	    else
9560	        ctxt->value->floatval = f;
9561	}
9562
9563    }
9564#endif
9565}
9566
9567/**
9568 * xmlXPathRoundFunction:
9569 * @ctxt:  the XPath Parser context
9570 * @nargs:  the number of arguments
9571 *
9572 * Implement the round() XPath function
9573 *    number round(number)
9574 * The round function returns the number that is closest to the
9575 * argument and that is an integer. If there are two such numbers,
9576 * then the one that is even is returned.
9577 */
9578void
9579xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9580    double f;
9581
9582    CHECK_ARITY(1);
9583    CAST_TO_NUMBER;
9584    CHECK_TYPE(XPATH_NUMBER);
9585
9586    if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9587	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9588	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9589	(ctxt->value->floatval == 0.0))
9590	return;
9591
9592    XTRUNC(f, ctxt->value->floatval);
9593    if (ctxt->value->floatval < 0) {
9594	if (ctxt->value->floatval < f - 0.5)
9595	    ctxt->value->floatval = f - 1;
9596	else
9597	    ctxt->value->floatval = f;
9598	if (ctxt->value->floatval == 0)
9599	    ctxt->value->floatval = xmlXPathNZERO;
9600    } else {
9601	if (ctxt->value->floatval < f + 0.5)
9602	    ctxt->value->floatval = f;
9603	else
9604	    ctxt->value->floatval = f + 1;
9605    }
9606}
9607
9608/************************************************************************
9609 *									*
9610 *			The Parser					*
9611 *									*
9612 ************************************************************************/
9613
9614/*
9615 * a few forward declarations since we use a recursive call based
9616 * implementation.
9617 */
9618static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9619static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9620static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9621static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9622static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9623	                                  int qualified);
9624
9625/**
9626 * xmlXPathCurrentChar:
9627 * @ctxt:  the XPath parser context
9628 * @cur:  pointer to the beginning of the char
9629 * @len:  pointer to the length of the char read
9630 *
9631 * The current char value, if using UTF-8 this may actually span multiple
9632 * bytes in the input buffer.
9633 *
9634 * Returns the current char value and its length
9635 */
9636
9637static int
9638xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9639    unsigned char c;
9640    unsigned int val;
9641    const xmlChar *cur;
9642
9643    if (ctxt == NULL)
9644	return(0);
9645    cur = ctxt->cur;
9646
9647    /*
9648     * We are supposed to handle UTF8, check it's valid
9649     * From rfc2044: encoding of the Unicode values on UTF-8:
9650     *
9651     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9652     * 0000 0000-0000 007F   0xxxxxxx
9653     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9654     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9655     *
9656     * Check for the 0x110000 limit too
9657     */
9658    c = *cur;
9659    if (c & 0x80) {
9660	if ((cur[1] & 0xc0) != 0x80)
9661	    goto encoding_error;
9662	if ((c & 0xe0) == 0xe0) {
9663
9664	    if ((cur[2] & 0xc0) != 0x80)
9665		goto encoding_error;
9666	    if ((c & 0xf0) == 0xf0) {
9667		if (((c & 0xf8) != 0xf0) ||
9668		    ((cur[3] & 0xc0) != 0x80))
9669		    goto encoding_error;
9670		/* 4-byte code */
9671		*len = 4;
9672		val = (cur[0] & 0x7) << 18;
9673		val |= (cur[1] & 0x3f) << 12;
9674		val |= (cur[2] & 0x3f) << 6;
9675		val |= cur[3] & 0x3f;
9676	    } else {
9677	      /* 3-byte code */
9678		*len = 3;
9679		val = (cur[0] & 0xf) << 12;
9680		val |= (cur[1] & 0x3f) << 6;
9681		val |= cur[2] & 0x3f;
9682	    }
9683	} else {
9684	  /* 2-byte code */
9685	    *len = 2;
9686	    val = (cur[0] & 0x1f) << 6;
9687	    val |= cur[1] & 0x3f;
9688	}
9689	if (!IS_CHAR(val)) {
9690	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9691	}
9692	return(val);
9693    } else {
9694	/* 1-byte code */
9695	*len = 1;
9696	return((int) *cur);
9697    }
9698encoding_error:
9699    /*
9700     * If we detect an UTF8 error that probably means that the
9701     * input encoding didn't get properly advertised in the
9702     * declaration header. Report the error and switch the encoding
9703     * to ISO-Latin-1 (if you don't like this policy, just declare the
9704     * encoding !)
9705     */
9706    *len = 0;
9707    XP_ERROR0(XPATH_ENCODING_ERROR);
9708}
9709
9710/**
9711 * xmlXPathParseNCName:
9712 * @ctxt:  the XPath Parser context
9713 *
9714 * parse an XML namespace non qualified name.
9715 *
9716 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9717 *
9718 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9719 *                       CombiningChar | Extender
9720 *
9721 * Returns the namespace name or NULL
9722 */
9723
9724xmlChar *
9725xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9726    const xmlChar *in;
9727    xmlChar *ret;
9728    int count = 0;
9729
9730    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9731    /*
9732     * Accelerator for simple ASCII names
9733     */
9734    in = ctxt->cur;
9735    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9736	((*in >= 0x41) && (*in <= 0x5A)) ||
9737	(*in == '_')) {
9738	in++;
9739	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9740	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9741	       ((*in >= 0x30) && (*in <= 0x39)) ||
9742	       (*in == '_') || (*in == '.') ||
9743	       (*in == '-'))
9744	    in++;
9745	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9746            (*in == '[') || (*in == ']') || (*in == ':') ||
9747            (*in == '@') || (*in == '*')) {
9748	    count = in - ctxt->cur;
9749	    if (count == 0)
9750		return(NULL);
9751	    ret = xmlStrndup(ctxt->cur, count);
9752	    ctxt->cur = in;
9753	    return(ret);
9754	}
9755    }
9756    return(xmlXPathParseNameComplex(ctxt, 0));
9757}
9758
9759
9760/**
9761 * xmlXPathParseQName:
9762 * @ctxt:  the XPath Parser context
9763 * @prefix:  a xmlChar **
9764 *
9765 * parse an XML qualified name
9766 *
9767 * [NS 5] QName ::= (Prefix ':')? LocalPart
9768 *
9769 * [NS 6] Prefix ::= NCName
9770 *
9771 * [NS 7] LocalPart ::= NCName
9772 *
9773 * Returns the function returns the local part, and prefix is updated
9774 *   to get the Prefix if any.
9775 */
9776
9777static xmlChar *
9778xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9779    xmlChar *ret = NULL;
9780
9781    *prefix = NULL;
9782    ret = xmlXPathParseNCName(ctxt);
9783    if (ret && CUR == ':') {
9784        *prefix = ret;
9785	NEXT;
9786	ret = xmlXPathParseNCName(ctxt);
9787    }
9788    return(ret);
9789}
9790
9791/**
9792 * xmlXPathParseName:
9793 * @ctxt:  the XPath Parser context
9794 *
9795 * parse an XML name
9796 *
9797 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9798 *                  CombiningChar | Extender
9799 *
9800 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9801 *
9802 * Returns the namespace name or NULL
9803 */
9804
9805xmlChar *
9806xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9807    const xmlChar *in;
9808    xmlChar *ret;
9809    int count = 0;
9810
9811    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9812    /*
9813     * Accelerator for simple ASCII names
9814     */
9815    in = ctxt->cur;
9816    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9817	((*in >= 0x41) && (*in <= 0x5A)) ||
9818	(*in == '_') || (*in == ':')) {
9819	in++;
9820	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9821	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9822	       ((*in >= 0x30) && (*in <= 0x39)) ||
9823	       (*in == '_') || (*in == '-') ||
9824	       (*in == ':') || (*in == '.'))
9825	    in++;
9826	if ((*in > 0) && (*in < 0x80)) {
9827	    count = in - ctxt->cur;
9828	    ret = xmlStrndup(ctxt->cur, count);
9829	    ctxt->cur = in;
9830	    return(ret);
9831	}
9832    }
9833    return(xmlXPathParseNameComplex(ctxt, 1));
9834}
9835
9836static xmlChar *
9837xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9838    xmlChar buf[XML_MAX_NAMELEN + 5];
9839    int len = 0, l;
9840    int c;
9841
9842    /*
9843     * Handler for more complex cases
9844     */
9845    c = CUR_CHAR(l);
9846    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9847        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9848        (c == '*') || /* accelerators */
9849	(!IS_LETTER(c) && (c != '_') &&
9850         ((qualified) && (c != ':')))) {
9851	return(NULL);
9852    }
9853
9854    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9855	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9856            (c == '.') || (c == '-') ||
9857	    (c == '_') || ((qualified) && (c == ':')) ||
9858	    (IS_COMBINING(c)) ||
9859	    (IS_EXTENDER(c)))) {
9860	COPY_BUF(l,buf,len,c);
9861	NEXTL(l);
9862	c = CUR_CHAR(l);
9863	if (len >= XML_MAX_NAMELEN) {
9864	    /*
9865	     * Okay someone managed to make a huge name, so he's ready to pay
9866	     * for the processing speed.
9867	     */
9868	    xmlChar *buffer;
9869	    int max = len * 2;
9870
9871	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9872	    if (buffer == NULL) {
9873		XP_ERRORNULL(XPATH_MEMORY_ERROR);
9874	    }
9875	    memcpy(buffer, buf, len);
9876	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9877		   (c == '.') || (c == '-') ||
9878		   (c == '_') || ((qualified) && (c == ':')) ||
9879		   (IS_COMBINING(c)) ||
9880		   (IS_EXTENDER(c))) {
9881		if (len + 10 > max) {
9882		    max *= 2;
9883		    buffer = (xmlChar *) xmlRealloc(buffer,
9884			                            max * sizeof(xmlChar));
9885		    if (buffer == NULL) {
9886			XP_ERRORNULL(XPATH_MEMORY_ERROR);
9887		    }
9888		}
9889		COPY_BUF(l,buffer,len,c);
9890		NEXTL(l);
9891		c = CUR_CHAR(l);
9892	    }
9893	    buffer[len] = 0;
9894	    return(buffer);
9895	}
9896    }
9897    if (len == 0)
9898	return(NULL);
9899    return(xmlStrndup(buf, len));
9900}
9901
9902#define MAX_FRAC 20
9903
9904/*
9905 * These are used as divisors for the fractional part of a number.
9906 * Since the table includes 1.0 (representing '0' fractional digits),
9907 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9908 */
9909static double my_pow10[MAX_FRAC+1] = {
9910    1.0, 10.0, 100.0, 1000.0, 10000.0,
9911    100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9912    10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9913    100000000000000.0,
9914    1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9915    1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9916};
9917
9918/**
9919 * xmlXPathStringEvalNumber:
9920 * @str:  A string to scan
9921 *
9922 *  [30a]  Float  ::= Number ('e' Digits?)?
9923 *
9924 *  [30]   Number ::=   Digits ('.' Digits?)?
9925 *                    | '.' Digits
9926 *  [31]   Digits ::=   [0-9]+
9927 *
9928 * Compile a Number in the string
9929 * In complement of the Number expression, this function also handles
9930 * negative values : '-' Number.
9931 *
9932 * Returns the double value.
9933 */
9934double
9935xmlXPathStringEvalNumber(const xmlChar *str) {
9936    const xmlChar *cur = str;
9937    double ret;
9938    int ok = 0;
9939    int isneg = 0;
9940    int exponent = 0;
9941    int is_exponent_negative = 0;
9942#ifdef __GNUC__
9943    unsigned long tmp = 0;
9944    double temp;
9945#endif
9946    if (cur == NULL) return(0);
9947    while (IS_BLANK_CH(*cur)) cur++;
9948    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9949        return(xmlXPathNAN);
9950    }
9951    if (*cur == '-') {
9952	isneg = 1;
9953	cur++;
9954    }
9955
9956#ifdef __GNUC__
9957    /*
9958     * tmp/temp is a workaround against a gcc compiler bug
9959     * http://veillard.com/gcc.bug
9960     */
9961    ret = 0;
9962    while ((*cur >= '0') && (*cur <= '9')) {
9963	ret = ret * 10;
9964	tmp = (*cur - '0');
9965	ok = 1;
9966	cur++;
9967	temp = (double) tmp;
9968	ret = ret + temp;
9969    }
9970#else
9971    ret = 0;
9972    while ((*cur >= '0') && (*cur <= '9')) {
9973	ret = ret * 10 + (*cur - '0');
9974	ok = 1;
9975	cur++;
9976    }
9977#endif
9978
9979    if (*cur == '.') {
9980	int v, frac = 0;
9981	double fraction = 0;
9982
9983        cur++;
9984	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9985	    return(xmlXPathNAN);
9986	}
9987	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9988	    v = (*cur - '0');
9989	    fraction = fraction * 10 + v;
9990	    frac = frac + 1;
9991	    cur++;
9992	}
9993	fraction /= my_pow10[frac];
9994	ret = ret + fraction;
9995	while ((*cur >= '0') && (*cur <= '9'))
9996	    cur++;
9997    }
9998    if ((*cur == 'e') || (*cur == 'E')) {
9999      cur++;
10000      if (*cur == '-') {
10001	is_exponent_negative = 1;
10002	cur++;
10003      } else if (*cur == '+') {
10004        cur++;
10005      }
10006      while ((*cur >= '0') && (*cur <= '9')) {
10007	exponent = exponent * 10 + (*cur - '0');
10008	cur++;
10009      }
10010    }
10011    while (IS_BLANK_CH(*cur)) cur++;
10012    if (*cur != 0) return(xmlXPathNAN);
10013    if (isneg) ret = -ret;
10014    if (is_exponent_negative) exponent = -exponent;
10015    ret *= pow(10.0, (double)exponent);
10016    return(ret);
10017}
10018
10019/**
10020 * xmlXPathCompNumber:
10021 * @ctxt:  the XPath Parser context
10022 *
10023 *  [30]   Number ::=   Digits ('.' Digits?)?
10024 *                    | '.' Digits
10025 *  [31]   Digits ::=   [0-9]+
10026 *
10027 * Compile a Number, then push it on the stack
10028 *
10029 */
10030static void
10031xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10032{
10033    double ret = 0.0;
10034    double mult = 1;
10035    int ok = 0;
10036    int exponent = 0;
10037    int is_exponent_negative = 0;
10038#ifdef __GNUC__
10039    unsigned long tmp = 0;
10040    double temp;
10041#endif
10042
10043    CHECK_ERROR;
10044    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10045        XP_ERROR(XPATH_NUMBER_ERROR);
10046    }
10047#ifdef __GNUC__
10048    /*
10049     * tmp/temp is a workaround against a gcc compiler bug
10050     * http://veillard.com/gcc.bug
10051     */
10052    ret = 0;
10053    while ((CUR >= '0') && (CUR <= '9')) {
10054	ret = ret * 10;
10055	tmp = (CUR - '0');
10056        ok = 1;
10057        NEXT;
10058	temp = (double) tmp;
10059	ret = ret + temp;
10060    }
10061#else
10062    ret = 0;
10063    while ((CUR >= '0') && (CUR <= '9')) {
10064	ret = ret * 10 + (CUR - '0');
10065	ok = 1;
10066	NEXT;
10067    }
10068#endif
10069    if (CUR == '.') {
10070        NEXT;
10071        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10072            XP_ERROR(XPATH_NUMBER_ERROR);
10073        }
10074        while ((CUR >= '0') && (CUR <= '9')) {
10075            mult /= 10;
10076            ret = ret + (CUR - '0') * mult;
10077            NEXT;
10078        }
10079    }
10080    if ((CUR == 'e') || (CUR == 'E')) {
10081        NEXT;
10082        if (CUR == '-') {
10083            is_exponent_negative = 1;
10084            NEXT;
10085        } else if (CUR == '+') {
10086	    NEXT;
10087	}
10088        while ((CUR >= '0') && (CUR <= '9')) {
10089            exponent = exponent * 10 + (CUR - '0');
10090            NEXT;
10091        }
10092        if (is_exponent_negative)
10093            exponent = -exponent;
10094        ret *= pow(10.0, (double) exponent);
10095    }
10096    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10097                   xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10098}
10099
10100/**
10101 * xmlXPathParseLiteral:
10102 * @ctxt:  the XPath Parser context
10103 *
10104 * Parse a Literal
10105 *
10106 *  [29]   Literal ::=   '"' [^"]* '"'
10107 *                    | "'" [^']* "'"
10108 *
10109 * Returns the value found or NULL in case of error
10110 */
10111static xmlChar *
10112xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10113    const xmlChar *q;
10114    xmlChar *ret = NULL;
10115
10116    if (CUR == '"') {
10117        NEXT;
10118	q = CUR_PTR;
10119	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10120	    NEXT;
10121	if (!IS_CHAR_CH(CUR)) {
10122	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10123	} else {
10124	    ret = xmlStrndup(q, CUR_PTR - q);
10125	    NEXT;
10126        }
10127    } else if (CUR == '\'') {
10128        NEXT;
10129	q = CUR_PTR;
10130	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10131	    NEXT;
10132	if (!IS_CHAR_CH(CUR)) {
10133	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10134	} else {
10135	    ret = xmlStrndup(q, CUR_PTR - q);
10136	    NEXT;
10137        }
10138    } else {
10139	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10140    }
10141    return(ret);
10142}
10143
10144/**
10145 * xmlXPathCompLiteral:
10146 * @ctxt:  the XPath Parser context
10147 *
10148 * Parse a Literal and push it on the stack.
10149 *
10150 *  [29]   Literal ::=   '"' [^"]* '"'
10151 *                    | "'" [^']* "'"
10152 *
10153 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10154 */
10155static void
10156xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10157    const xmlChar *q;
10158    xmlChar *ret = NULL;
10159
10160    if (CUR == '"') {
10161        NEXT;
10162	q = CUR_PTR;
10163	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10164	    NEXT;
10165	if (!IS_CHAR_CH(CUR)) {
10166	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10167	} else {
10168	    ret = xmlStrndup(q, CUR_PTR - q);
10169	    NEXT;
10170        }
10171    } else if (CUR == '\'') {
10172        NEXT;
10173	q = CUR_PTR;
10174	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10175	    NEXT;
10176	if (!IS_CHAR_CH(CUR)) {
10177	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10178	} else {
10179	    ret = xmlStrndup(q, CUR_PTR - q);
10180	    NEXT;
10181        }
10182    } else {
10183	XP_ERROR(XPATH_START_LITERAL_ERROR);
10184    }
10185    if (ret == NULL) return;
10186    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10187	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10188    xmlFree(ret);
10189}
10190
10191/**
10192 * xmlXPathCompVariableReference:
10193 * @ctxt:  the XPath Parser context
10194 *
10195 * Parse a VariableReference, evaluate it and push it on the stack.
10196 *
10197 * The variable bindings consist of a mapping from variable names
10198 * to variable values. The value of a variable is an object, which can be
10199 * of any of the types that are possible for the value of an expression,
10200 * and may also be of additional types not specified here.
10201 *
10202 * Early evaluation is possible since:
10203 * The variable bindings [...] used to evaluate a subexpression are
10204 * always the same as those used to evaluate the containing expression.
10205 *
10206 *  [36]   VariableReference ::=   '$' QName
10207 */
10208static void
10209xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10210    xmlChar *name;
10211    xmlChar *prefix;
10212
10213    SKIP_BLANKS;
10214    if (CUR != '$') {
10215	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10216    }
10217    NEXT;
10218    name = xmlXPathParseQName(ctxt, &prefix);
10219    if (name == NULL) {
10220	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10221    }
10222    ctxt->comp->last = -1;
10223    PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10224	           name, prefix);
10225    SKIP_BLANKS;
10226    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10227	XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10228    }
10229}
10230
10231/**
10232 * xmlXPathIsNodeType:
10233 * @name:  a name string
10234 *
10235 * Is the name given a NodeType one.
10236 *
10237 *  [38]   NodeType ::=   'comment'
10238 *                    | 'text'
10239 *                    | 'processing-instruction'
10240 *                    | 'node'
10241 *
10242 * Returns 1 if true 0 otherwise
10243 */
10244int
10245xmlXPathIsNodeType(const xmlChar *name) {
10246    if (name == NULL)
10247	return(0);
10248
10249    if (xmlStrEqual(name, BAD_CAST "node"))
10250	return(1);
10251    if (xmlStrEqual(name, BAD_CAST "text"))
10252	return(1);
10253    if (xmlStrEqual(name, BAD_CAST "comment"))
10254	return(1);
10255    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10256	return(1);
10257    return(0);
10258}
10259
10260/**
10261 * xmlXPathCompFunctionCall:
10262 * @ctxt:  the XPath Parser context
10263 *
10264 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10265 *  [17]   Argument ::=   Expr
10266 *
10267 * Compile a function call, the evaluation of all arguments are
10268 * pushed on the stack
10269 */
10270static void
10271xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10272    xmlChar *name;
10273    xmlChar *prefix;
10274    int nbargs = 0;
10275    int sort = 1;
10276
10277    name = xmlXPathParseQName(ctxt, &prefix);
10278    if (name == NULL) {
10279	xmlFree(prefix);
10280	XP_ERROR(XPATH_EXPR_ERROR);
10281    }
10282    SKIP_BLANKS;
10283#ifdef DEBUG_EXPR
10284    if (prefix == NULL)
10285	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10286			name);
10287    else
10288	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10289			prefix, name);
10290#endif
10291
10292    if (CUR != '(') {
10293	XP_ERROR(XPATH_EXPR_ERROR);
10294    }
10295    NEXT;
10296    SKIP_BLANKS;
10297
10298    /*
10299    * Optimization for count(): we don't need the node-set to be sorted.
10300    */
10301    if ((prefix == NULL) && (name[0] == 'c') &&
10302	xmlStrEqual(name, BAD_CAST "count"))
10303    {
10304	sort = 0;
10305    }
10306    ctxt->comp->last = -1;
10307    if (CUR != ')') {
10308	while (CUR != 0) {
10309	    int op1 = ctxt->comp->last;
10310	    ctxt->comp->last = -1;
10311	    xmlXPathCompileExpr(ctxt, sort);
10312	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10313		xmlFree(name);
10314		xmlFree(prefix);
10315		return;
10316	    }
10317	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10318	    nbargs++;
10319	    if (CUR == ')') break;
10320	    if (CUR != ',') {
10321		XP_ERROR(XPATH_EXPR_ERROR);
10322	    }
10323	    NEXT;
10324	    SKIP_BLANKS;
10325	}
10326    }
10327    PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10328	           name, prefix);
10329    NEXT;
10330    SKIP_BLANKS;
10331}
10332
10333/**
10334 * xmlXPathCompPrimaryExpr:
10335 * @ctxt:  the XPath Parser context
10336 *
10337 *  [15]   PrimaryExpr ::=   VariableReference
10338 *                | '(' Expr ')'
10339 *                | Literal
10340 *                | Number
10341 *                | FunctionCall
10342 *
10343 * Compile a primary expression.
10344 */
10345static void
10346xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10347    SKIP_BLANKS;
10348    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10349    else if (CUR == '(') {
10350	NEXT;
10351	SKIP_BLANKS;
10352	xmlXPathCompileExpr(ctxt, 1);
10353	CHECK_ERROR;
10354	if (CUR != ')') {
10355	    XP_ERROR(XPATH_EXPR_ERROR);
10356	}
10357	NEXT;
10358	SKIP_BLANKS;
10359    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10360	xmlXPathCompNumber(ctxt);
10361    } else if ((CUR == '\'') || (CUR == '"')) {
10362	xmlXPathCompLiteral(ctxt);
10363    } else {
10364	xmlXPathCompFunctionCall(ctxt);
10365    }
10366    SKIP_BLANKS;
10367}
10368
10369/**
10370 * xmlXPathCompFilterExpr:
10371 * @ctxt:  the XPath Parser context
10372 *
10373 *  [20]   FilterExpr ::=   PrimaryExpr
10374 *               | FilterExpr Predicate
10375 *
10376 * Compile a filter expression.
10377 * Square brackets are used to filter expressions in the same way that
10378 * they are used in location paths. It is an error if the expression to
10379 * be filtered does not evaluate to a node-set. The context node list
10380 * used for evaluating the expression in square brackets is the node-set
10381 * to be filtered listed in document order.
10382 */
10383
10384static void
10385xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10386    xmlXPathCompPrimaryExpr(ctxt);
10387    CHECK_ERROR;
10388    SKIP_BLANKS;
10389
10390    while (CUR == '[') {
10391	xmlXPathCompPredicate(ctxt, 1);
10392	SKIP_BLANKS;
10393    }
10394
10395
10396}
10397
10398/**
10399 * xmlXPathScanName:
10400 * @ctxt:  the XPath Parser context
10401 *
10402 * Trickery: parse an XML name but without consuming the input flow
10403 * Needed to avoid insanity in the parser state.
10404 *
10405 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10406 *                  CombiningChar | Extender
10407 *
10408 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10409 *
10410 * [6] Names ::= Name (S Name)*
10411 *
10412 * Returns the Name parsed or NULL
10413 */
10414
10415static xmlChar *
10416xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10417    int len = 0, l;
10418    int c;
10419    const xmlChar *cur;
10420    xmlChar *ret;
10421
10422    cur = ctxt->cur;
10423
10424    c = CUR_CHAR(l);
10425    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10426	(!IS_LETTER(c) && (c != '_') &&
10427         (c != ':'))) {
10428	return(NULL);
10429    }
10430
10431    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10432	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10433            (c == '.') || (c == '-') ||
10434	    (c == '_') || (c == ':') ||
10435	    (IS_COMBINING(c)) ||
10436	    (IS_EXTENDER(c)))) {
10437	len += l;
10438	NEXTL(l);
10439	c = CUR_CHAR(l);
10440    }
10441    ret = xmlStrndup(cur, ctxt->cur - cur);
10442    ctxt->cur = cur;
10443    return(ret);
10444}
10445
10446/**
10447 * xmlXPathCompPathExpr:
10448 * @ctxt:  the XPath Parser context
10449 *
10450 *  [19]   PathExpr ::=   LocationPath
10451 *               | FilterExpr
10452 *               | FilterExpr '/' RelativeLocationPath
10453 *               | FilterExpr '//' RelativeLocationPath
10454 *
10455 * Compile a path expression.
10456 * The / operator and // operators combine an arbitrary expression
10457 * and a relative location path. It is an error if the expression
10458 * does not evaluate to a node-set.
10459 * The / operator does composition in the same way as when / is
10460 * used in a location path. As in location paths, // is short for
10461 * /descendant-or-self::node()/.
10462 */
10463
10464static void
10465xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10466    int lc = 1;           /* Should we branch to LocationPath ?         */
10467    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10468
10469    SKIP_BLANKS;
10470    if ((CUR == '$') || (CUR == '(') ||
10471	(IS_ASCII_DIGIT(CUR)) ||
10472        (CUR == '\'') || (CUR == '"') ||
10473	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10474	lc = 0;
10475    } else if (CUR == '*') {
10476	/* relative or absolute location path */
10477	lc = 1;
10478    } else if (CUR == '/') {
10479	/* relative or absolute location path */
10480	lc = 1;
10481    } else if (CUR == '@') {
10482	/* relative abbreviated attribute location path */
10483	lc = 1;
10484    } else if (CUR == '.') {
10485	/* relative abbreviated attribute location path */
10486	lc = 1;
10487    } else {
10488	/*
10489	 * Problem is finding if we have a name here whether it's:
10490	 *   - a nodetype
10491	 *   - a function call in which case it's followed by '('
10492	 *   - an axis in which case it's followed by ':'
10493	 *   - a element name
10494	 * We do an a priori analysis here rather than having to
10495	 * maintain parsed token content through the recursive function
10496	 * calls. This looks uglier but makes the code easier to
10497	 * read/write/debug.
10498	 */
10499	SKIP_BLANKS;
10500	name = xmlXPathScanName(ctxt);
10501	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10502#ifdef DEBUG_STEP
10503	    xmlGenericError(xmlGenericErrorContext,
10504		    "PathExpr: Axis\n");
10505#endif
10506	    lc = 1;
10507	    xmlFree(name);
10508	} else if (name != NULL) {
10509	    int len =xmlStrlen(name);
10510
10511
10512	    while (NXT(len) != 0) {
10513		if (NXT(len) == '/') {
10514		    /* element name */
10515#ifdef DEBUG_STEP
10516		    xmlGenericError(xmlGenericErrorContext,
10517			    "PathExpr: AbbrRelLocation\n");
10518#endif
10519		    lc = 1;
10520		    break;
10521		} else if (IS_BLANK_CH(NXT(len))) {
10522		    /* ignore blanks */
10523		    ;
10524		} else if (NXT(len) == ':') {
10525#ifdef DEBUG_STEP
10526		    xmlGenericError(xmlGenericErrorContext,
10527			    "PathExpr: AbbrRelLocation\n");
10528#endif
10529		    lc = 1;
10530		    break;
10531		} else if ((NXT(len) == '(')) {
10532		    /* Note Type or Function */
10533		    if (xmlXPathIsNodeType(name)) {
10534#ifdef DEBUG_STEP
10535		        xmlGenericError(xmlGenericErrorContext,
10536				"PathExpr: Type search\n");
10537#endif
10538			lc = 1;
10539		    } else {
10540#ifdef DEBUG_STEP
10541		        xmlGenericError(xmlGenericErrorContext,
10542				"PathExpr: function call\n");
10543#endif
10544			lc = 0;
10545		    }
10546                    break;
10547		} else if ((NXT(len) == '[')) {
10548		    /* element name */
10549#ifdef DEBUG_STEP
10550		    xmlGenericError(xmlGenericErrorContext,
10551			    "PathExpr: AbbrRelLocation\n");
10552#endif
10553		    lc = 1;
10554		    break;
10555		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10556			   (NXT(len) == '=')) {
10557		    lc = 1;
10558		    break;
10559		} else {
10560		    lc = 1;
10561		    break;
10562		}
10563		len++;
10564	    }
10565	    if (NXT(len) == 0) {
10566#ifdef DEBUG_STEP
10567		xmlGenericError(xmlGenericErrorContext,
10568			"PathExpr: AbbrRelLocation\n");
10569#endif
10570		/* element name */
10571		lc = 1;
10572	    }
10573	    xmlFree(name);
10574	} else {
10575	    /* make sure all cases are covered explicitly */
10576	    XP_ERROR(XPATH_EXPR_ERROR);
10577	}
10578    }
10579
10580    if (lc) {
10581	if (CUR == '/') {
10582	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10583	} else {
10584	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10585	}
10586	xmlXPathCompLocationPath(ctxt);
10587    } else {
10588	xmlXPathCompFilterExpr(ctxt);
10589	CHECK_ERROR;
10590	if ((CUR == '/') && (NXT(1) == '/')) {
10591	    SKIP(2);
10592	    SKIP_BLANKS;
10593
10594	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10595		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10596	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10597
10598	    xmlXPathCompRelativeLocationPath(ctxt);
10599	} else if (CUR == '/') {
10600	    xmlXPathCompRelativeLocationPath(ctxt);
10601	}
10602    }
10603    SKIP_BLANKS;
10604}
10605
10606/**
10607 * xmlXPathCompUnionExpr:
10608 * @ctxt:  the XPath Parser context
10609 *
10610 *  [18]   UnionExpr ::=   PathExpr
10611 *               | UnionExpr '|' PathExpr
10612 *
10613 * Compile an union expression.
10614 */
10615
10616static void
10617xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10618    xmlXPathCompPathExpr(ctxt);
10619    CHECK_ERROR;
10620    SKIP_BLANKS;
10621    while (CUR == '|') {
10622	int op1 = ctxt->comp->last;
10623	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10624
10625	NEXT;
10626	SKIP_BLANKS;
10627	xmlXPathCompPathExpr(ctxt);
10628
10629	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10630
10631	SKIP_BLANKS;
10632    }
10633}
10634
10635/**
10636 * xmlXPathCompUnaryExpr:
10637 * @ctxt:  the XPath Parser context
10638 *
10639 *  [27]   UnaryExpr ::=   UnionExpr
10640 *                   | '-' UnaryExpr
10641 *
10642 * Compile an unary expression.
10643 */
10644
10645static void
10646xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10647    int minus = 0;
10648    int found = 0;
10649
10650    SKIP_BLANKS;
10651    while (CUR == '-') {
10652        minus = 1 - minus;
10653	found = 1;
10654	NEXT;
10655	SKIP_BLANKS;
10656    }
10657
10658    xmlXPathCompUnionExpr(ctxt);
10659    CHECK_ERROR;
10660    if (found) {
10661	if (minus)
10662	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10663	else
10664	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10665    }
10666}
10667
10668/**
10669 * xmlXPathCompMultiplicativeExpr:
10670 * @ctxt:  the XPath Parser context
10671 *
10672 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10673 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10674 *                   | MultiplicativeExpr 'div' UnaryExpr
10675 *                   | MultiplicativeExpr 'mod' UnaryExpr
10676 *  [34]   MultiplyOperator ::=   '*'
10677 *
10678 * Compile an Additive expression.
10679 */
10680
10681static void
10682xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10683    xmlXPathCompUnaryExpr(ctxt);
10684    CHECK_ERROR;
10685    SKIP_BLANKS;
10686    while ((CUR == '*') ||
10687           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10688           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10689	int op = -1;
10690	int op1 = ctxt->comp->last;
10691
10692        if (CUR == '*') {
10693	    op = 0;
10694	    NEXT;
10695	} else if (CUR == 'd') {
10696	    op = 1;
10697	    SKIP(3);
10698	} else if (CUR == 'm') {
10699	    op = 2;
10700	    SKIP(3);
10701	}
10702	SKIP_BLANKS;
10703        xmlXPathCompUnaryExpr(ctxt);
10704	CHECK_ERROR;
10705	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10706	SKIP_BLANKS;
10707    }
10708}
10709
10710/**
10711 * xmlXPathCompAdditiveExpr:
10712 * @ctxt:  the XPath Parser context
10713 *
10714 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10715 *                   | AdditiveExpr '+' MultiplicativeExpr
10716 *                   | AdditiveExpr '-' MultiplicativeExpr
10717 *
10718 * Compile an Additive expression.
10719 */
10720
10721static void
10722xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10723
10724    xmlXPathCompMultiplicativeExpr(ctxt);
10725    CHECK_ERROR;
10726    SKIP_BLANKS;
10727    while ((CUR == '+') || (CUR == '-')) {
10728	int plus;
10729	int op1 = ctxt->comp->last;
10730
10731        if (CUR == '+') plus = 1;
10732	else plus = 0;
10733	NEXT;
10734	SKIP_BLANKS;
10735        xmlXPathCompMultiplicativeExpr(ctxt);
10736	CHECK_ERROR;
10737	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10738	SKIP_BLANKS;
10739    }
10740}
10741
10742/**
10743 * xmlXPathCompRelationalExpr:
10744 * @ctxt:  the XPath Parser context
10745 *
10746 *  [24]   RelationalExpr ::=   AdditiveExpr
10747 *                 | RelationalExpr '<' AdditiveExpr
10748 *                 | RelationalExpr '>' AdditiveExpr
10749 *                 | RelationalExpr '<=' AdditiveExpr
10750 *                 | RelationalExpr '>=' AdditiveExpr
10751 *
10752 *  A <= B > C is allowed ? Answer from James, yes with
10753 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10754 *  which is basically what got implemented.
10755 *
10756 * Compile a Relational expression, then push the result
10757 * on the stack
10758 */
10759
10760static void
10761xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10762    xmlXPathCompAdditiveExpr(ctxt);
10763    CHECK_ERROR;
10764    SKIP_BLANKS;
10765    while ((CUR == '<') ||
10766           (CUR == '>') ||
10767           ((CUR == '<') && (NXT(1) == '=')) ||
10768           ((CUR == '>') && (NXT(1) == '='))) {
10769	int inf, strict;
10770	int op1 = ctxt->comp->last;
10771
10772        if (CUR == '<') inf = 1;
10773	else inf = 0;
10774	if (NXT(1) == '=') strict = 0;
10775	else strict = 1;
10776	NEXT;
10777	if (!strict) NEXT;
10778	SKIP_BLANKS;
10779        xmlXPathCompAdditiveExpr(ctxt);
10780	CHECK_ERROR;
10781	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10782	SKIP_BLANKS;
10783    }
10784}
10785
10786/**
10787 * xmlXPathCompEqualityExpr:
10788 * @ctxt:  the XPath Parser context
10789 *
10790 *  [23]   EqualityExpr ::=   RelationalExpr
10791 *                 | EqualityExpr '=' RelationalExpr
10792 *                 | EqualityExpr '!=' RelationalExpr
10793 *
10794 *  A != B != C is allowed ? Answer from James, yes with
10795 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10796 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10797 *  which is basically what got implemented.
10798 *
10799 * Compile an Equality expression.
10800 *
10801 */
10802static void
10803xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10804    xmlXPathCompRelationalExpr(ctxt);
10805    CHECK_ERROR;
10806    SKIP_BLANKS;
10807    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10808	int eq;
10809	int op1 = ctxt->comp->last;
10810
10811        if (CUR == '=') eq = 1;
10812	else eq = 0;
10813	NEXT;
10814	if (!eq) NEXT;
10815	SKIP_BLANKS;
10816        xmlXPathCompRelationalExpr(ctxt);
10817	CHECK_ERROR;
10818	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10819	SKIP_BLANKS;
10820    }
10821}
10822
10823/**
10824 * xmlXPathCompAndExpr:
10825 * @ctxt:  the XPath Parser context
10826 *
10827 *  [22]   AndExpr ::=   EqualityExpr
10828 *                 | AndExpr 'and' EqualityExpr
10829 *
10830 * Compile an AND expression.
10831 *
10832 */
10833static void
10834xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10835    xmlXPathCompEqualityExpr(ctxt);
10836    CHECK_ERROR;
10837    SKIP_BLANKS;
10838    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10839	int op1 = ctxt->comp->last;
10840        SKIP(3);
10841	SKIP_BLANKS;
10842        xmlXPathCompEqualityExpr(ctxt);
10843	CHECK_ERROR;
10844	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10845	SKIP_BLANKS;
10846    }
10847}
10848
10849/**
10850 * xmlXPathCompileExpr:
10851 * @ctxt:  the XPath Parser context
10852 *
10853 *  [14]   Expr ::=   OrExpr
10854 *  [21]   OrExpr ::=   AndExpr
10855 *                 | OrExpr 'or' AndExpr
10856 *
10857 * Parse and compile an expression
10858 */
10859static void
10860xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10861    xmlXPathCompAndExpr(ctxt);
10862    CHECK_ERROR;
10863    SKIP_BLANKS;
10864    while ((CUR == 'o') && (NXT(1) == 'r')) {
10865	int op1 = ctxt->comp->last;
10866        SKIP(2);
10867	SKIP_BLANKS;
10868        xmlXPathCompAndExpr(ctxt);
10869	CHECK_ERROR;
10870	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10871	SKIP_BLANKS;
10872    }
10873    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10874	/* more ops could be optimized too */
10875	/*
10876	* This is the main place to eliminate sorting for
10877	* operations which don't require a sorted node-set.
10878	* E.g. count().
10879	*/
10880	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10881    }
10882}
10883
10884/**
10885 * xmlXPathCompPredicate:
10886 * @ctxt:  the XPath Parser context
10887 * @filter:  act as a filter
10888 *
10889 *  [8]   Predicate ::=   '[' PredicateExpr ']'
10890 *  [9]   PredicateExpr ::=   Expr
10891 *
10892 * Compile a predicate expression
10893 */
10894static void
10895xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10896    int op1 = ctxt->comp->last;
10897
10898    SKIP_BLANKS;
10899    if (CUR != '[') {
10900	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10901    }
10902    NEXT;
10903    SKIP_BLANKS;
10904
10905    ctxt->comp->last = -1;
10906    /*
10907    * This call to xmlXPathCompileExpr() will deactivate sorting
10908    * of the predicate result.
10909    * TODO: Sorting is still activated for filters, since I'm not
10910    *  sure if needed. Normally sorting should not be needed, since
10911    *  a filter can only diminish the number of items in a sequence,
10912    *  but won't change its order; so if the initial sequence is sorted,
10913    *  subsequent sorting is not needed.
10914    */
10915    if (! filter)
10916	xmlXPathCompileExpr(ctxt, 0);
10917    else
10918	xmlXPathCompileExpr(ctxt, 1);
10919    CHECK_ERROR;
10920
10921    if (CUR != ']') {
10922	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10923    }
10924
10925    if (filter)
10926	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10927    else
10928	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10929
10930    NEXT;
10931    SKIP_BLANKS;
10932}
10933
10934/**
10935 * xmlXPathCompNodeTest:
10936 * @ctxt:  the XPath Parser context
10937 * @test:  pointer to a xmlXPathTestVal
10938 * @type:  pointer to a xmlXPathTypeVal
10939 * @prefix:  placeholder for a possible name prefix
10940 *
10941 * [7] NodeTest ::=   NameTest
10942 *		    | NodeType '(' ')'
10943 *		    | 'processing-instruction' '(' Literal ')'
10944 *
10945 * [37] NameTest ::=  '*'
10946 *		    | NCName ':' '*'
10947 *		    | QName
10948 * [38] NodeType ::= 'comment'
10949 *		   | 'text'
10950 *		   | 'processing-instruction'
10951 *		   | 'node'
10952 *
10953 * Returns the name found and updates @test, @type and @prefix appropriately
10954 */
10955static xmlChar *
10956xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10957	             xmlXPathTypeVal *type, const xmlChar **prefix,
10958		     xmlChar *name) {
10959    int blanks;
10960
10961    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10962	STRANGE;
10963	return(NULL);
10964    }
10965    *type = (xmlXPathTypeVal) 0;
10966    *test = (xmlXPathTestVal) 0;
10967    *prefix = NULL;
10968    SKIP_BLANKS;
10969
10970    if ((name == NULL) && (CUR == '*')) {
10971	/*
10972	 * All elements
10973	 */
10974	NEXT;
10975	*test = NODE_TEST_ALL;
10976	return(NULL);
10977    }
10978
10979    if (name == NULL)
10980	name = xmlXPathParseNCName(ctxt);
10981    if (name == NULL) {
10982	XP_ERRORNULL(XPATH_EXPR_ERROR);
10983    }
10984
10985    blanks = IS_BLANK_CH(CUR);
10986    SKIP_BLANKS;
10987    if (CUR == '(') {
10988	NEXT;
10989	/*
10990	 * NodeType or PI search
10991	 */
10992	if (xmlStrEqual(name, BAD_CAST "comment"))
10993	    *type = NODE_TYPE_COMMENT;
10994	else if (xmlStrEqual(name, BAD_CAST "node"))
10995	    *type = NODE_TYPE_NODE;
10996	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10997	    *type = NODE_TYPE_PI;
10998	else if (xmlStrEqual(name, BAD_CAST "text"))
10999	    *type = NODE_TYPE_TEXT;
11000	else {
11001	    if (name != NULL)
11002		xmlFree(name);
11003	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11004	}
11005
11006	*test = NODE_TEST_TYPE;
11007
11008	SKIP_BLANKS;
11009	if (*type == NODE_TYPE_PI) {
11010	    /*
11011	     * Specific case: search a PI by name.
11012	     */
11013	    if (name != NULL)
11014		xmlFree(name);
11015	    name = NULL;
11016	    if (CUR != ')') {
11017		name = xmlXPathParseLiteral(ctxt);
11018		CHECK_ERROR NULL;
11019		*test = NODE_TEST_PI;
11020		SKIP_BLANKS;
11021	    }
11022	}
11023	if (CUR != ')') {
11024	    if (name != NULL)
11025		xmlFree(name);
11026	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11027	}
11028	NEXT;
11029	return(name);
11030    }
11031    *test = NODE_TEST_NAME;
11032    if ((!blanks) && (CUR == ':')) {
11033	NEXT;
11034
11035	/*
11036	 * Since currently the parser context don't have a
11037	 * namespace list associated:
11038	 * The namespace name for this prefix can be computed
11039	 * only at evaluation time. The compilation is done
11040	 * outside of any context.
11041	 */
11042#if 0
11043	*prefix = xmlXPathNsLookup(ctxt->context, name);
11044	if (name != NULL)
11045	    xmlFree(name);
11046	if (*prefix == NULL) {
11047	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11048	}
11049#else
11050	*prefix = name;
11051#endif
11052
11053	if (CUR == '*') {
11054	    /*
11055	     * All elements
11056	     */
11057	    NEXT;
11058	    *test = NODE_TEST_ALL;
11059	    return(NULL);
11060	}
11061
11062	name = xmlXPathParseNCName(ctxt);
11063	if (name == NULL) {
11064	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11065	}
11066    }
11067    return(name);
11068}
11069
11070/**
11071 * xmlXPathIsAxisName:
11072 * @name:  a preparsed name token
11073 *
11074 * [6] AxisName ::=   'ancestor'
11075 *                  | 'ancestor-or-self'
11076 *                  | 'attribute'
11077 *                  | 'child'
11078 *                  | 'descendant'
11079 *                  | 'descendant-or-self'
11080 *                  | 'following'
11081 *                  | 'following-sibling'
11082 *                  | 'namespace'
11083 *                  | 'parent'
11084 *                  | 'preceding'
11085 *                  | 'preceding-sibling'
11086 *                  | 'self'
11087 *
11088 * Returns the axis or 0
11089 */
11090static xmlXPathAxisVal
11091xmlXPathIsAxisName(const xmlChar *name) {
11092    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11093    switch (name[0]) {
11094	case 'a':
11095	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11096		ret = AXIS_ANCESTOR;
11097	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11098		ret = AXIS_ANCESTOR_OR_SELF;
11099	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11100		ret = AXIS_ATTRIBUTE;
11101	    break;
11102	case 'c':
11103	    if (xmlStrEqual(name, BAD_CAST "child"))
11104		ret = AXIS_CHILD;
11105	    break;
11106	case 'd':
11107	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11108		ret = AXIS_DESCENDANT;
11109	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11110		ret = AXIS_DESCENDANT_OR_SELF;
11111	    break;
11112	case 'f':
11113	    if (xmlStrEqual(name, BAD_CAST "following"))
11114		ret = AXIS_FOLLOWING;
11115	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11116		ret = AXIS_FOLLOWING_SIBLING;
11117	    break;
11118	case 'n':
11119	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11120		ret = AXIS_NAMESPACE;
11121	    break;
11122	case 'p':
11123	    if (xmlStrEqual(name, BAD_CAST "parent"))
11124		ret = AXIS_PARENT;
11125	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11126		ret = AXIS_PRECEDING;
11127	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11128		ret = AXIS_PRECEDING_SIBLING;
11129	    break;
11130	case 's':
11131	    if (xmlStrEqual(name, BAD_CAST "self"))
11132		ret = AXIS_SELF;
11133	    break;
11134    }
11135    return(ret);
11136}
11137
11138/**
11139 * xmlXPathCompStep:
11140 * @ctxt:  the XPath Parser context
11141 *
11142 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11143 *                  | AbbreviatedStep
11144 *
11145 * [12] AbbreviatedStep ::=   '.' | '..'
11146 *
11147 * [5] AxisSpecifier ::= AxisName '::'
11148 *                  | AbbreviatedAxisSpecifier
11149 *
11150 * [13] AbbreviatedAxisSpecifier ::= '@'?
11151 *
11152 * Modified for XPtr range support as:
11153 *
11154 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11155 *                     | AbbreviatedStep
11156 *                     | 'range-to' '(' Expr ')' Predicate*
11157 *
11158 * Compile one step in a Location Path
11159 * A location step of . is short for self::node(). This is
11160 * particularly useful in conjunction with //. For example, the
11161 * location path .//para is short for
11162 * self::node()/descendant-or-self::node()/child::para
11163 * and so will select all para descendant elements of the context
11164 * node.
11165 * Similarly, a location step of .. is short for parent::node().
11166 * For example, ../title is short for parent::node()/child::title
11167 * and so will select the title children of the parent of the context
11168 * node.
11169 */
11170static void
11171xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11172#ifdef LIBXML_XPTR_ENABLED
11173    int rangeto = 0;
11174    int op2 = -1;
11175#endif
11176
11177    SKIP_BLANKS;
11178    if ((CUR == '.') && (NXT(1) == '.')) {
11179	SKIP(2);
11180	SKIP_BLANKS;
11181	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11182		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11183    } else if (CUR == '.') {
11184	NEXT;
11185	SKIP_BLANKS;
11186    } else {
11187	xmlChar *name = NULL;
11188	const xmlChar *prefix = NULL;
11189	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11190	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11191	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11192	int op1;
11193
11194	/*
11195	 * The modification needed for XPointer change to the production
11196	 */
11197#ifdef LIBXML_XPTR_ENABLED
11198	if (ctxt->xptr) {
11199	    name = xmlXPathParseNCName(ctxt);
11200	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11201                op2 = ctxt->comp->last;
11202		xmlFree(name);
11203		SKIP_BLANKS;
11204		if (CUR != '(') {
11205		    XP_ERROR(XPATH_EXPR_ERROR);
11206		}
11207		NEXT;
11208		SKIP_BLANKS;
11209
11210		xmlXPathCompileExpr(ctxt, 1);
11211		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11212		CHECK_ERROR;
11213
11214		SKIP_BLANKS;
11215		if (CUR != ')') {
11216		    XP_ERROR(XPATH_EXPR_ERROR);
11217		}
11218		NEXT;
11219		rangeto = 1;
11220		goto eval_predicates;
11221	    }
11222	}
11223#endif
11224	if (CUR == '*') {
11225	    axis = AXIS_CHILD;
11226	} else {
11227	    if (name == NULL)
11228		name = xmlXPathParseNCName(ctxt);
11229	    if (name != NULL) {
11230		axis = xmlXPathIsAxisName(name);
11231		if (axis != 0) {
11232		    SKIP_BLANKS;
11233		    if ((CUR == ':') && (NXT(1) == ':')) {
11234			SKIP(2);
11235			xmlFree(name);
11236			name = NULL;
11237		    } else {
11238			/* an element name can conflict with an axis one :-\ */
11239			axis = AXIS_CHILD;
11240		    }
11241		} else {
11242		    axis = AXIS_CHILD;
11243		}
11244	    } else if (CUR == '@') {
11245		NEXT;
11246		axis = AXIS_ATTRIBUTE;
11247	    } else {
11248		axis = AXIS_CHILD;
11249	    }
11250	}
11251
11252	CHECK_ERROR;
11253
11254	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11255	if (test == 0)
11256	    return;
11257
11258        if ((prefix != NULL) && (ctxt->context != NULL) &&
11259	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11260	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11261		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11262	    }
11263	}
11264#ifdef DEBUG_STEP
11265	xmlGenericError(xmlGenericErrorContext,
11266		"Basis : computing new set\n");
11267#endif
11268
11269#ifdef DEBUG_STEP
11270	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11271	if (ctxt->value == NULL)
11272	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11273	else if (ctxt->value->nodesetval == NULL)
11274	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11275	else
11276	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11277#endif
11278
11279#ifdef LIBXML_XPTR_ENABLED
11280eval_predicates:
11281#endif
11282	op1 = ctxt->comp->last;
11283	ctxt->comp->last = -1;
11284
11285	SKIP_BLANKS;
11286	while (CUR == '[') {
11287	    xmlXPathCompPredicate(ctxt, 0);
11288	}
11289
11290#ifdef LIBXML_XPTR_ENABLED
11291	if (rangeto) {
11292	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11293	} else
11294#endif
11295	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11296			   test, type, (void *)prefix, (void *)name);
11297
11298    }
11299#ifdef DEBUG_STEP
11300    xmlGenericError(xmlGenericErrorContext, "Step : ");
11301    if (ctxt->value == NULL)
11302	xmlGenericError(xmlGenericErrorContext, "no value\n");
11303    else if (ctxt->value->nodesetval == NULL)
11304	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11305    else
11306	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11307		ctxt->value->nodesetval);
11308#endif
11309}
11310
11311/**
11312 * xmlXPathCompRelativeLocationPath:
11313 * @ctxt:  the XPath Parser context
11314 *
11315 *  [3]   RelativeLocationPath ::=   Step
11316 *                     | RelativeLocationPath '/' Step
11317 *                     | AbbreviatedRelativeLocationPath
11318 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11319 *
11320 * Compile a relative location path.
11321 */
11322static void
11323xmlXPathCompRelativeLocationPath
11324(xmlXPathParserContextPtr ctxt) {
11325    SKIP_BLANKS;
11326    if ((CUR == '/') && (NXT(1) == '/')) {
11327	SKIP(2);
11328	SKIP_BLANKS;
11329	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11330		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11331    } else if (CUR == '/') {
11332	    NEXT;
11333	SKIP_BLANKS;
11334    }
11335    xmlXPathCompStep(ctxt);
11336    CHECK_ERROR;
11337    SKIP_BLANKS;
11338    while (CUR == '/') {
11339	if ((CUR == '/') && (NXT(1) == '/')) {
11340	    SKIP(2);
11341	    SKIP_BLANKS;
11342	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11343			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11344	    xmlXPathCompStep(ctxt);
11345	} else if (CUR == '/') {
11346	    NEXT;
11347	    SKIP_BLANKS;
11348	    xmlXPathCompStep(ctxt);
11349	}
11350	SKIP_BLANKS;
11351    }
11352}
11353
11354/**
11355 * xmlXPathCompLocationPath:
11356 * @ctxt:  the XPath Parser context
11357 *
11358 *  [1]   LocationPath ::=   RelativeLocationPath
11359 *                     | AbsoluteLocationPath
11360 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11361 *                     | AbbreviatedAbsoluteLocationPath
11362 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11363 *                           '//' RelativeLocationPath
11364 *
11365 * Compile a location path
11366 *
11367 * // is short for /descendant-or-self::node()/. For example,
11368 * //para is short for /descendant-or-self::node()/child::para and
11369 * so will select any para element in the document (even a para element
11370 * that is a document element will be selected by //para since the
11371 * document element node is a child of the root node); div//para is
11372 * short for div/descendant-or-self::node()/child::para and so will
11373 * select all para descendants of div children.
11374 */
11375static void
11376xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11377    SKIP_BLANKS;
11378    if (CUR != '/') {
11379        xmlXPathCompRelativeLocationPath(ctxt);
11380    } else {
11381	while (CUR == '/') {
11382	    if ((CUR == '/') && (NXT(1) == '/')) {
11383		SKIP(2);
11384		SKIP_BLANKS;
11385		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11386			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11387		xmlXPathCompRelativeLocationPath(ctxt);
11388	    } else if (CUR == '/') {
11389		NEXT;
11390		SKIP_BLANKS;
11391		if ((CUR != 0 ) &&
11392		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11393		     (CUR == '@') || (CUR == '*')))
11394		    xmlXPathCompRelativeLocationPath(ctxt);
11395	    }
11396	    CHECK_ERROR;
11397	}
11398    }
11399}
11400
11401/************************************************************************
11402 *									*
11403 *		XPath precompiled expression evaluation			*
11404 *									*
11405 ************************************************************************/
11406
11407static int
11408xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11409
11410#ifdef DEBUG_STEP
11411static void
11412xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11413			  int nbNodes)
11414{
11415    xmlGenericError(xmlGenericErrorContext, "new step : ");
11416    switch (op->value) {
11417        case AXIS_ANCESTOR:
11418            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11419            break;
11420        case AXIS_ANCESTOR_OR_SELF:
11421            xmlGenericError(xmlGenericErrorContext,
11422                            "axis 'ancestors-or-self' ");
11423            break;
11424        case AXIS_ATTRIBUTE:
11425            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11426            break;
11427        case AXIS_CHILD:
11428            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11429            break;
11430        case AXIS_DESCENDANT:
11431            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11432            break;
11433        case AXIS_DESCENDANT_OR_SELF:
11434            xmlGenericError(xmlGenericErrorContext,
11435                            "axis 'descendant-or-self' ");
11436            break;
11437        case AXIS_FOLLOWING:
11438            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11439            break;
11440        case AXIS_FOLLOWING_SIBLING:
11441            xmlGenericError(xmlGenericErrorContext,
11442                            "axis 'following-siblings' ");
11443            break;
11444        case AXIS_NAMESPACE:
11445            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11446            break;
11447        case AXIS_PARENT:
11448            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11449            break;
11450        case AXIS_PRECEDING:
11451            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11452            break;
11453        case AXIS_PRECEDING_SIBLING:
11454            xmlGenericError(xmlGenericErrorContext,
11455                            "axis 'preceding-sibling' ");
11456            break;
11457        case AXIS_SELF:
11458            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11459            break;
11460    }
11461    xmlGenericError(xmlGenericErrorContext,
11462	" context contains %d nodes\n", nbNodes);
11463    switch (op->value2) {
11464        case NODE_TEST_NONE:
11465            xmlGenericError(xmlGenericErrorContext,
11466                            "           searching for none !!!\n");
11467            break;
11468        case NODE_TEST_TYPE:
11469            xmlGenericError(xmlGenericErrorContext,
11470                            "           searching for type %d\n", op->value3);
11471            break;
11472        case NODE_TEST_PI:
11473            xmlGenericError(xmlGenericErrorContext,
11474                            "           searching for PI !!!\n");
11475            break;
11476        case NODE_TEST_ALL:
11477            xmlGenericError(xmlGenericErrorContext,
11478                            "           searching for *\n");
11479            break;
11480        case NODE_TEST_NS:
11481            xmlGenericError(xmlGenericErrorContext,
11482                            "           searching for namespace %s\n",
11483                            op->value5);
11484            break;
11485        case NODE_TEST_NAME:
11486            xmlGenericError(xmlGenericErrorContext,
11487                            "           searching for name %s\n", op->value5);
11488            if (op->value4)
11489                xmlGenericError(xmlGenericErrorContext,
11490                                "           with namespace %s\n", op->value4);
11491            break;
11492    }
11493    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11494}
11495#endif /* DEBUG_STEP */
11496
11497static int
11498xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11499			    xmlXPathStepOpPtr op,
11500			    xmlNodeSetPtr set,
11501			    int contextSize,
11502			    int hasNsNodes)
11503{
11504    if (op->ch1 != -1) {
11505	xmlXPathCompExprPtr comp = ctxt->comp;
11506	/*
11507	* Process inner predicates first.
11508	*/
11509	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11510	    /*
11511	    * TODO: raise an internal error.
11512	    */
11513	}
11514	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11515	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11516	CHECK_ERROR0;
11517	if (contextSize <= 0)
11518	    return(0);
11519    }
11520    if (op->ch2 != -1) {
11521	xmlXPathContextPtr xpctxt = ctxt->context;
11522	xmlNodePtr contextNode, oldContextNode;
11523	xmlDocPtr oldContextDoc;
11524	int i, res, contextPos = 0, newContextSize;
11525	xmlXPathStepOpPtr exprOp;
11526	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11527
11528#ifdef LIBXML_XPTR_ENABLED
11529	/*
11530	* URGENT TODO: Check the following:
11531	*  We don't expect location sets if evaluating prediates, right?
11532	*  Only filters should expect location sets, right?
11533	*/
11534#endif
11535	/*
11536	* SPEC XPath 1.0:
11537	*  "For each node in the node-set to be filtered, the
11538	*  PredicateExpr is evaluated with that node as the
11539	*  context node, with the number of nodes in the
11540	*  node-set as the context size, and with the proximity
11541	*  position of the node in the node-set with respect to
11542	*  the axis as the context position;"
11543	* @oldset is the node-set" to be filtered.
11544	*
11545	* SPEC XPath 1.0:
11546	*  "only predicates change the context position and
11547	*  context size (see [2.4 Predicates])."
11548	* Example:
11549	*   node-set  context pos
11550	*    nA         1
11551	*    nB         2
11552	*    nC         3
11553	*   After applying predicate [position() > 1] :
11554	*   node-set  context pos
11555	*    nB         1
11556	*    nC         2
11557	*/
11558	oldContextNode = xpctxt->node;
11559	oldContextDoc = xpctxt->doc;
11560	/*
11561	* Get the expression of this predicate.
11562	*/
11563	exprOp = &ctxt->comp->steps[op->ch2];
11564	newContextSize = 0;
11565	for (i = 0; i < set->nodeNr; i++) {
11566	    if (set->nodeTab[i] == NULL)
11567		continue;
11568
11569	    contextNode = set->nodeTab[i];
11570	    xpctxt->node = contextNode;
11571	    xpctxt->contextSize = contextSize;
11572	    xpctxt->proximityPosition = ++contextPos;
11573
11574	    /*
11575	    * Also set the xpath document in case things like
11576	    * key() are evaluated in the predicate.
11577	    */
11578	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11579		(contextNode->doc != NULL))
11580		xpctxt->doc = contextNode->doc;
11581	    /*
11582	    * Evaluate the predicate expression with 1 context node
11583	    * at a time; this node is packaged into a node set; this
11584	    * node set is handed over to the evaluation mechanism.
11585	    */
11586	    if (contextObj == NULL)
11587		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11588	    else
11589		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11590		    contextNode);
11591
11592	    valuePush(ctxt, contextObj);
11593
11594	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11595
11596	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11597		xmlXPathNodeSetClear(set, hasNsNodes);
11598		newContextSize = 0;
11599		goto evaluation_exit;
11600	    }
11601
11602	    if (res != 0) {
11603		newContextSize++;
11604	    } else {
11605		/*
11606		* Remove the entry from the initial node set.
11607		*/
11608		set->nodeTab[i] = NULL;
11609		if (contextNode->type == XML_NAMESPACE_DECL)
11610		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11611	    }
11612	    if (ctxt->value == contextObj) {
11613		/*
11614		* Don't free the temporary XPath object holding the
11615		* context node, in order to avoid massive recreation
11616		* inside this loop.
11617		*/
11618		valuePop(ctxt);
11619		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11620	    } else {
11621		/*
11622		* TODO: The object was lost in the evaluation machinery.
11623		*  Can this happen? Maybe in internal-error cases.
11624		*/
11625		contextObj = NULL;
11626	    }
11627	}
11628
11629	if (contextObj != NULL) {
11630	    if (ctxt->value == contextObj)
11631		valuePop(ctxt);
11632	    xmlXPathReleaseObject(xpctxt, contextObj);
11633	}
11634evaluation_exit:
11635	if (exprRes != NULL)
11636	    xmlXPathReleaseObject(ctxt->context, exprRes);
11637	/*
11638	* Reset/invalidate the context.
11639	*/
11640	xpctxt->node = oldContextNode;
11641	xpctxt->doc = oldContextDoc;
11642	xpctxt->contextSize = -1;
11643	xpctxt->proximityPosition = -1;
11644	return(newContextSize);
11645    }
11646    return(contextSize);
11647}
11648
11649static int
11650xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11651				      xmlXPathStepOpPtr op,
11652				      xmlNodeSetPtr set,
11653				      int contextSize,
11654				      int minPos,
11655				      int maxPos,
11656				      int hasNsNodes)
11657{
11658    if (op->ch1 != -1) {
11659	xmlXPathCompExprPtr comp = ctxt->comp;
11660	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11661	    /*
11662	    * TODO: raise an internal error.
11663	    */
11664	}
11665	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11666	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11667	CHECK_ERROR0;
11668	if (contextSize <= 0)
11669	    return(0);
11670    }
11671    /*
11672    * Check if the node set contains a sufficient number of nodes for
11673    * the requested range.
11674    */
11675    if (contextSize < minPos) {
11676	xmlXPathNodeSetClear(set, hasNsNodes);
11677	return(0);
11678    }
11679    if (op->ch2 == -1) {
11680	/*
11681	* TODO: Can this ever happen?
11682	*/
11683	return (contextSize);
11684    } else {
11685	xmlDocPtr oldContextDoc;
11686	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11687	xmlXPathStepOpPtr exprOp;
11688	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11689	xmlNodePtr oldContextNode, contextNode = NULL;
11690	xmlXPathContextPtr xpctxt = ctxt->context;
11691
11692#ifdef LIBXML_XPTR_ENABLED
11693	    /*
11694	    * URGENT TODO: Check the following:
11695	    *  We don't expect location sets if evaluating prediates, right?
11696	    *  Only filters should expect location sets, right?
11697	*/
11698#endif /* LIBXML_XPTR_ENABLED */
11699
11700	/*
11701	* Save old context.
11702	*/
11703	oldContextNode = xpctxt->node;
11704	oldContextDoc = xpctxt->doc;
11705	/*
11706	* Get the expression of this predicate.
11707	*/
11708	exprOp = &ctxt->comp->steps[op->ch2];
11709	for (i = 0; i < set->nodeNr; i++) {
11710	    if (set->nodeTab[i] == NULL)
11711		continue;
11712
11713	    contextNode = set->nodeTab[i];
11714	    xpctxt->node = contextNode;
11715	    xpctxt->contextSize = contextSize;
11716	    xpctxt->proximityPosition = ++contextPos;
11717
11718	    /*
11719	    * Initialize the new set.
11720	    * Also set the xpath document in case things like
11721	    * key() evaluation are attempted on the predicate
11722	    */
11723	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11724		(contextNode->doc != NULL))
11725		xpctxt->doc = contextNode->doc;
11726	    /*
11727	    * Evaluate the predicate expression with 1 context node
11728	    * at a time; this node is packaged into a node set; this
11729	    * node set is handed over to the evaluation mechanism.
11730	    */
11731	    if (contextObj == NULL)
11732		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11733	    else
11734		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11735		    contextNode);
11736
11737	    valuePush(ctxt, contextObj);
11738	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11739
11740	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11741	        xmlXPathObjectPtr tmp;
11742		/* pop the result */
11743		tmp = valuePop(ctxt);
11744		xmlXPathReleaseObject(xpctxt, tmp);
11745		/* then pop off contextObj, which will be freed later */
11746		valuePop(ctxt);
11747		goto evaluation_error;
11748	    }
11749
11750	    if (res)
11751		pos++;
11752
11753	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11754		/*
11755		* Fits in the requested range.
11756		*/
11757		newContextSize++;
11758		if (minPos == maxPos) {
11759		    /*
11760		    * Only 1 node was requested.
11761		    */
11762		    if (contextNode->type == XML_NAMESPACE_DECL) {
11763			/*
11764			* As always: take care of those nasty
11765			* namespace nodes.
11766			*/
11767			set->nodeTab[i] = NULL;
11768		    }
11769		    xmlXPathNodeSetClear(set, hasNsNodes);
11770		    set->nodeNr = 1;
11771		    set->nodeTab[0] = contextNode;
11772		    goto evaluation_exit;
11773		}
11774		if (pos == maxPos) {
11775		    /*
11776		    * We are done.
11777		    */
11778		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11779		    goto evaluation_exit;
11780		}
11781	    } else {
11782		/*
11783		* Remove the entry from the initial node set.
11784		*/
11785		set->nodeTab[i] = NULL;
11786		if (contextNode->type == XML_NAMESPACE_DECL)
11787		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11788	    }
11789	    if (exprRes != NULL) {
11790		xmlXPathReleaseObject(ctxt->context, exprRes);
11791		exprRes = NULL;
11792	    }
11793	    if (ctxt->value == contextObj) {
11794		/*
11795		* Don't free the temporary XPath object holding the
11796		* context node, in order to avoid massive recreation
11797		* inside this loop.
11798		*/
11799		valuePop(ctxt);
11800		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11801	    } else {
11802		/*
11803		* The object was lost in the evaluation machinery.
11804		* Can this happen? Maybe in case of internal-errors.
11805		*/
11806		contextObj = NULL;
11807	    }
11808	}
11809	goto evaluation_exit;
11810
11811evaluation_error:
11812	xmlXPathNodeSetClear(set, hasNsNodes);
11813	newContextSize = 0;
11814
11815evaluation_exit:
11816	if (contextObj != NULL) {
11817	    if (ctxt->value == contextObj)
11818		valuePop(ctxt);
11819	    xmlXPathReleaseObject(xpctxt, contextObj);
11820	}
11821	if (exprRes != NULL)
11822	    xmlXPathReleaseObject(ctxt->context, exprRes);
11823	/*
11824	* Reset/invalidate the context.
11825	*/
11826	xpctxt->node = oldContextNode;
11827	xpctxt->doc = oldContextDoc;
11828	xpctxt->contextSize = -1;
11829	xpctxt->proximityPosition = -1;
11830	return(newContextSize);
11831    }
11832    return(contextSize);
11833}
11834
11835static int
11836xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11837			    xmlXPathStepOpPtr op,
11838			    int *maxPos)
11839{
11840
11841    xmlXPathStepOpPtr exprOp;
11842
11843    /*
11844    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11845    */
11846
11847    /*
11848    * If not -1, then ch1 will point to:
11849    * 1) For predicates (XPATH_OP_PREDICATE):
11850    *    - an inner predicate operator
11851    * 2) For filters (XPATH_OP_FILTER):
11852    *    - an inner filter operater OR
11853    *    - an expression selecting the node set.
11854    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11855    */
11856    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11857	return(0);
11858
11859    if (op->ch2 != -1) {
11860	exprOp = &ctxt->comp->steps[op->ch2];
11861    } else
11862	return(0);
11863
11864    if ((exprOp != NULL) &&
11865	(exprOp->op == XPATH_OP_VALUE) &&
11866	(exprOp->value4 != NULL) &&
11867	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11868    {
11869	/*
11870	* We have a "[n]" predicate here.
11871	* TODO: Unfortunately this simplistic test here is not
11872	* able to detect a position() predicate in compound
11873	* expressions like "[@attr = 'a" and position() = 1],
11874	* and even not the usage of position() in
11875	* "[position() = 1]"; thus - obviously - a position-range,
11876	* like it "[position() < 5]", is also not detected.
11877	* Maybe we could rewrite the AST to ease the optimization.
11878	*/
11879	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11880
11881	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11882	    (float) *maxPos)
11883	{
11884	    return(1);
11885	}
11886    }
11887    return(0);
11888}
11889
11890static int
11891xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11892                           xmlXPathStepOpPtr op,
11893			   xmlNodePtr * first, xmlNodePtr * last,
11894			   int toBool)
11895{
11896
11897#define XP_TEST_HIT \
11898    if (hasAxisRange != 0) { \
11899	if (++pos == maxPos) { \
11900	    addNode(seq, cur); \
11901	goto axis_range_end; } \
11902    } else { \
11903	addNode(seq, cur); \
11904	if (breakOnFirstHit) goto first_hit; }
11905
11906#define XP_TEST_HIT_NS \
11907    if (hasAxisRange != 0) { \
11908	if (++pos == maxPos) { \
11909	    hasNsNodes = 1; \
11910	    xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11911	goto axis_range_end; } \
11912    } else { \
11913	hasNsNodes = 1; \
11914	xmlXPathNodeSetAddNs(seq, \
11915	xpctxt->node, (xmlNsPtr) cur); \
11916	if (breakOnFirstHit) goto first_hit; }
11917
11918    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11919    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11920    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11921    const xmlChar *prefix = op->value4;
11922    const xmlChar *name = op->value5;
11923    const xmlChar *URI = NULL;
11924
11925#ifdef DEBUG_STEP
11926    int nbMatches = 0, prevMatches = 0;
11927#endif
11928    int total = 0, hasNsNodes = 0;
11929    /* The popped object holding the context nodes */
11930    xmlXPathObjectPtr obj;
11931    /* The set of context nodes for the node tests */
11932    xmlNodeSetPtr contextSeq;
11933    int contextIdx;
11934    xmlNodePtr contextNode;
11935    /* The context node for a compound traversal */
11936    xmlNodePtr outerContextNode;
11937    /* The final resulting node set wrt to all context nodes */
11938    xmlNodeSetPtr outSeq;
11939    /*
11940    * The temporary resulting node set wrt 1 context node.
11941    * Used to feed predicate evaluation.
11942    */
11943    xmlNodeSetPtr seq;
11944    xmlNodePtr cur;
11945    /* First predicate operator */
11946    xmlXPathStepOpPtr predOp;
11947    int maxPos; /* The requested position() (when a "[n]" predicate) */
11948    int hasPredicateRange, hasAxisRange, pos, size, newSize;
11949    int breakOnFirstHit;
11950
11951    xmlXPathTraversalFunction next = NULL;
11952    /* compound axis traversal */
11953    xmlXPathTraversalFunctionExt outerNext = NULL;
11954    void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11955    xmlXPathNodeSetMergeFunction mergeAndClear;
11956    xmlNodePtr oldContextNode;
11957    xmlXPathContextPtr xpctxt = ctxt->context;
11958
11959
11960    CHECK_TYPE0(XPATH_NODESET);
11961    obj = valuePop(ctxt);
11962    /*
11963    * Setup namespaces.
11964    */
11965    if (prefix != NULL) {
11966        URI = xmlXPathNsLookup(xpctxt, prefix);
11967        if (URI == NULL) {
11968	    xmlXPathReleaseObject(xpctxt, obj);
11969            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11970	}
11971    }
11972    /*
11973    * Setup axis.
11974    *
11975    * MAYBE FUTURE TODO: merging optimizations:
11976    * - If the nodes to be traversed wrt to the initial nodes and
11977    *   the current axis cannot overlap, then we could avoid searching
11978    *   for duplicates during the merge.
11979    *   But the question is how/when to evaluate if they cannot overlap.
11980    *   Example: if we know that for two initial nodes, the one is
11981    *   not in the ancestor-or-self axis of the other, then we could safely
11982    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11983    *   the descendant-or-self axis.
11984    */
11985    mergeAndClear = xmlXPathNodeSetMergeAndClear;
11986    switch (axis) {
11987        case AXIS_ANCESTOR:
11988            first = NULL;
11989            next = xmlXPathNextAncestor;
11990            break;
11991        case AXIS_ANCESTOR_OR_SELF:
11992            first = NULL;
11993            next = xmlXPathNextAncestorOrSelf;
11994            break;
11995        case AXIS_ATTRIBUTE:
11996            first = NULL;
11997	    last = NULL;
11998            next = xmlXPathNextAttribute;
11999	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12000            break;
12001        case AXIS_CHILD:
12002	    last = NULL;
12003	    if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12004		/*
12005		* This iterator will give us only nodes which can
12006		* hold element nodes.
12007		*/
12008		outerNext = xmlXPathNextDescendantOrSelfElemParent;
12009	    }
12010	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12011		(type == NODE_TYPE_NODE))
12012	    {
12013		/*
12014		* Optimization if an element node type is 'element'.
12015		*/
12016		next = xmlXPathNextChildElement;
12017	    } else
12018		next = xmlXPathNextChild;
12019	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12020            break;
12021        case AXIS_DESCENDANT:
12022	    last = NULL;
12023            next = xmlXPathNextDescendant;
12024            break;
12025        case AXIS_DESCENDANT_OR_SELF:
12026	    last = NULL;
12027            next = xmlXPathNextDescendantOrSelf;
12028            break;
12029        case AXIS_FOLLOWING:
12030	    last = NULL;
12031            next = xmlXPathNextFollowing;
12032            break;
12033        case AXIS_FOLLOWING_SIBLING:
12034	    last = NULL;
12035            next = xmlXPathNextFollowingSibling;
12036            break;
12037        case AXIS_NAMESPACE:
12038            first = NULL;
12039	    last = NULL;
12040            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12041	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12042            break;
12043        case AXIS_PARENT:
12044            first = NULL;
12045            next = xmlXPathNextParent;
12046            break;
12047        case AXIS_PRECEDING:
12048            first = NULL;
12049            next = xmlXPathNextPrecedingInternal;
12050            break;
12051        case AXIS_PRECEDING_SIBLING:
12052            first = NULL;
12053            next = xmlXPathNextPrecedingSibling;
12054            break;
12055        case AXIS_SELF:
12056            first = NULL;
12057	    last = NULL;
12058            next = xmlXPathNextSelf;
12059	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12060            break;
12061    }
12062
12063#ifdef DEBUG_STEP
12064    xmlXPathDebugDumpStepAxis(op,
12065	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12066#endif
12067
12068    if (next == NULL) {
12069	xmlXPathReleaseObject(xpctxt, obj);
12070        return(0);
12071    }
12072    contextSeq = obj->nodesetval;
12073    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12074	xmlXPathReleaseObject(xpctxt, obj);
12075        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12076        return(0);
12077    }
12078    /*
12079    * Predicate optimization ---------------------------------------------
12080    * If this step has a last predicate, which contains a position(),
12081    * then we'll optimize (although not exactly "position()", but only
12082    * the  short-hand form, i.e., "[n]".
12083    *
12084    * Example - expression "/foo[parent::bar][1]":
12085    *
12086    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12087    *   ROOT                               -- op->ch1
12088    *   PREDICATE                          -- op->ch2 (predOp)
12089    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12090    *       SORT
12091    *         COLLECT  'parent' 'name' 'node' bar
12092    *           NODE
12093    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12094    *
12095    */
12096    maxPos = 0;
12097    predOp = NULL;
12098    hasPredicateRange = 0;
12099    hasAxisRange = 0;
12100    if (op->ch2 != -1) {
12101	/*
12102	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12103	*/
12104	predOp = &ctxt->comp->steps[op->ch2];
12105	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12106	    if (predOp->ch1 != -1) {
12107		/*
12108		* Use the next inner predicate operator.
12109		*/
12110		predOp = &ctxt->comp->steps[predOp->ch1];
12111		hasPredicateRange = 1;
12112	    } else {
12113		/*
12114		* There's no other predicate than the [n] predicate.
12115		*/
12116		predOp = NULL;
12117		hasAxisRange = 1;
12118	    }
12119	}
12120    }
12121    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12122    /*
12123    * Axis traversal -----------------------------------------------------
12124    */
12125    /*
12126     * 2.3 Node Tests
12127     *  - For the attribute axis, the principal node type is attribute.
12128     *  - For the namespace axis, the principal node type is namespace.
12129     *  - For other axes, the principal node type is element.
12130     *
12131     * A node test * is true for any node of the
12132     * principal node type. For example, child::* will
12133     * select all element children of the context node
12134     */
12135    oldContextNode = xpctxt->node;
12136    addNode = xmlXPathNodeSetAddUnique;
12137    outSeq = NULL;
12138    seq = NULL;
12139    outerContextNode = NULL;
12140    contextNode = NULL;
12141    contextIdx = 0;
12142
12143
12144    while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12145	if (outerNext != NULL) {
12146	    /*
12147	    * This is a compound traversal.
12148	    */
12149	    if (contextNode == NULL) {
12150		/*
12151		* Set the context for the outer traversal.
12152		*/
12153		outerContextNode = contextSeq->nodeTab[contextIdx++];
12154		contextNode = outerNext(NULL, outerContextNode);
12155	    } else
12156		contextNode = outerNext(contextNode, outerContextNode);
12157	    if (contextNode == NULL)
12158		continue;
12159	    /*
12160	    * Set the context for the main traversal.
12161	    */
12162	    xpctxt->node = contextNode;
12163	} else
12164	    xpctxt->node = contextSeq->nodeTab[contextIdx++];
12165
12166	if (seq == NULL) {
12167	    seq = xmlXPathNodeSetCreate(NULL);
12168	    if (seq == NULL) {
12169		total = 0;
12170		goto error;
12171	    }
12172	}
12173	/*
12174	* Traverse the axis and test the nodes.
12175	*/
12176	pos = 0;
12177	cur = NULL;
12178	hasNsNodes = 0;
12179        do {
12180            cur = next(ctxt, cur);
12181            if (cur == NULL)
12182                break;
12183
12184	    /*
12185	    * QUESTION TODO: What does the "first" and "last" stuff do?
12186	    */
12187            if ((first != NULL) && (*first != NULL)) {
12188		if (*first == cur)
12189		    break;
12190		if (((total % 256) == 0) &&
12191#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12192		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12193#else
12194		    (xmlXPathCmpNodes(*first, cur) >= 0))
12195#endif
12196		{
12197		    break;
12198		}
12199	    }
12200	    if ((last != NULL) && (*last != NULL)) {
12201		if (*last == cur)
12202		    break;
12203		if (((total % 256) == 0) &&
12204#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12205		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12206#else
12207		    (xmlXPathCmpNodes(cur, *last) >= 0))
12208#endif
12209		{
12210		    break;
12211		}
12212	    }
12213
12214            total++;
12215
12216#ifdef DEBUG_STEP
12217            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12218#endif
12219
12220	    switch (test) {
12221                case NODE_TEST_NONE:
12222		    total = 0;
12223                    STRANGE
12224		    goto error;
12225                case NODE_TEST_TYPE:
12226		    /*
12227		    * TODO: Don't we need to use
12228		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
12229		    *  Surprisingly, some c14n tests fail, if we do this.
12230		    */
12231		    if (type == NODE_TYPE_NODE) {
12232			switch (cur->type) {
12233			    case XML_DOCUMENT_NODE:
12234			    case XML_HTML_DOCUMENT_NODE:
12235#ifdef LIBXML_DOCB_ENABLED
12236			    case XML_DOCB_DOCUMENT_NODE:
12237#endif
12238			    case XML_ELEMENT_NODE:
12239			    case XML_ATTRIBUTE_NODE:
12240			    case XML_PI_NODE:
12241			    case XML_COMMENT_NODE:
12242			    case XML_CDATA_SECTION_NODE:
12243			    case XML_TEXT_NODE:
12244			    case XML_NAMESPACE_DECL:
12245				XP_TEST_HIT
12246				break;
12247			    default:
12248				break;
12249			}
12250		    } else if (cur->type == type) {
12251			if (type == XML_NAMESPACE_DECL)
12252			    XP_TEST_HIT_NS
12253			else
12254			    XP_TEST_HIT
12255		    } else if ((type == NODE_TYPE_TEXT) &&
12256			 (cur->type == XML_CDATA_SECTION_NODE))
12257		    {
12258			XP_TEST_HIT
12259		    }
12260		    break;
12261                case NODE_TEST_PI:
12262                    if ((cur->type == XML_PI_NODE) &&
12263                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12264		    {
12265			XP_TEST_HIT
12266                    }
12267                    break;
12268                case NODE_TEST_ALL:
12269                    if (axis == AXIS_ATTRIBUTE) {
12270                        if (cur->type == XML_ATTRIBUTE_NODE)
12271			{
12272			    XP_TEST_HIT
12273                        }
12274                    } else if (axis == AXIS_NAMESPACE) {
12275                        if (cur->type == XML_NAMESPACE_DECL)
12276			{
12277			    XP_TEST_HIT_NS
12278                        }
12279                    } else {
12280                        if (cur->type == XML_ELEMENT_NODE) {
12281                            if (prefix == NULL)
12282			    {
12283				XP_TEST_HIT
12284
12285                            } else if ((cur->ns != NULL) &&
12286				(xmlStrEqual(URI, cur->ns->href)))
12287			    {
12288				XP_TEST_HIT
12289                            }
12290                        }
12291                    }
12292                    break;
12293                case NODE_TEST_NS:{
12294                        TODO;
12295                        break;
12296                    }
12297                case NODE_TEST_NAME:
12298                    if (axis == AXIS_ATTRIBUTE) {
12299                        if (cur->type != XML_ATTRIBUTE_NODE)
12300			    break;
12301		    } else if (axis == AXIS_NAMESPACE) {
12302                        if (cur->type != XML_NAMESPACE_DECL)
12303			    break;
12304		    } else {
12305		        if (cur->type != XML_ELEMENT_NODE)
12306			    break;
12307		    }
12308                    switch (cur->type) {
12309                        case XML_ELEMENT_NODE:
12310                            if (xmlStrEqual(name, cur->name)) {
12311                                if (prefix == NULL) {
12312                                    if (cur->ns == NULL)
12313				    {
12314					XP_TEST_HIT
12315                                    }
12316                                } else {
12317                                    if ((cur->ns != NULL) &&
12318                                        (xmlStrEqual(URI, cur->ns->href)))
12319				    {
12320					XP_TEST_HIT
12321                                    }
12322                                }
12323                            }
12324                            break;
12325                        case XML_ATTRIBUTE_NODE:{
12326                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12327
12328                                if (xmlStrEqual(name, attr->name)) {
12329                                    if (prefix == NULL) {
12330                                        if ((attr->ns == NULL) ||
12331                                            (attr->ns->prefix == NULL))
12332					{
12333					    XP_TEST_HIT
12334                                        }
12335                                    } else {
12336                                        if ((attr->ns != NULL) &&
12337                                            (xmlStrEqual(URI,
12338					      attr->ns->href)))
12339					{
12340					    XP_TEST_HIT
12341                                        }
12342                                    }
12343                                }
12344                                break;
12345                            }
12346                        case XML_NAMESPACE_DECL:
12347                            if (cur->type == XML_NAMESPACE_DECL) {
12348                                xmlNsPtr ns = (xmlNsPtr) cur;
12349
12350                                if ((ns->prefix != NULL) && (name != NULL)
12351                                    && (xmlStrEqual(ns->prefix, name)))
12352				{
12353				    XP_TEST_HIT_NS
12354                                }
12355                            }
12356                            break;
12357                        default:
12358                            break;
12359                    }
12360                    break;
12361	    } /* switch(test) */
12362        } while (cur != NULL);
12363
12364	goto apply_predicates;
12365
12366axis_range_end: /* ----------------------------------------------------- */
12367	/*
12368	* We have a "/foo[n]", and position() = n was reached.
12369	* Note that we can have as well "/foo/::parent::foo[1]", so
12370	* a duplicate-aware merge is still needed.
12371	* Merge with the result.
12372	*/
12373	if (outSeq == NULL) {
12374	    outSeq = seq;
12375	    seq = NULL;
12376	} else
12377	    outSeq = mergeAndClear(outSeq, seq, 0);
12378	/*
12379	* Break if only a true/false result was requested.
12380	*/
12381	if (toBool)
12382	    break;
12383	continue;
12384
12385first_hit: /* ---------------------------------------------------------- */
12386	/*
12387	* Break if only a true/false result was requested and
12388	* no predicates existed and a node test succeeded.
12389	*/
12390	if (outSeq == NULL) {
12391	    outSeq = seq;
12392	    seq = NULL;
12393	} else
12394	    outSeq = mergeAndClear(outSeq, seq, 0);
12395	break;
12396
12397#ifdef DEBUG_STEP
12398	if (seq != NULL)
12399	    nbMatches += seq->nodeNr;
12400#endif
12401
12402apply_predicates: /* --------------------------------------------------- */
12403        /*
12404	* Apply predicates.
12405	*/
12406        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12407	    /*
12408	    * E.g. when we have a "/foo[some expression][n]".
12409	    */
12410	    /*
12411	    * QUESTION TODO: The old predicate evaluation took into
12412	    *  account location-sets.
12413	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12414	    *  Do we expect such a set here?
12415	    *  All what I learned now from the evaluation semantics
12416	    *  does not indicate that a location-set will be processed
12417	    *  here, so this looks OK.
12418	    */
12419	    /*
12420	    * Iterate over all predicates, starting with the outermost
12421	    * predicate.
12422	    * TODO: Problem: we cannot execute the inner predicates first
12423	    *  since we cannot go back *up* the operator tree!
12424	    *  Options we have:
12425	    *  1) Use of recursive functions (like is it currently done
12426	    *     via xmlXPathCompOpEval())
12427	    *  2) Add a predicate evaluation information stack to the
12428	    *     context struct
12429	    *  3) Change the way the operators are linked; we need a
12430	    *     "parent" field on xmlXPathStepOp
12431	    *
12432	    * For the moment, I'll try to solve this with a recursive
12433	    * function: xmlXPathCompOpEvalPredicate().
12434	    */
12435	    size = seq->nodeNr;
12436	    if (hasPredicateRange != 0)
12437		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12438		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12439	    else
12440		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12441		    predOp, seq, size, hasNsNodes);
12442
12443	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12444		total = 0;
12445		goto error;
12446	    }
12447	    /*
12448	    * Add the filtered set of nodes to the result node set.
12449	    */
12450	    if (newSize == 0) {
12451		/*
12452		* The predicates filtered all nodes out.
12453		*/
12454		xmlXPathNodeSetClear(seq, hasNsNodes);
12455	    } else if (seq->nodeNr > 0) {
12456		/*
12457		* Add to result set.
12458		*/
12459		if (outSeq == NULL) {
12460		    if (size != newSize) {
12461			/*
12462			* We need to merge and clear here, since
12463			* the sequence will contained NULLed entries.
12464			*/
12465			outSeq = mergeAndClear(NULL, seq, 1);
12466		    } else {
12467			outSeq = seq;
12468			seq = NULL;
12469		    }
12470		} else
12471		    outSeq = mergeAndClear(outSeq, seq,
12472			(size != newSize) ? 1: 0);
12473		/*
12474		* Break if only a true/false result was requested.
12475		*/
12476		if (toBool)
12477		    break;
12478	    }
12479        } else if (seq->nodeNr > 0) {
12480	    /*
12481	    * Add to result set.
12482	    */
12483	    if (outSeq == NULL) {
12484		outSeq = seq;
12485		seq = NULL;
12486	    } else {
12487		outSeq = mergeAndClear(outSeq, seq, 0);
12488	    }
12489	}
12490    }
12491
12492error:
12493    if ((obj->boolval) && (obj->user != NULL)) {
12494	/*
12495	* QUESTION TODO: What does this do and why?
12496	* TODO: Do we have to do this also for the "error"
12497	* cleanup further down?
12498	*/
12499	ctxt->value->boolval = 1;
12500	ctxt->value->user = obj->user;
12501	obj->user = NULL;
12502	obj->boolval = 0;
12503    }
12504    xmlXPathReleaseObject(xpctxt, obj);
12505
12506    /*
12507    * Ensure we return at least an emtpy set.
12508    */
12509    if (outSeq == NULL) {
12510	if ((seq != NULL) && (seq->nodeNr == 0))
12511	    outSeq = seq;
12512	else
12513	    outSeq = xmlXPathNodeSetCreate(NULL);
12514        /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12515    }
12516    if ((seq != NULL) && (seq != outSeq)) {
12517	 xmlXPathFreeNodeSet(seq);
12518    }
12519    /*
12520    * Hand over the result. Better to push the set also in
12521    * case of errors.
12522    */
12523    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12524    /*
12525    * Reset the context node.
12526    */
12527    xpctxt->node = oldContextNode;
12528
12529#ifdef DEBUG_STEP
12530    xmlGenericError(xmlGenericErrorContext,
12531	"\nExamined %d nodes, found %d nodes at that step\n",
12532	total, nbMatches);
12533#endif
12534
12535    return(total);
12536}
12537
12538static int
12539xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12540			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12541
12542/**
12543 * xmlXPathCompOpEvalFirst:
12544 * @ctxt:  the XPath parser context with the compiled expression
12545 * @op:  an XPath compiled operation
12546 * @first:  the first elem found so far
12547 *
12548 * Evaluate the Precompiled XPath operation searching only the first
12549 * element in document order
12550 *
12551 * Returns the number of examined objects.
12552 */
12553static int
12554xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12555                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12556{
12557    int total = 0, cur;
12558    xmlXPathCompExprPtr comp;
12559    xmlXPathObjectPtr arg1, arg2;
12560
12561    CHECK_ERROR0;
12562    comp = ctxt->comp;
12563    switch (op->op) {
12564        case XPATH_OP_END:
12565            return (0);
12566        case XPATH_OP_UNION:
12567            total =
12568                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12569                                        first);
12570	    CHECK_ERROR0;
12571            if ((ctxt->value != NULL)
12572                && (ctxt->value->type == XPATH_NODESET)
12573                && (ctxt->value->nodesetval != NULL)
12574                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12575                /*
12576                 * limit tree traversing to first node in the result
12577                 */
12578		/*
12579		* OPTIMIZE TODO: This implicitely sorts
12580		*  the result, even if not needed. E.g. if the argument
12581		*  of the count() function, no sorting is needed.
12582		* OPTIMIZE TODO: How do we know if the node-list wasn't
12583		*  aready sorted?
12584		*/
12585		if (ctxt->value->nodesetval->nodeNr > 1)
12586		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12587                *first = ctxt->value->nodesetval->nodeTab[0];
12588            }
12589            cur =
12590                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12591                                        first);
12592	    CHECK_ERROR0;
12593            CHECK_TYPE0(XPATH_NODESET);
12594            arg2 = valuePop(ctxt);
12595
12596            CHECK_TYPE0(XPATH_NODESET);
12597            arg1 = valuePop(ctxt);
12598
12599            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12600                                                    arg2->nodesetval);
12601            valuePush(ctxt, arg1);
12602	    xmlXPathReleaseObject(ctxt->context, arg2);
12603            /* optimizer */
12604	    if (total > cur)
12605		xmlXPathCompSwap(op);
12606            return (total + cur);
12607        case XPATH_OP_ROOT:
12608            xmlXPathRoot(ctxt);
12609            return (0);
12610        case XPATH_OP_NODE:
12611            if (op->ch1 != -1)
12612                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12613	    CHECK_ERROR0;
12614            if (op->ch2 != -1)
12615                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12616	    CHECK_ERROR0;
12617	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12618		ctxt->context->node));
12619            return (total);
12620        case XPATH_OP_RESET:
12621            if (op->ch1 != -1)
12622                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12623	    CHECK_ERROR0;
12624            if (op->ch2 != -1)
12625                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12626	    CHECK_ERROR0;
12627            ctxt->context->node = NULL;
12628            return (total);
12629        case XPATH_OP_COLLECT:{
12630                if (op->ch1 == -1)
12631                    return (total);
12632
12633                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12634		CHECK_ERROR0;
12635
12636                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12637                return (total);
12638            }
12639        case XPATH_OP_VALUE:
12640            valuePush(ctxt,
12641                      xmlXPathCacheObjectCopy(ctxt->context,
12642			(xmlXPathObjectPtr) op->value4));
12643            return (0);
12644        case XPATH_OP_SORT:
12645            if (op->ch1 != -1)
12646                total +=
12647                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12648                                            first);
12649	    CHECK_ERROR0;
12650            if ((ctxt->value != NULL)
12651                && (ctxt->value->type == XPATH_NODESET)
12652                && (ctxt->value->nodesetval != NULL)
12653		&& (ctxt->value->nodesetval->nodeNr > 1))
12654                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12655            return (total);
12656#ifdef XP_OPTIMIZED_FILTER_FIRST
12657	case XPATH_OP_FILTER:
12658                total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12659            return (total);
12660#endif
12661        default:
12662            return (xmlXPathCompOpEval(ctxt, op));
12663    }
12664}
12665
12666/**
12667 * xmlXPathCompOpEvalLast:
12668 * @ctxt:  the XPath parser context with the compiled expression
12669 * @op:  an XPath compiled operation
12670 * @last:  the last elem found so far
12671 *
12672 * Evaluate the Precompiled XPath operation searching only the last
12673 * element in document order
12674 *
12675 * Returns the number of nodes traversed
12676 */
12677static int
12678xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12679                       xmlNodePtr * last)
12680{
12681    int total = 0, cur;
12682    xmlXPathCompExprPtr comp;
12683    xmlXPathObjectPtr arg1, arg2;
12684    xmlNodePtr bak;
12685    xmlDocPtr bakd;
12686    int pp;
12687    int cs;
12688
12689    CHECK_ERROR0;
12690    comp = ctxt->comp;
12691    switch (op->op) {
12692        case XPATH_OP_END:
12693            return (0);
12694        case XPATH_OP_UNION:
12695	    bakd = ctxt->context->doc;
12696	    bak = ctxt->context->node;
12697	    pp = ctxt->context->proximityPosition;
12698	    cs = ctxt->context->contextSize;
12699            total =
12700                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12701	    CHECK_ERROR0;
12702            if ((ctxt->value != NULL)
12703                && (ctxt->value->type == XPATH_NODESET)
12704                && (ctxt->value->nodesetval != NULL)
12705                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12706                /*
12707                 * limit tree traversing to first node in the result
12708                 */
12709		if (ctxt->value->nodesetval->nodeNr > 1)
12710		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12711                *last =
12712                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12713                                                     nodesetval->nodeNr -
12714                                                     1];
12715            }
12716	    ctxt->context->doc = bakd;
12717	    ctxt->context->node = bak;
12718	    ctxt->context->proximityPosition = pp;
12719	    ctxt->context->contextSize = cs;
12720            cur =
12721                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12722	    CHECK_ERROR0;
12723            if ((ctxt->value != NULL)
12724                && (ctxt->value->type == XPATH_NODESET)
12725                && (ctxt->value->nodesetval != NULL)
12726                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12727            }
12728            CHECK_TYPE0(XPATH_NODESET);
12729            arg2 = valuePop(ctxt);
12730
12731            CHECK_TYPE0(XPATH_NODESET);
12732            arg1 = valuePop(ctxt);
12733
12734            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12735                                                    arg2->nodesetval);
12736            valuePush(ctxt, arg1);
12737	    xmlXPathReleaseObject(ctxt->context, arg2);
12738            /* optimizer */
12739	    if (total > cur)
12740		xmlXPathCompSwap(op);
12741            return (total + cur);
12742        case XPATH_OP_ROOT:
12743            xmlXPathRoot(ctxt);
12744            return (0);
12745        case XPATH_OP_NODE:
12746            if (op->ch1 != -1)
12747                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12748	    CHECK_ERROR0;
12749            if (op->ch2 != -1)
12750                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12751	    CHECK_ERROR0;
12752	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12753		ctxt->context->node));
12754            return (total);
12755        case XPATH_OP_RESET:
12756            if (op->ch1 != -1)
12757                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12758	    CHECK_ERROR0;
12759            if (op->ch2 != -1)
12760                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12761	    CHECK_ERROR0;
12762            ctxt->context->node = NULL;
12763            return (total);
12764        case XPATH_OP_COLLECT:{
12765                if (op->ch1 == -1)
12766                    return (0);
12767
12768                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12769		CHECK_ERROR0;
12770
12771                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12772                return (total);
12773            }
12774        case XPATH_OP_VALUE:
12775            valuePush(ctxt,
12776                      xmlXPathCacheObjectCopy(ctxt->context,
12777			(xmlXPathObjectPtr) op->value4));
12778            return (0);
12779        case XPATH_OP_SORT:
12780            if (op->ch1 != -1)
12781                total +=
12782                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12783                                           last);
12784	    CHECK_ERROR0;
12785            if ((ctxt->value != NULL)
12786                && (ctxt->value->type == XPATH_NODESET)
12787                && (ctxt->value->nodesetval != NULL)
12788		&& (ctxt->value->nodesetval->nodeNr > 1))
12789                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12790            return (total);
12791        default:
12792            return (xmlXPathCompOpEval(ctxt, op));
12793    }
12794}
12795
12796#ifdef XP_OPTIMIZED_FILTER_FIRST
12797static int
12798xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12799			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12800{
12801    int total = 0;
12802    xmlXPathCompExprPtr comp;
12803    xmlXPathObjectPtr res;
12804    xmlXPathObjectPtr obj;
12805    xmlNodeSetPtr oldset;
12806    xmlNodePtr oldnode;
12807    xmlDocPtr oldDoc;
12808    int i;
12809
12810    CHECK_ERROR0;
12811    comp = ctxt->comp;
12812    /*
12813    * Optimization for ()[last()] selection i.e. the last elem
12814    */
12815    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12816	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12817	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12818	int f = comp->steps[op->ch2].ch1;
12819
12820	if ((f != -1) &&
12821	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12822	    (comp->steps[f].value5 == NULL) &&
12823	    (comp->steps[f].value == 0) &&
12824	    (comp->steps[f].value4 != NULL) &&
12825	    (xmlStrEqual
12826	    (comp->steps[f].value4, BAD_CAST "last"))) {
12827	    xmlNodePtr last = NULL;
12828
12829	    total +=
12830		xmlXPathCompOpEvalLast(ctxt,
12831		    &comp->steps[op->ch1],
12832		    &last);
12833	    CHECK_ERROR0;
12834	    /*
12835	    * The nodeset should be in document order,
12836	    * Keep only the last value
12837	    */
12838	    if ((ctxt->value != NULL) &&
12839		(ctxt->value->type == XPATH_NODESET) &&
12840		(ctxt->value->nodesetval != NULL) &&
12841		(ctxt->value->nodesetval->nodeTab != NULL) &&
12842		(ctxt->value->nodesetval->nodeNr > 1)) {
12843		ctxt->value->nodesetval->nodeTab[0] =
12844		    ctxt->value->nodesetval->nodeTab[ctxt->
12845		    value->
12846		    nodesetval->
12847		    nodeNr -
12848		    1];
12849		ctxt->value->nodesetval->nodeNr = 1;
12850		*first = *(ctxt->value->nodesetval->nodeTab);
12851	    }
12852	    return (total);
12853	}
12854    }
12855
12856    if (op->ch1 != -1)
12857	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12858    CHECK_ERROR0;
12859    if (op->ch2 == -1)
12860	return (total);
12861    if (ctxt->value == NULL)
12862	return (total);
12863
12864#ifdef LIBXML_XPTR_ENABLED
12865    oldnode = ctxt->context->node;
12866    /*
12867    * Hum are we filtering the result of an XPointer expression
12868    */
12869    if (ctxt->value->type == XPATH_LOCATIONSET) {
12870	xmlXPathObjectPtr tmp = NULL;
12871	xmlLocationSetPtr newlocset = NULL;
12872	xmlLocationSetPtr oldlocset;
12873
12874	/*
12875	* Extract the old locset, and then evaluate the result of the
12876	* expression for all the element in the locset. use it to grow
12877	* up a new locset.
12878	*/
12879	CHECK_TYPE0(XPATH_LOCATIONSET);
12880	obj = valuePop(ctxt);
12881	oldlocset = obj->user;
12882	ctxt->context->node = NULL;
12883
12884	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12885	    ctxt->context->contextSize = 0;
12886	    ctxt->context->proximityPosition = 0;
12887	    if (op->ch2 != -1)
12888		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12889	    res = valuePop(ctxt);
12890	    if (res != NULL) {
12891		xmlXPathReleaseObject(ctxt->context, res);
12892	    }
12893	    valuePush(ctxt, obj);
12894	    CHECK_ERROR0;
12895	    return (total);
12896	}
12897	newlocset = xmlXPtrLocationSetCreate(NULL);
12898
12899	for (i = 0; i < oldlocset->locNr; i++) {
12900	    /*
12901	    * Run the evaluation with a node list made of a
12902	    * single item in the nodelocset.
12903	    */
12904	    ctxt->context->node = oldlocset->locTab[i]->user;
12905	    ctxt->context->contextSize = oldlocset->locNr;
12906	    ctxt->context->proximityPosition = i + 1;
12907	    if (tmp == NULL) {
12908		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12909		    ctxt->context->node);
12910	    } else {
12911		xmlXPathNodeSetAddUnique(tmp->nodesetval,
12912		    ctxt->context->node);
12913	    }
12914	    valuePush(ctxt, tmp);
12915	    if (op->ch2 != -1)
12916		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12917	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12918		xmlXPathFreeObject(obj);
12919		return(0);
12920	    }
12921	    /*
12922	    * The result of the evaluation need to be tested to
12923	    * decided whether the filter succeeded or not
12924	    */
12925	    res = valuePop(ctxt);
12926	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12927		xmlXPtrLocationSetAdd(newlocset,
12928		    xmlXPathCacheObjectCopy(ctxt->context,
12929			oldlocset->locTab[i]));
12930	    }
12931	    /*
12932	    * Cleanup
12933	    */
12934	    if (res != NULL) {
12935		xmlXPathReleaseObject(ctxt->context, res);
12936	    }
12937	    if (ctxt->value == tmp) {
12938		valuePop(ctxt);
12939		xmlXPathNodeSetClear(tmp->nodesetval, 1);
12940		/*
12941		* REVISIT TODO: Don't create a temporary nodeset
12942		* for everly iteration.
12943		*/
12944		/* OLD: xmlXPathFreeObject(res); */
12945	    } else
12946		tmp = NULL;
12947	    ctxt->context->node = NULL;
12948	    /*
12949	    * Only put the first node in the result, then leave.
12950	    */
12951	    if (newlocset->locNr > 0) {
12952		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
12953		break;
12954	    }
12955	}
12956	if (tmp != NULL) {
12957	    xmlXPathReleaseObject(ctxt->context, tmp);
12958	}
12959	/*
12960	* The result is used as the new evaluation locset.
12961	*/
12962	xmlXPathReleaseObject(ctxt->context, obj);
12963	ctxt->context->node = NULL;
12964	ctxt->context->contextSize = -1;
12965	ctxt->context->proximityPosition = -1;
12966	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12967	ctxt->context->node = oldnode;
12968	return (total);
12969    }
12970#endif /* LIBXML_XPTR_ENABLED */
12971
12972    /*
12973    * Extract the old set, and then evaluate the result of the
12974    * expression for all the element in the set. use it to grow
12975    * up a new set.
12976    */
12977    CHECK_TYPE0(XPATH_NODESET);
12978    obj = valuePop(ctxt);
12979    oldset = obj->nodesetval;
12980
12981    oldnode = ctxt->context->node;
12982    oldDoc = ctxt->context->doc;
12983    ctxt->context->node = NULL;
12984
12985    if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12986	ctxt->context->contextSize = 0;
12987	ctxt->context->proximityPosition = 0;
12988	/* QUESTION TODO: Why was this code commented out?
12989	    if (op->ch2 != -1)
12990		total +=
12991		    xmlXPathCompOpEval(ctxt,
12992			&comp->steps[op->ch2]);
12993	    CHECK_ERROR0;
12994	    res = valuePop(ctxt);
12995	    if (res != NULL)
12996		xmlXPathFreeObject(res);
12997	*/
12998	valuePush(ctxt, obj);
12999	ctxt->context->node = oldnode;
13000	CHECK_ERROR0;
13001    } else {
13002	xmlNodeSetPtr newset;
13003	xmlXPathObjectPtr tmp = NULL;
13004	/*
13005	* Initialize the new set.
13006	* Also set the xpath document in case things like
13007	* key() evaluation are attempted on the predicate
13008	*/
13009	newset = xmlXPathNodeSetCreate(NULL);
13010        /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13011
13012	for (i = 0; i < oldset->nodeNr; i++) {
13013	    /*
13014	    * Run the evaluation with a node list made of
13015	    * a single item in the nodeset.
13016	    */
13017	    ctxt->context->node = oldset->nodeTab[i];
13018	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13019		(oldset->nodeTab[i]->doc != NULL))
13020		ctxt->context->doc = oldset->nodeTab[i]->doc;
13021	    if (tmp == NULL) {
13022		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13023		    ctxt->context->node);
13024	    } else {
13025		xmlXPathNodeSetAddUnique(tmp->nodesetval,
13026		    ctxt->context->node);
13027	    }
13028	    valuePush(ctxt, tmp);
13029	    ctxt->context->contextSize = oldset->nodeNr;
13030	    ctxt->context->proximityPosition = i + 1;
13031	    if (op->ch2 != -1)
13032		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13033	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13034		xmlXPathFreeNodeSet(newset);
13035		xmlXPathFreeObject(obj);
13036		return(0);
13037	    }
13038	    /*
13039	    * The result of the evaluation needs to be tested to
13040	    * decide whether the filter succeeded or not
13041	    */
13042	    res = valuePop(ctxt);
13043	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13044		xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13045	    }
13046	    /*
13047	    * Cleanup
13048	    */
13049	    if (res != NULL) {
13050		xmlXPathReleaseObject(ctxt->context, res);
13051	    }
13052	    if (ctxt->value == tmp) {
13053		valuePop(ctxt);
13054		/*
13055		* Don't free the temporary nodeset
13056		* in order to avoid massive recreation inside this
13057		* loop.
13058		*/
13059		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13060	    } else
13061		tmp = NULL;
13062	    ctxt->context->node = NULL;
13063	    /*
13064	    * Only put the first node in the result, then leave.
13065	    */
13066	    if (newset->nodeNr > 0) {
13067		*first = *(newset->nodeTab);
13068		break;
13069	    }
13070	}
13071	if (tmp != NULL) {
13072	    xmlXPathReleaseObject(ctxt->context, tmp);
13073	}
13074	/*
13075	* The result is used as the new evaluation set.
13076	*/
13077	xmlXPathReleaseObject(ctxt->context, obj);
13078	ctxt->context->node = NULL;
13079	ctxt->context->contextSize = -1;
13080	ctxt->context->proximityPosition = -1;
13081	/* may want to move this past the '}' later */
13082	ctxt->context->doc = oldDoc;
13083	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13084    }
13085    ctxt->context->node = oldnode;
13086    return(total);
13087}
13088#endif /* XP_OPTIMIZED_FILTER_FIRST */
13089
13090/**
13091 * xmlXPathCompOpEval:
13092 * @ctxt:  the XPath parser context with the compiled expression
13093 * @op:  an XPath compiled operation
13094 *
13095 * Evaluate the Precompiled XPath operation
13096 * Returns the number of nodes traversed
13097 */
13098static int
13099xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13100{
13101    int total = 0;
13102    int equal, ret;
13103    xmlXPathCompExprPtr comp;
13104    xmlXPathObjectPtr arg1, arg2;
13105    xmlNodePtr bak;
13106    xmlDocPtr bakd;
13107    int pp;
13108    int cs;
13109
13110    CHECK_ERROR0;
13111    comp = ctxt->comp;
13112    switch (op->op) {
13113        case XPATH_OP_END:
13114            return (0);
13115        case XPATH_OP_AND:
13116	    bakd = ctxt->context->doc;
13117	    bak = ctxt->context->node;
13118	    pp = ctxt->context->proximityPosition;
13119	    cs = ctxt->context->contextSize;
13120            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13121	    CHECK_ERROR0;
13122            xmlXPathBooleanFunction(ctxt, 1);
13123            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13124                return (total);
13125            arg2 = valuePop(ctxt);
13126	    ctxt->context->doc = bakd;
13127	    ctxt->context->node = bak;
13128	    ctxt->context->proximityPosition = pp;
13129	    ctxt->context->contextSize = cs;
13130            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13131	    if (ctxt->error) {
13132		xmlXPathFreeObject(arg2);
13133		return(0);
13134	    }
13135            xmlXPathBooleanFunction(ctxt, 1);
13136            arg1 = valuePop(ctxt);
13137            arg1->boolval &= arg2->boolval;
13138            valuePush(ctxt, arg1);
13139	    xmlXPathReleaseObject(ctxt->context, arg2);
13140            return (total);
13141        case XPATH_OP_OR:
13142	    bakd = ctxt->context->doc;
13143	    bak = ctxt->context->node;
13144	    pp = ctxt->context->proximityPosition;
13145	    cs = ctxt->context->contextSize;
13146            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13147	    CHECK_ERROR0;
13148            xmlXPathBooleanFunction(ctxt, 1);
13149            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13150                return (total);
13151            arg2 = valuePop(ctxt);
13152	    ctxt->context->doc = bakd;
13153	    ctxt->context->node = bak;
13154	    ctxt->context->proximityPosition = pp;
13155	    ctxt->context->contextSize = cs;
13156            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13157	    if (ctxt->error) {
13158		xmlXPathFreeObject(arg2);
13159		return(0);
13160	    }
13161            xmlXPathBooleanFunction(ctxt, 1);
13162            arg1 = valuePop(ctxt);
13163            arg1->boolval |= arg2->boolval;
13164            valuePush(ctxt, arg1);
13165	    xmlXPathReleaseObject(ctxt->context, arg2);
13166            return (total);
13167        case XPATH_OP_EQUAL:
13168	    bakd = ctxt->context->doc;
13169	    bak = ctxt->context->node;
13170	    pp = ctxt->context->proximityPosition;
13171	    cs = ctxt->context->contextSize;
13172            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13173	    CHECK_ERROR0;
13174	    ctxt->context->doc = bakd;
13175	    ctxt->context->node = bak;
13176	    ctxt->context->proximityPosition = pp;
13177	    ctxt->context->contextSize = cs;
13178            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13179	    CHECK_ERROR0;
13180	    if (op->value)
13181		equal = xmlXPathEqualValues(ctxt);
13182	    else
13183		equal = xmlXPathNotEqualValues(ctxt);
13184	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13185            return (total);
13186        case XPATH_OP_CMP:
13187	    bakd = ctxt->context->doc;
13188	    bak = ctxt->context->node;
13189	    pp = ctxt->context->proximityPosition;
13190	    cs = ctxt->context->contextSize;
13191            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13192	    CHECK_ERROR0;
13193	    ctxt->context->doc = bakd;
13194	    ctxt->context->node = bak;
13195	    ctxt->context->proximityPosition = pp;
13196	    ctxt->context->contextSize = cs;
13197            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13198	    CHECK_ERROR0;
13199            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13200	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13201            return (total);
13202        case XPATH_OP_PLUS:
13203	    bakd = ctxt->context->doc;
13204	    bak = ctxt->context->node;
13205	    pp = ctxt->context->proximityPosition;
13206	    cs = ctxt->context->contextSize;
13207            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13208	    CHECK_ERROR0;
13209            if (op->ch2 != -1) {
13210		ctxt->context->doc = bakd;
13211		ctxt->context->node = bak;
13212		ctxt->context->proximityPosition = pp;
13213		ctxt->context->contextSize = cs;
13214                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13215	    }
13216	    CHECK_ERROR0;
13217            if (op->value == 0)
13218                xmlXPathSubValues(ctxt);
13219            else if (op->value == 1)
13220                xmlXPathAddValues(ctxt);
13221            else if (op->value == 2)
13222                xmlXPathValueFlipSign(ctxt);
13223            else if (op->value == 3) {
13224                CAST_TO_NUMBER;
13225                CHECK_TYPE0(XPATH_NUMBER);
13226            }
13227            return (total);
13228        case XPATH_OP_MULT:
13229	    bakd = ctxt->context->doc;
13230	    bak = ctxt->context->node;
13231	    pp = ctxt->context->proximityPosition;
13232	    cs = ctxt->context->contextSize;
13233            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13234	    CHECK_ERROR0;
13235	    ctxt->context->doc = bakd;
13236	    ctxt->context->node = bak;
13237	    ctxt->context->proximityPosition = pp;
13238	    ctxt->context->contextSize = cs;
13239            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13240	    CHECK_ERROR0;
13241            if (op->value == 0)
13242                xmlXPathMultValues(ctxt);
13243            else if (op->value == 1)
13244                xmlXPathDivValues(ctxt);
13245            else if (op->value == 2)
13246                xmlXPathModValues(ctxt);
13247            return (total);
13248        case XPATH_OP_UNION:
13249	    bakd = ctxt->context->doc;
13250	    bak = ctxt->context->node;
13251	    pp = ctxt->context->proximityPosition;
13252	    cs = ctxt->context->contextSize;
13253            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13254	    CHECK_ERROR0;
13255	    ctxt->context->doc = bakd;
13256	    ctxt->context->node = bak;
13257	    ctxt->context->proximityPosition = pp;
13258	    ctxt->context->contextSize = cs;
13259            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13260	    CHECK_ERROR0;
13261            CHECK_TYPE0(XPATH_NODESET);
13262            arg2 = valuePop(ctxt);
13263
13264            CHECK_TYPE0(XPATH_NODESET);
13265            arg1 = valuePop(ctxt);
13266
13267	    if ((arg1->nodesetval == NULL) ||
13268		((arg2->nodesetval != NULL) &&
13269		 (arg2->nodesetval->nodeNr != 0)))
13270	    {
13271		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13272							arg2->nodesetval);
13273	    }
13274
13275            valuePush(ctxt, arg1);
13276	    xmlXPathReleaseObject(ctxt->context, arg2);
13277            return (total);
13278        case XPATH_OP_ROOT:
13279            xmlXPathRoot(ctxt);
13280            return (total);
13281        case XPATH_OP_NODE:
13282            if (op->ch1 != -1)
13283                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13284	    CHECK_ERROR0;
13285            if (op->ch2 != -1)
13286                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13287	    CHECK_ERROR0;
13288	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13289		ctxt->context->node));
13290            return (total);
13291        case XPATH_OP_RESET:
13292            if (op->ch1 != -1)
13293                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13294	    CHECK_ERROR0;
13295            if (op->ch2 != -1)
13296                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13297	    CHECK_ERROR0;
13298            ctxt->context->node = NULL;
13299            return (total);
13300        case XPATH_OP_COLLECT:{
13301                if (op->ch1 == -1)
13302                    return (total);
13303
13304                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13305		CHECK_ERROR0;
13306
13307                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13308                return (total);
13309            }
13310        case XPATH_OP_VALUE:
13311            valuePush(ctxt,
13312                      xmlXPathCacheObjectCopy(ctxt->context,
13313			(xmlXPathObjectPtr) op->value4));
13314            return (total);
13315        case XPATH_OP_VARIABLE:{
13316		xmlXPathObjectPtr val;
13317
13318                if (op->ch1 != -1)
13319                    total +=
13320                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13321                if (op->value5 == NULL) {
13322		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13323		    if (val == NULL) {
13324			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13325			return(0);
13326		    }
13327                    valuePush(ctxt, val);
13328		} else {
13329                    const xmlChar *URI;
13330
13331                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13332                    if (URI == NULL) {
13333                        xmlGenericError(xmlGenericErrorContext,
13334            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13335                                    (char *) op->value4, (char *)op->value5);
13336                        return (total);
13337                    }
13338		    val = xmlXPathVariableLookupNS(ctxt->context,
13339                                                       op->value4, URI);
13340		    if (val == NULL) {
13341			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13342			return(0);
13343		    }
13344                    valuePush(ctxt, val);
13345                }
13346                return (total);
13347            }
13348        case XPATH_OP_FUNCTION:{
13349                xmlXPathFunction func;
13350                const xmlChar *oldFunc, *oldFuncURI;
13351		int i;
13352
13353                if (op->ch1 != -1)
13354                    total +=
13355                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13356		if (ctxt->valueNr < op->value) {
13357		    xmlGenericError(xmlGenericErrorContext,
13358			    "xmlXPathCompOpEval: parameter error\n");
13359		    ctxt->error = XPATH_INVALID_OPERAND;
13360		    return (total);
13361		}
13362		for (i = 0; i < op->value; i++)
13363		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13364			xmlGenericError(xmlGenericErrorContext,
13365				"xmlXPathCompOpEval: parameter error\n");
13366			ctxt->error = XPATH_INVALID_OPERAND;
13367			return (total);
13368		    }
13369                if (op->cache != NULL)
13370                    XML_CAST_FPTR(func) = op->cache;
13371                else {
13372                    const xmlChar *URI = NULL;
13373
13374                    if (op->value5 == NULL)
13375                        func =
13376                            xmlXPathFunctionLookup(ctxt->context,
13377                                                   op->value4);
13378                    else {
13379                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13380                        if (URI == NULL) {
13381                            xmlGenericError(xmlGenericErrorContext,
13382            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13383                                    (char *)op->value4, (char *)op->value5);
13384                            return (total);
13385                        }
13386                        func = xmlXPathFunctionLookupNS(ctxt->context,
13387                                                        op->value4, URI);
13388                    }
13389                    if (func == NULL) {
13390                        xmlGenericError(xmlGenericErrorContext,
13391                                "xmlXPathCompOpEval: function %s not found\n",
13392                                        (char *)op->value4);
13393                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13394                    }
13395                    op->cache = XML_CAST_FPTR(func);
13396                    op->cacheURI = (void *) URI;
13397                }
13398                oldFunc = ctxt->context->function;
13399                oldFuncURI = ctxt->context->functionURI;
13400                ctxt->context->function = op->value4;
13401                ctxt->context->functionURI = op->cacheURI;
13402                func(ctxt, op->value);
13403                ctxt->context->function = oldFunc;
13404                ctxt->context->functionURI = oldFuncURI;
13405                return (total);
13406            }
13407        case XPATH_OP_ARG:
13408	    bakd = ctxt->context->doc;
13409	    bak = ctxt->context->node;
13410	    pp = ctxt->context->proximityPosition;
13411	    cs = ctxt->context->contextSize;
13412            if (op->ch1 != -1)
13413                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13414	    ctxt->context->contextSize = cs;
13415	    ctxt->context->proximityPosition = pp;
13416	    ctxt->context->node = bak;
13417	    ctxt->context->doc = bakd;
13418	    CHECK_ERROR0;
13419            if (op->ch2 != -1) {
13420                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13421	        ctxt->context->doc = bakd;
13422	        ctxt->context->node = bak;
13423	        CHECK_ERROR0;
13424	    }
13425            return (total);
13426        case XPATH_OP_PREDICATE:
13427        case XPATH_OP_FILTER:{
13428                xmlXPathObjectPtr res;
13429                xmlXPathObjectPtr obj, tmp;
13430                xmlNodeSetPtr newset = NULL;
13431                xmlNodeSetPtr oldset;
13432                xmlNodePtr oldnode;
13433		xmlDocPtr oldDoc;
13434                int i;
13435
13436                /*
13437                 * Optimization for ()[1] selection i.e. the first elem
13438                 */
13439                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13440#ifdef XP_OPTIMIZED_FILTER_FIRST
13441		    /*
13442		    * FILTER TODO: Can we assume that the inner processing
13443		    *  will result in an ordered list if we have an
13444		    *  XPATH_OP_FILTER?
13445		    *  What about an additional field or flag on
13446		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13447		    *  to assume anything, so it would be more robust and
13448		    *  easier to optimize.
13449		    */
13450                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13451		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13452#else
13453		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13454#endif
13455                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13456                    xmlXPathObjectPtr val;
13457
13458                    val = comp->steps[op->ch2].value4;
13459                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13460                        (val->floatval == 1.0)) {
13461                        xmlNodePtr first = NULL;
13462
13463                        total +=
13464                            xmlXPathCompOpEvalFirst(ctxt,
13465                                                    &comp->steps[op->ch1],
13466                                                    &first);
13467			CHECK_ERROR0;
13468                        /*
13469                         * The nodeset should be in document order,
13470                         * Keep only the first value
13471                         */
13472                        if ((ctxt->value != NULL) &&
13473                            (ctxt->value->type == XPATH_NODESET) &&
13474                            (ctxt->value->nodesetval != NULL) &&
13475                            (ctxt->value->nodesetval->nodeNr > 1))
13476                            ctxt->value->nodesetval->nodeNr = 1;
13477                        return (total);
13478                    }
13479                }
13480                /*
13481                 * Optimization for ()[last()] selection i.e. the last elem
13482                 */
13483                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13484                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13485                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13486                    int f = comp->steps[op->ch2].ch1;
13487
13488                    if ((f != -1) &&
13489                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13490                        (comp->steps[f].value5 == NULL) &&
13491                        (comp->steps[f].value == 0) &&
13492                        (comp->steps[f].value4 != NULL) &&
13493                        (xmlStrEqual
13494                         (comp->steps[f].value4, BAD_CAST "last"))) {
13495                        xmlNodePtr last = NULL;
13496
13497                        total +=
13498                            xmlXPathCompOpEvalLast(ctxt,
13499                                                   &comp->steps[op->ch1],
13500                                                   &last);
13501			CHECK_ERROR0;
13502                        /*
13503                         * The nodeset should be in document order,
13504                         * Keep only the last value
13505                         */
13506                        if ((ctxt->value != NULL) &&
13507                            (ctxt->value->type == XPATH_NODESET) &&
13508                            (ctxt->value->nodesetval != NULL) &&
13509                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13510                            (ctxt->value->nodesetval->nodeNr > 1)) {
13511                            ctxt->value->nodesetval->nodeTab[0] =
13512                                ctxt->value->nodesetval->nodeTab[ctxt->
13513                                                                 value->
13514                                                                 nodesetval->
13515                                                                 nodeNr -
13516                                                                 1];
13517                            ctxt->value->nodesetval->nodeNr = 1;
13518                        }
13519                        return (total);
13520                    }
13521                }
13522		/*
13523		* Process inner predicates first.
13524		* Example "index[parent::book][1]":
13525		* ...
13526		*   PREDICATE   <-- we are here "[1]"
13527		*     PREDICATE <-- process "[parent::book]" first
13528		*       SORT
13529		*         COLLECT  'parent' 'name' 'node' book
13530		*           NODE
13531		*     ELEM Object is a number : 1
13532		*/
13533                if (op->ch1 != -1)
13534                    total +=
13535                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13536		CHECK_ERROR0;
13537                if (op->ch2 == -1)
13538                    return (total);
13539                if (ctxt->value == NULL)
13540                    return (total);
13541
13542                oldnode = ctxt->context->node;
13543
13544#ifdef LIBXML_XPTR_ENABLED
13545                /*
13546                 * Hum are we filtering the result of an XPointer expression
13547                 */
13548                if (ctxt->value->type == XPATH_LOCATIONSET) {
13549                    xmlLocationSetPtr newlocset = NULL;
13550                    xmlLocationSetPtr oldlocset;
13551
13552                    /*
13553                     * Extract the old locset, and then evaluate the result of the
13554                     * expression for all the element in the locset. use it to grow
13555                     * up a new locset.
13556                     */
13557                    CHECK_TYPE0(XPATH_LOCATIONSET);
13558                    obj = valuePop(ctxt);
13559                    oldlocset = obj->user;
13560                    ctxt->context->node = NULL;
13561
13562                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13563                        ctxt->context->contextSize = 0;
13564                        ctxt->context->proximityPosition = 0;
13565                        if (op->ch2 != -1)
13566                            total +=
13567                                xmlXPathCompOpEval(ctxt,
13568                                                   &comp->steps[op->ch2]);
13569                        res = valuePop(ctxt);
13570                        if (res != NULL) {
13571			    xmlXPathReleaseObject(ctxt->context, res);
13572			}
13573                        valuePush(ctxt, obj);
13574                        CHECK_ERROR0;
13575                        return (total);
13576                    }
13577                    newlocset = xmlXPtrLocationSetCreate(NULL);
13578
13579                    for (i = 0; i < oldlocset->locNr; i++) {
13580                        /*
13581                         * Run the evaluation with a node list made of a
13582                         * single item in the nodelocset.
13583                         */
13584                        ctxt->context->node = oldlocset->locTab[i]->user;
13585                        ctxt->context->contextSize = oldlocset->locNr;
13586                        ctxt->context->proximityPosition = i + 1;
13587			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13588			    ctxt->context->node);
13589                        valuePush(ctxt, tmp);
13590
13591                        if (op->ch2 != -1)
13592                            total +=
13593                                xmlXPathCompOpEval(ctxt,
13594                                                   &comp->steps[op->ch2]);
13595			if (ctxt->error != XPATH_EXPRESSION_OK) {
13596			    xmlXPathFreeObject(obj);
13597			    return(0);
13598			}
13599
13600                        /*
13601                         * The result of the evaluation need to be tested to
13602                         * decided whether the filter succeeded or not
13603                         */
13604                        res = valuePop(ctxt);
13605                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13606                            xmlXPtrLocationSetAdd(newlocset,
13607                                                  xmlXPathObjectCopy
13608                                                  (oldlocset->locTab[i]));
13609                        }
13610
13611                        /*
13612                         * Cleanup
13613                         */
13614                        if (res != NULL) {
13615			    xmlXPathReleaseObject(ctxt->context, res);
13616			}
13617                        if (ctxt->value == tmp) {
13618                            res = valuePop(ctxt);
13619			    xmlXPathReleaseObject(ctxt->context, res);
13620                        }
13621
13622                        ctxt->context->node = NULL;
13623                    }
13624
13625                    /*
13626                     * The result is used as the new evaluation locset.
13627                     */
13628		    xmlXPathReleaseObject(ctxt->context, obj);
13629                    ctxt->context->node = NULL;
13630                    ctxt->context->contextSize = -1;
13631                    ctxt->context->proximityPosition = -1;
13632                    valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13633                    ctxt->context->node = oldnode;
13634                    return (total);
13635                }
13636#endif /* LIBXML_XPTR_ENABLED */
13637
13638                /*
13639                 * Extract the old set, and then evaluate the result of the
13640                 * expression for all the element in the set. use it to grow
13641                 * up a new set.
13642                 */
13643                CHECK_TYPE0(XPATH_NODESET);
13644                obj = valuePop(ctxt);
13645                oldset = obj->nodesetval;
13646
13647                oldnode = ctxt->context->node;
13648		oldDoc = ctxt->context->doc;
13649                ctxt->context->node = NULL;
13650
13651                if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13652                    ctxt->context->contextSize = 0;
13653                    ctxt->context->proximityPosition = 0;
13654/*
13655                    if (op->ch2 != -1)
13656                        total +=
13657                            xmlXPathCompOpEval(ctxt,
13658                                               &comp->steps[op->ch2]);
13659		    CHECK_ERROR0;
13660                    res = valuePop(ctxt);
13661                    if (res != NULL)
13662                        xmlXPathFreeObject(res);
13663*/
13664                    valuePush(ctxt, obj);
13665                    ctxt->context->node = oldnode;
13666                    CHECK_ERROR0;
13667                } else {
13668		    tmp = NULL;
13669                    /*
13670                     * Initialize the new set.
13671		     * Also set the xpath document in case things like
13672		     * key() evaluation are attempted on the predicate
13673                     */
13674                    newset = xmlXPathNodeSetCreate(NULL);
13675		    /*
13676		    * SPEC XPath 1.0:
13677		    *  "For each node in the node-set to be filtered, the
13678		    *  PredicateExpr is evaluated with that node as the
13679		    *  context node, with the number of nodes in the
13680		    *  node-set as the context size, and with the proximity
13681		    *  position of the node in the node-set with respect to
13682		    *  the axis as the context position;"
13683		    * @oldset is the node-set" to be filtered.
13684		    *
13685		    * SPEC XPath 1.0:
13686		    *  "only predicates change the context position and
13687		    *  context size (see [2.4 Predicates])."
13688		    * Example:
13689		    *   node-set  context pos
13690		    *    nA         1
13691		    *    nB         2
13692		    *    nC         3
13693		    *   After applying predicate [position() > 1] :
13694		    *   node-set  context pos
13695		    *    nB         1
13696		    *    nC         2
13697		    *
13698		    * removed the first node in the node-set, then
13699		    * the context position of the
13700		    */
13701                    for (i = 0; i < oldset->nodeNr; i++) {
13702                        /*
13703                         * Run the evaluation with a node list made of
13704                         * a single item in the nodeset.
13705                         */
13706                        ctxt->context->node = oldset->nodeTab[i];
13707			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13708			    (oldset->nodeTab[i]->doc != NULL))
13709		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13710			if (tmp == NULL) {
13711			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13712				ctxt->context->node);
13713			} else {
13714			    xmlXPathNodeSetAddUnique(tmp->nodesetval,
13715				ctxt->context->node);
13716			}
13717                        valuePush(ctxt, tmp);
13718                        ctxt->context->contextSize = oldset->nodeNr;
13719                        ctxt->context->proximityPosition = i + 1;
13720			/*
13721			* Evaluate the predicate against the context node.
13722			* Can/should we optimize position() predicates
13723			* here (e.g. "[1]")?
13724			*/
13725                        if (op->ch2 != -1)
13726                            total +=
13727                                xmlXPathCompOpEval(ctxt,
13728                                                   &comp->steps[op->ch2]);
13729			if (ctxt->error != XPATH_EXPRESSION_OK) {
13730			    xmlXPathFreeNodeSet(newset);
13731			    xmlXPathFreeObject(obj);
13732			    return(0);
13733			}
13734
13735                        /*
13736                         * The result of the evaluation needs to be tested to
13737                         * decide whether the filter succeeded or not
13738                         */
13739			/*
13740			* OPTIMIZE TODO: Can we use
13741			* xmlXPathNodeSetAdd*Unique()* instead?
13742			*/
13743                        res = valuePop(ctxt);
13744                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13745                            xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13746                        }
13747
13748                        /*
13749                         * Cleanup
13750                         */
13751                        if (res != NULL) {
13752			    xmlXPathReleaseObject(ctxt->context, res);
13753			}
13754                        if (ctxt->value == tmp) {
13755                            valuePop(ctxt);
13756			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13757			    /*
13758			    * Don't free the temporary nodeset
13759			    * in order to avoid massive recreation inside this
13760			    * loop.
13761			    */
13762                        } else
13763			    tmp = NULL;
13764                        ctxt->context->node = NULL;
13765                    }
13766		    if (tmp != NULL)
13767			xmlXPathReleaseObject(ctxt->context, tmp);
13768                    /*
13769                     * The result is used as the new evaluation set.
13770                     */
13771		    xmlXPathReleaseObject(ctxt->context, obj);
13772                    ctxt->context->node = NULL;
13773                    ctxt->context->contextSize = -1;
13774                    ctxt->context->proximityPosition = -1;
13775		    /* may want to move this past the '}' later */
13776		    ctxt->context->doc = oldDoc;
13777		    valuePush(ctxt,
13778			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13779                }
13780                ctxt->context->node = oldnode;
13781                return (total);
13782            }
13783        case XPATH_OP_SORT:
13784            if (op->ch1 != -1)
13785                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13786	    CHECK_ERROR0;
13787            if ((ctxt->value != NULL) &&
13788                (ctxt->value->type == XPATH_NODESET) &&
13789                (ctxt->value->nodesetval != NULL) &&
13790		(ctxt->value->nodesetval->nodeNr > 1))
13791	    {
13792                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13793	    }
13794            return (total);
13795#ifdef LIBXML_XPTR_ENABLED
13796        case XPATH_OP_RANGETO:{
13797                xmlXPathObjectPtr range;
13798                xmlXPathObjectPtr res, obj;
13799                xmlXPathObjectPtr tmp;
13800                xmlLocationSetPtr newlocset = NULL;
13801		    xmlLocationSetPtr oldlocset;
13802                xmlNodeSetPtr oldset;
13803                int i, j;
13804
13805                if (op->ch1 != -1)
13806                    total +=
13807                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13808                if (op->ch2 == -1)
13809                    return (total);
13810
13811                if (ctxt->value->type == XPATH_LOCATIONSET) {
13812                    /*
13813                     * Extract the old locset, and then evaluate the result of the
13814                     * expression for all the element in the locset. use it to grow
13815                     * up a new locset.
13816                     */
13817                    CHECK_TYPE0(XPATH_LOCATIONSET);
13818                    obj = valuePop(ctxt);
13819                    oldlocset = obj->user;
13820
13821                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13822		        ctxt->context->node = NULL;
13823                        ctxt->context->contextSize = 0;
13824                        ctxt->context->proximityPosition = 0;
13825                        total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13826                        res = valuePop(ctxt);
13827                        if (res != NULL) {
13828			    xmlXPathReleaseObject(ctxt->context, res);
13829			}
13830                        valuePush(ctxt, obj);
13831                        CHECK_ERROR0;
13832                        return (total);
13833                    }
13834                    newlocset = xmlXPtrLocationSetCreate(NULL);
13835
13836                    for (i = 0; i < oldlocset->locNr; i++) {
13837                        /*
13838                         * Run the evaluation with a node list made of a
13839                         * single item in the nodelocset.
13840                         */
13841                        ctxt->context->node = oldlocset->locTab[i]->user;
13842                        ctxt->context->contextSize = oldlocset->locNr;
13843                        ctxt->context->proximityPosition = i + 1;
13844			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13845			    ctxt->context->node);
13846                        valuePush(ctxt, tmp);
13847
13848                        if (op->ch2 != -1)
13849                            total +=
13850                                xmlXPathCompOpEval(ctxt,
13851                                                   &comp->steps[op->ch2]);
13852			if (ctxt->error != XPATH_EXPRESSION_OK) {
13853			    xmlXPathFreeObject(obj);
13854			    return(0);
13855			}
13856
13857                        res = valuePop(ctxt);
13858			if (res->type == XPATH_LOCATIONSET) {
13859			    xmlLocationSetPtr rloc =
13860			        (xmlLocationSetPtr)res->user;
13861			    for (j=0; j<rloc->locNr; j++) {
13862			        range = xmlXPtrNewRange(
13863				  oldlocset->locTab[i]->user,
13864				  oldlocset->locTab[i]->index,
13865				  rloc->locTab[j]->user2,
13866				  rloc->locTab[j]->index2);
13867				if (range != NULL) {
13868				    xmlXPtrLocationSetAdd(newlocset, range);
13869				}
13870			    }
13871			} else {
13872			    range = xmlXPtrNewRangeNodeObject(
13873				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13874                            if (range != NULL) {
13875                                xmlXPtrLocationSetAdd(newlocset,range);
13876			    }
13877                        }
13878
13879                        /*
13880                         * Cleanup
13881                         */
13882                        if (res != NULL) {
13883			    xmlXPathReleaseObject(ctxt->context, res);
13884			}
13885                        if (ctxt->value == tmp) {
13886                            res = valuePop(ctxt);
13887			    xmlXPathReleaseObject(ctxt->context, res);
13888                        }
13889
13890                        ctxt->context->node = NULL;
13891                    }
13892		} else {	/* Not a location set */
13893                    CHECK_TYPE0(XPATH_NODESET);
13894                    obj = valuePop(ctxt);
13895                    oldset = obj->nodesetval;
13896                    ctxt->context->node = NULL;
13897
13898                    newlocset = xmlXPtrLocationSetCreate(NULL);
13899
13900                    if (oldset != NULL) {
13901                        for (i = 0; i < oldset->nodeNr; i++) {
13902                            /*
13903                             * Run the evaluation with a node list made of a single item
13904                             * in the nodeset.
13905                             */
13906                            ctxt->context->node = oldset->nodeTab[i];
13907			    /*
13908			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13909			    */
13910			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13911				ctxt->context->node);
13912                            valuePush(ctxt, tmp);
13913
13914                            if (op->ch2 != -1)
13915                                total +=
13916                                    xmlXPathCompOpEval(ctxt,
13917                                                   &comp->steps[op->ch2]);
13918			    if (ctxt->error != XPATH_EXPRESSION_OK) {
13919				xmlXPathFreeObject(obj);
13920				return(0);
13921			    }
13922
13923                            res = valuePop(ctxt);
13924                            range =
13925                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13926                                                      res);
13927                            if (range != NULL) {
13928                                xmlXPtrLocationSetAdd(newlocset, range);
13929                            }
13930
13931                            /*
13932                             * Cleanup
13933                             */
13934                            if (res != NULL) {
13935				xmlXPathReleaseObject(ctxt->context, res);
13936			    }
13937                            if (ctxt->value == tmp) {
13938                                res = valuePop(ctxt);
13939				xmlXPathReleaseObject(ctxt->context, res);
13940                            }
13941
13942                            ctxt->context->node = NULL;
13943                        }
13944                    }
13945                }
13946
13947                /*
13948                 * The result is used as the new evaluation set.
13949                 */
13950		xmlXPathReleaseObject(ctxt->context, obj);
13951                ctxt->context->node = NULL;
13952                ctxt->context->contextSize = -1;
13953                ctxt->context->proximityPosition = -1;
13954                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13955                return (total);
13956            }
13957#endif /* LIBXML_XPTR_ENABLED */
13958    }
13959    xmlGenericError(xmlGenericErrorContext,
13960                    "XPath: unknown precompiled operation %d\n", op->op);
13961    return (total);
13962}
13963
13964/**
13965 * xmlXPathCompOpEvalToBoolean:
13966 * @ctxt:  the XPath parser context
13967 *
13968 * Evaluates if the expression evaluates to true.
13969 *
13970 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13971 */
13972static int
13973xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13974			    xmlXPathStepOpPtr op,
13975			    int isPredicate)
13976{
13977    xmlXPathObjectPtr resObj = NULL;
13978
13979start:
13980    /* comp = ctxt->comp; */
13981    switch (op->op) {
13982        case XPATH_OP_END:
13983            return (0);
13984	case XPATH_OP_VALUE:
13985	    resObj = (xmlXPathObjectPtr) op->value4;
13986	    if (isPredicate)
13987		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13988	    return(xmlXPathCastToBoolean(resObj));
13989	case XPATH_OP_SORT:
13990	    /*
13991	    * We don't need sorting for boolean results. Skip this one.
13992	    */
13993            if (op->ch1 != -1) {
13994		op = &ctxt->comp->steps[op->ch1];
13995		goto start;
13996	    }
13997	    return(0);
13998	case XPATH_OP_COLLECT:
13999	    if (op->ch1 == -1)
14000		return(0);
14001
14002            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14003	    if (ctxt->error != XPATH_EXPRESSION_OK)
14004		return(-1);
14005
14006            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14007	    if (ctxt->error != XPATH_EXPRESSION_OK)
14008		return(-1);
14009
14010	    resObj = valuePop(ctxt);
14011	    if (resObj == NULL)
14012		return(-1);
14013	    break;
14014	default:
14015	    /*
14016	    * Fallback to call xmlXPathCompOpEval().
14017	    */
14018	    xmlXPathCompOpEval(ctxt, op);
14019	    if (ctxt->error != XPATH_EXPRESSION_OK)
14020		return(-1);
14021
14022	    resObj = valuePop(ctxt);
14023	    if (resObj == NULL)
14024		return(-1);
14025	    break;
14026    }
14027
14028    if (resObj) {
14029	int res;
14030
14031	if (resObj->type == XPATH_BOOLEAN) {
14032	    res = resObj->boolval;
14033	} else if (isPredicate) {
14034	    /*
14035	    * For predicates a result of type "number" is handled
14036	    * differently:
14037	    * SPEC XPath 1.0:
14038	    * "If the result is a number, the result will be converted
14039	    *  to true if the number is equal to the context position
14040	    *  and will be converted to false otherwise;"
14041	    */
14042	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14043	} else {
14044	    res = xmlXPathCastToBoolean(resObj);
14045	}
14046	xmlXPathReleaseObject(ctxt->context, resObj);
14047	return(res);
14048    }
14049
14050    return(0);
14051}
14052
14053#ifdef XPATH_STREAMING
14054/**
14055 * xmlXPathRunStreamEval:
14056 * @ctxt:  the XPath parser context with the compiled expression
14057 *
14058 * Evaluate the Precompiled Streamable XPath expression in the given context.
14059 */
14060static int
14061xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14062		      xmlXPathObjectPtr *resultSeq, int toBool)
14063{
14064    int max_depth, min_depth;
14065    int from_root;
14066    int ret, depth;
14067    int eval_all_nodes;
14068    xmlNodePtr cur = NULL, limit = NULL;
14069    xmlStreamCtxtPtr patstream = NULL;
14070
14071    int nb_nodes = 0;
14072
14073    if ((ctxt == NULL) || (comp == NULL))
14074        return(-1);
14075    max_depth = xmlPatternMaxDepth(comp);
14076    if (max_depth == -1)
14077        return(-1);
14078    if (max_depth == -2)
14079        max_depth = 10000;
14080    min_depth = xmlPatternMinDepth(comp);
14081    if (min_depth == -1)
14082        return(-1);
14083    from_root = xmlPatternFromRoot(comp);
14084    if (from_root < 0)
14085        return(-1);
14086#if 0
14087    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14088#endif
14089
14090    if (! toBool) {
14091	if (resultSeq == NULL)
14092	    return(-1);
14093	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14094	if (*resultSeq == NULL)
14095	    return(-1);
14096    }
14097
14098    /*
14099     * handle the special cases of "/" amd "." being matched
14100     */
14101    if (min_depth == 0) {
14102	if (from_root) {
14103	    /* Select "/" */
14104	    if (toBool)
14105		return(1);
14106	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14107		(xmlNodePtr) ctxt->doc);
14108	} else {
14109	    /* Select "self::node()" */
14110	    if (toBool)
14111		return(1);
14112	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14113	}
14114    }
14115    if (max_depth == 0) {
14116	return(0);
14117    }
14118
14119    if (from_root) {
14120        cur = (xmlNodePtr)ctxt->doc;
14121    } else if (ctxt->node != NULL) {
14122        switch (ctxt->node->type) {
14123            case XML_ELEMENT_NODE:
14124            case XML_DOCUMENT_NODE:
14125            case XML_DOCUMENT_FRAG_NODE:
14126            case XML_HTML_DOCUMENT_NODE:
14127#ifdef LIBXML_DOCB_ENABLED
14128            case XML_DOCB_DOCUMENT_NODE:
14129#endif
14130	        cur = ctxt->node;
14131		break;
14132            case XML_ATTRIBUTE_NODE:
14133            case XML_TEXT_NODE:
14134            case XML_CDATA_SECTION_NODE:
14135            case XML_ENTITY_REF_NODE:
14136            case XML_ENTITY_NODE:
14137            case XML_PI_NODE:
14138            case XML_COMMENT_NODE:
14139            case XML_NOTATION_NODE:
14140            case XML_DTD_NODE:
14141            case XML_DOCUMENT_TYPE_NODE:
14142            case XML_ELEMENT_DECL:
14143            case XML_ATTRIBUTE_DECL:
14144            case XML_ENTITY_DECL:
14145            case XML_NAMESPACE_DECL:
14146            case XML_XINCLUDE_START:
14147            case XML_XINCLUDE_END:
14148		break;
14149	}
14150	limit = cur;
14151    }
14152    if (cur == NULL) {
14153        return(0);
14154    }
14155
14156    patstream = xmlPatternGetStreamCtxt(comp);
14157    if (patstream == NULL) {
14158	/*
14159	* QUESTION TODO: Is this an error?
14160	*/
14161	return(0);
14162    }
14163
14164    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14165
14166    if (from_root) {
14167	ret = xmlStreamPush(patstream, NULL, NULL);
14168	if (ret < 0) {
14169	} else if (ret == 1) {
14170	    if (toBool)
14171		goto return_1;
14172	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14173	}
14174    }
14175    depth = 0;
14176    goto scan_children;
14177next_node:
14178    do {
14179        nb_nodes++;
14180
14181	switch (cur->type) {
14182	    case XML_ELEMENT_NODE:
14183	    case XML_TEXT_NODE:
14184	    case XML_CDATA_SECTION_NODE:
14185	    case XML_COMMENT_NODE:
14186	    case XML_PI_NODE:
14187		if (cur->type == XML_ELEMENT_NODE) {
14188		    ret = xmlStreamPush(patstream, cur->name,
14189				(cur->ns ? cur->ns->href : NULL));
14190		} else if (eval_all_nodes)
14191		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14192		else
14193		    break;
14194
14195		if (ret < 0) {
14196		    /* NOP. */
14197		} else if (ret == 1) {
14198		    if (toBool)
14199			goto return_1;
14200		    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14201		}
14202		if ((cur->children == NULL) || (depth >= max_depth)) {
14203		    ret = xmlStreamPop(patstream);
14204		    while (cur->next != NULL) {
14205			cur = cur->next;
14206			if ((cur->type != XML_ENTITY_DECL) &&
14207			    (cur->type != XML_DTD_NODE))
14208			    goto next_node;
14209		    }
14210		}
14211	    default:
14212		break;
14213	}
14214
14215scan_children:
14216	if ((cur->children != NULL) && (depth < max_depth)) {
14217	    /*
14218	     * Do not descend on entities declarations
14219	     */
14220	    if (cur->children->type != XML_ENTITY_DECL) {
14221		cur = cur->children;
14222		depth++;
14223		/*
14224		 * Skip DTDs
14225		 */
14226		if (cur->type != XML_DTD_NODE)
14227		    continue;
14228	    }
14229	}
14230
14231	if (cur == limit)
14232	    break;
14233
14234	while (cur->next != NULL) {
14235	    cur = cur->next;
14236	    if ((cur->type != XML_ENTITY_DECL) &&
14237		(cur->type != XML_DTD_NODE))
14238		goto next_node;
14239	}
14240
14241	do {
14242	    cur = cur->parent;
14243	    depth--;
14244	    if ((cur == NULL) || (cur == limit))
14245	        goto done;
14246	    if (cur->type == XML_ELEMENT_NODE) {
14247		ret = xmlStreamPop(patstream);
14248	    } else if ((eval_all_nodes) &&
14249		((cur->type == XML_TEXT_NODE) ||
14250		 (cur->type == XML_CDATA_SECTION_NODE) ||
14251		 (cur->type == XML_COMMENT_NODE) ||
14252		 (cur->type == XML_PI_NODE)))
14253	    {
14254		ret = xmlStreamPop(patstream);
14255	    }
14256	    if (cur->next != NULL) {
14257		cur = cur->next;
14258		break;
14259	    }
14260	} while (cur != NULL);
14261
14262    } while ((cur != NULL) && (depth >= 0));
14263
14264done:
14265
14266#if 0
14267    printf("stream eval: checked %d nodes selected %d\n",
14268           nb_nodes, retObj->nodesetval->nodeNr);
14269#endif
14270
14271    if (patstream)
14272	xmlFreeStreamCtxt(patstream);
14273    return(0);
14274
14275return_1:
14276    if (patstream)
14277	xmlFreeStreamCtxt(patstream);
14278    return(1);
14279}
14280#endif /* XPATH_STREAMING */
14281
14282/**
14283 * xmlXPathRunEval:
14284 * @ctxt:  the XPath parser context with the compiled expression
14285 * @toBool:  evaluate to a boolean result
14286 *
14287 * Evaluate the Precompiled XPath expression in the given context.
14288 */
14289static int
14290xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14291{
14292    xmlXPathCompExprPtr comp;
14293
14294    if ((ctxt == NULL) || (ctxt->comp == NULL))
14295	return(-1);
14296
14297    if (ctxt->valueTab == NULL) {
14298	/* Allocate the value stack */
14299	ctxt->valueTab = (xmlXPathObjectPtr *)
14300			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14301	if (ctxt->valueTab == NULL) {
14302	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14303	    xmlFree(ctxt);
14304	}
14305	ctxt->valueNr = 0;
14306	ctxt->valueMax = 10;
14307	ctxt->value = NULL;
14308    }
14309#ifdef XPATH_STREAMING
14310    if (ctxt->comp->stream) {
14311	int res;
14312
14313	if (toBool) {
14314	    /*
14315	    * Evaluation to boolean result.
14316	    */
14317	    res = xmlXPathRunStreamEval(ctxt->context,
14318		ctxt->comp->stream, NULL, 1);
14319	    if (res != -1)
14320		return(res);
14321	} else {
14322	    xmlXPathObjectPtr resObj = NULL;
14323
14324	    /*
14325	    * Evaluation to a sequence.
14326	    */
14327	    res = xmlXPathRunStreamEval(ctxt->context,
14328		ctxt->comp->stream, &resObj, 0);
14329
14330	    if ((res != -1) && (resObj != NULL)) {
14331		valuePush(ctxt, resObj);
14332		return(0);
14333	    }
14334	    if (resObj != NULL)
14335		xmlXPathReleaseObject(ctxt->context, resObj);
14336	}
14337	/*
14338	* QUESTION TODO: This falls back to normal XPath evaluation
14339	* if res == -1. Is this intended?
14340	*/
14341    }
14342#endif
14343    comp = ctxt->comp;
14344    if (comp->last < 0) {
14345	xmlGenericError(xmlGenericErrorContext,
14346	    "xmlXPathRunEval: last is less than zero\n");
14347	return(-1);
14348    }
14349    if (toBool)
14350	return(xmlXPathCompOpEvalToBoolean(ctxt,
14351	    &comp->steps[comp->last], 0));
14352    else
14353	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14354
14355    return(0);
14356}
14357
14358/************************************************************************
14359 *									*
14360 *			Public interfaces				*
14361 *									*
14362 ************************************************************************/
14363
14364/**
14365 * xmlXPathEvalPredicate:
14366 * @ctxt:  the XPath context
14367 * @res:  the Predicate Expression evaluation result
14368 *
14369 * Evaluate a predicate result for the current node.
14370 * A PredicateExpr is evaluated by evaluating the Expr and converting
14371 * the result to a boolean. If the result is a number, the result will
14372 * be converted to true if the number is equal to the position of the
14373 * context node in the context node list (as returned by the position
14374 * function) and will be converted to false otherwise; if the result
14375 * is not a number, then the result will be converted as if by a call
14376 * to the boolean function.
14377 *
14378 * Returns 1 if predicate is true, 0 otherwise
14379 */
14380int
14381xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14382    if ((ctxt == NULL) || (res == NULL)) return(0);
14383    switch (res->type) {
14384        case XPATH_BOOLEAN:
14385	    return(res->boolval);
14386        case XPATH_NUMBER:
14387	    return(res->floatval == ctxt->proximityPosition);
14388        case XPATH_NODESET:
14389        case XPATH_XSLT_TREE:
14390	    if (res->nodesetval == NULL)
14391		return(0);
14392	    return(res->nodesetval->nodeNr != 0);
14393        case XPATH_STRING:
14394	    return((res->stringval != NULL) &&
14395	           (xmlStrlen(res->stringval) != 0));
14396        default:
14397	    STRANGE
14398    }
14399    return(0);
14400}
14401
14402/**
14403 * xmlXPathEvaluatePredicateResult:
14404 * @ctxt:  the XPath Parser context
14405 * @res:  the Predicate Expression evaluation result
14406 *
14407 * Evaluate a predicate result for the current node.
14408 * A PredicateExpr is evaluated by evaluating the Expr and converting
14409 * the result to a boolean. If the result is a number, the result will
14410 * be converted to true if the number is equal to the position of the
14411 * context node in the context node list (as returned by the position
14412 * function) and will be converted to false otherwise; if the result
14413 * is not a number, then the result will be converted as if by a call
14414 * to the boolean function.
14415 *
14416 * Returns 1 if predicate is true, 0 otherwise
14417 */
14418int
14419xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14420                                xmlXPathObjectPtr res) {
14421    if ((ctxt == NULL) || (res == NULL)) return(0);
14422    switch (res->type) {
14423        case XPATH_BOOLEAN:
14424	    return(res->boolval);
14425        case XPATH_NUMBER:
14426#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14427	    return((res->floatval == ctxt->context->proximityPosition) &&
14428	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14429#else
14430	    return(res->floatval == ctxt->context->proximityPosition);
14431#endif
14432        case XPATH_NODESET:
14433        case XPATH_XSLT_TREE:
14434	    if (res->nodesetval == NULL)
14435		return(0);
14436	    return(res->nodesetval->nodeNr != 0);
14437        case XPATH_STRING:
14438	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14439#ifdef LIBXML_XPTR_ENABLED
14440	case XPATH_LOCATIONSET:{
14441	    xmlLocationSetPtr ptr = res->user;
14442	    if (ptr == NULL)
14443	        return(0);
14444	    return (ptr->locNr != 0);
14445	    }
14446#endif
14447        default:
14448	    STRANGE
14449    }
14450    return(0);
14451}
14452
14453#ifdef XPATH_STREAMING
14454/**
14455 * xmlXPathTryStreamCompile:
14456 * @ctxt: an XPath context
14457 * @str:  the XPath expression
14458 *
14459 * Try to compile the XPath expression as a streamable subset.
14460 *
14461 * Returns the compiled expression or NULL if failed to compile.
14462 */
14463static xmlXPathCompExprPtr
14464xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14465    /*
14466     * Optimization: use streaming patterns when the XPath expression can
14467     * be compiled to a stream lookup
14468     */
14469    xmlPatternPtr stream;
14470    xmlXPathCompExprPtr comp;
14471    xmlDictPtr dict = NULL;
14472    const xmlChar **namespaces = NULL;
14473    xmlNsPtr ns;
14474    int i, j;
14475
14476    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14477        (!xmlStrchr(str, '@'))) {
14478	const xmlChar *tmp;
14479
14480	/*
14481	 * We don't try to handle expressions using the verbose axis
14482	 * specifiers ("::"), just the simplied form at this point.
14483	 * Additionally, if there is no list of namespaces available and
14484	 *  there's a ":" in the expression, indicating a prefixed QName,
14485	 *  then we won't try to compile either. xmlPatterncompile() needs
14486	 *  to have a list of namespaces at compilation time in order to
14487	 *  compile prefixed name tests.
14488	 */
14489	tmp = xmlStrchr(str, ':');
14490	if ((tmp != NULL) &&
14491	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14492	    return(NULL);
14493
14494	if (ctxt != NULL) {
14495	    dict = ctxt->dict;
14496	    if (ctxt->nsNr > 0) {
14497		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14498		if (namespaces == NULL) {
14499		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14500		    return(NULL);
14501		}
14502		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14503		    ns = ctxt->namespaces[j];
14504		    namespaces[i++] = ns->href;
14505		    namespaces[i++] = ns->prefix;
14506		}
14507		namespaces[i++] = NULL;
14508		namespaces[i] = NULL;
14509	    }
14510	}
14511
14512	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14513			&namespaces[0]);
14514	if (namespaces != NULL) {
14515	    xmlFree((xmlChar **)namespaces);
14516	}
14517	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14518	    comp = xmlXPathNewCompExpr();
14519	    if (comp == NULL) {
14520		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14521		return(NULL);
14522	    }
14523	    comp->stream = stream;
14524	    comp->dict = dict;
14525	    if (comp->dict)
14526		xmlDictReference(comp->dict);
14527	    return(comp);
14528	}
14529	xmlFreePattern(stream);
14530    }
14531    return(NULL);
14532}
14533#endif /* XPATH_STREAMING */
14534
14535static int
14536xmlXPathCanRewriteDosExpression(xmlChar *expr)
14537{
14538    if (expr == NULL)
14539	return(0);
14540    do {
14541        if ((*expr == '/') && (*(++expr) == '/'))
14542	    return(1);
14543    } while (*expr++);
14544    return(0);
14545}
14546static void
14547xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14548{
14549    /*
14550    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14551    * internal representation.
14552    */
14553    if (op->ch1 != -1) {
14554	if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14555	    ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14556	    ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14557	    ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14558	{
14559	    /*
14560	    * This is a "child::foo"
14561	    */
14562	    xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14563
14564	    if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14565		(prevop->ch1 != -1) &&
14566		((xmlXPathAxisVal) prevop->value ==
14567		    AXIS_DESCENDANT_OR_SELF) &&
14568		(prevop->ch2 == -1) &&
14569		((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14570		((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14571		(comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14572	    {
14573		/*
14574		* This is a "/descendant-or-self::node()" without predicates.
14575		* Eliminate it.
14576		*/
14577		op->ch1 = prevop->ch1;
14578		op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14579	    }
14580	}
14581	if (op->ch1 != -1)
14582	    xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14583    }
14584    if (op->ch2 != -1)
14585	xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14586}
14587
14588/**
14589 * xmlXPathCtxtCompile:
14590 * @ctxt: an XPath context
14591 * @str:  the XPath expression
14592 *
14593 * Compile an XPath expression
14594 *
14595 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14596 *         the caller has to free the object.
14597 */
14598xmlXPathCompExprPtr
14599xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14600    xmlXPathParserContextPtr pctxt;
14601    xmlXPathCompExprPtr comp;
14602
14603#ifdef XPATH_STREAMING
14604    comp = xmlXPathTryStreamCompile(ctxt, str);
14605    if (comp != NULL)
14606        return(comp);
14607#endif
14608
14609    xmlXPathInit();
14610
14611    pctxt = xmlXPathNewParserContext(str, ctxt);
14612    if (pctxt == NULL)
14613        return NULL;
14614    xmlXPathCompileExpr(pctxt, 1);
14615
14616    if( pctxt->error != XPATH_EXPRESSION_OK )
14617    {
14618        xmlXPathFreeParserContext(pctxt);
14619        return(NULL);
14620    }
14621
14622    if (*pctxt->cur != 0) {
14623	/*
14624	 * aleksey: in some cases this line prints *second* error message
14625	 * (see bug #78858) and probably this should be fixed.
14626	 * However, we are not sure that all error messages are printed
14627	 * out in other places. It's not critical so we leave it as-is for now
14628	 */
14629	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14630	comp = NULL;
14631    } else {
14632	comp = pctxt->comp;
14633	pctxt->comp = NULL;
14634    }
14635    xmlXPathFreeParserContext(pctxt);
14636
14637    if (comp != NULL) {
14638	comp->expr = xmlStrdup(str);
14639#ifdef DEBUG_EVAL_COUNTS
14640	comp->string = xmlStrdup(str);
14641	comp->nb = 0;
14642#endif
14643	if ((comp->expr != NULL) &&
14644	    (comp->nbStep > 2) &&
14645	    (comp->last >= 0) &&
14646	    (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14647	{
14648	    xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14649	}
14650    }
14651    return(comp);
14652}
14653
14654/**
14655 * xmlXPathCompile:
14656 * @str:  the XPath expression
14657 *
14658 * Compile an XPath expression
14659 *
14660 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14661 *         the caller has to free the object.
14662 */
14663xmlXPathCompExprPtr
14664xmlXPathCompile(const xmlChar *str) {
14665    return(xmlXPathCtxtCompile(NULL, str));
14666}
14667
14668/**
14669 * xmlXPathCompiledEvalInternal:
14670 * @comp:  the compiled XPath expression
14671 * @ctxt:  the XPath context
14672 * @resObj: the resulting XPath object or NULL
14673 * @toBool: 1 if only a boolean result is requested
14674 *
14675 * Evaluate the Precompiled XPath expression in the given context.
14676 * The caller has to free @resObj.
14677 *
14678 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14679 *         the caller has to free the object.
14680 */
14681static int
14682xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14683			     xmlXPathContextPtr ctxt,
14684			     xmlXPathObjectPtr *resObj,
14685			     int toBool)
14686{
14687    xmlXPathParserContextPtr pctxt;
14688#ifndef LIBXML_THREAD_ENABLED
14689    static int reentance = 0;
14690#endif
14691    int res;
14692
14693    CHECK_CTXT_NEG(ctxt)
14694
14695    if (comp == NULL)
14696	return(-1);
14697    xmlXPathInit();
14698
14699#ifndef LIBXML_THREAD_ENABLED
14700    reentance++;
14701    if (reentance > 1)
14702	xmlXPathDisableOptimizer = 1;
14703#endif
14704
14705#ifdef DEBUG_EVAL_COUNTS
14706    comp->nb++;
14707    if ((comp->string != NULL) && (comp->nb > 100)) {
14708	fprintf(stderr, "100 x %s\n", comp->string);
14709	comp->nb = 0;
14710    }
14711#endif
14712    pctxt = xmlXPathCompParserContext(comp, ctxt);
14713    res = xmlXPathRunEval(pctxt, toBool);
14714
14715    if (resObj) {
14716	if (pctxt->value == NULL) {
14717	    xmlGenericError(xmlGenericErrorContext,
14718		"xmlXPathCompiledEval: evaluation failed\n");
14719	    *resObj = NULL;
14720	} else {
14721	    *resObj = valuePop(pctxt);
14722	}
14723    }
14724
14725    /*
14726    * Pop all remaining objects from the stack.
14727    */
14728    if (pctxt->valueNr > 0) {
14729	xmlXPathObjectPtr tmp;
14730	int stack = 0;
14731
14732	do {
14733	    tmp = valuePop(pctxt);
14734	    if (tmp != NULL) {
14735		stack++;
14736		xmlXPathReleaseObject(ctxt, tmp);
14737	    }
14738	} while (tmp != NULL);
14739	if ((stack != 0) &&
14740	    ((toBool) || ((resObj) && (*resObj))))
14741	{
14742	    xmlGenericError(xmlGenericErrorContext,
14743		"xmlXPathCompiledEval: %d objects left on the stack.\n",
14744		stack);
14745	}
14746    }
14747
14748    if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14749	xmlXPathFreeObject(*resObj);
14750	*resObj = NULL;
14751    }
14752    pctxt->comp = NULL;
14753    xmlXPathFreeParserContext(pctxt);
14754#ifndef LIBXML_THREAD_ENABLED
14755    reentance--;
14756#endif
14757
14758    return(res);
14759}
14760
14761/**
14762 * xmlXPathCompiledEval:
14763 * @comp:  the compiled XPath expression
14764 * @ctx:  the XPath context
14765 *
14766 * Evaluate the Precompiled XPath expression in the given context.
14767 *
14768 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14769 *         the caller has to free the object.
14770 */
14771xmlXPathObjectPtr
14772xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14773{
14774    xmlXPathObjectPtr res = NULL;
14775
14776    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14777    return(res);
14778}
14779
14780/**
14781 * xmlXPathCompiledEvalToBoolean:
14782 * @comp:  the compiled XPath expression
14783 * @ctxt:  the XPath context
14784 *
14785 * Applies the XPath boolean() function on the result of the given
14786 * compiled expression.
14787 *
14788 * Returns 1 if the expression evaluated to true, 0 if to false and
14789 *         -1 in API and internal errors.
14790 */
14791int
14792xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14793			      xmlXPathContextPtr ctxt)
14794{
14795    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14796}
14797
14798/**
14799 * xmlXPathEvalExpr:
14800 * @ctxt:  the XPath Parser context
14801 *
14802 * Parse and evaluate an XPath expression in the given context,
14803 * then push the result on the context stack
14804 */
14805void
14806xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14807#ifdef XPATH_STREAMING
14808    xmlXPathCompExprPtr comp;
14809#endif
14810
14811    if (ctxt == NULL) return;
14812
14813#ifdef XPATH_STREAMING
14814    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14815    if (comp != NULL) {
14816        if (ctxt->comp != NULL)
14817	    xmlXPathFreeCompExpr(ctxt->comp);
14818        ctxt->comp = comp;
14819	if (ctxt->cur != NULL)
14820	    while (*ctxt->cur != 0) ctxt->cur++;
14821    } else
14822#endif
14823    {
14824	xmlXPathCompileExpr(ctxt, 1);
14825	/*
14826	* In this scenario the expression string will sit in ctxt->base.
14827	*/
14828	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14829	    (ctxt->comp != NULL) &&
14830	    (ctxt->base != NULL) &&
14831	    (ctxt->comp->nbStep > 2) &&
14832	    (ctxt->comp->last >= 0) &&
14833	    (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14834	{
14835	    xmlXPathRewriteDOSExpression(ctxt->comp,
14836		&ctxt->comp->steps[ctxt->comp->last]);
14837	}
14838    }
14839    CHECK_ERROR;
14840    xmlXPathRunEval(ctxt, 0);
14841}
14842
14843/**
14844 * xmlXPathEval:
14845 * @str:  the XPath expression
14846 * @ctx:  the XPath context
14847 *
14848 * Evaluate the XPath Location Path in the given context.
14849 *
14850 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14851 *         the caller has to free the object.
14852 */
14853xmlXPathObjectPtr
14854xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14855    xmlXPathParserContextPtr ctxt;
14856    xmlXPathObjectPtr res, tmp, init = NULL;
14857    int stack = 0;
14858
14859    CHECK_CTXT(ctx)
14860
14861    xmlXPathInit();
14862
14863    ctxt = xmlXPathNewParserContext(str, ctx);
14864    if (ctxt == NULL)
14865        return NULL;
14866    xmlXPathEvalExpr(ctxt);
14867
14868    if (ctxt->value == NULL) {
14869	xmlGenericError(xmlGenericErrorContext,
14870		"xmlXPathEval: evaluation failed\n");
14871	res = NULL;
14872    } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14873#ifdef XPATH_STREAMING
14874            && (ctxt->comp->stream == NULL)
14875#endif
14876	      ) {
14877	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14878	res = NULL;
14879    } else {
14880	res = valuePop(ctxt);
14881    }
14882
14883    do {
14884        tmp = valuePop(ctxt);
14885	if (tmp != NULL) {
14886	    if (tmp != init)
14887		stack++;
14888	    xmlXPathReleaseObject(ctx, tmp);
14889        }
14890    } while (tmp != NULL);
14891    if ((stack != 0) && (res != NULL)) {
14892	xmlGenericError(xmlGenericErrorContext,
14893		"xmlXPathEval: %d object left on the stack\n",
14894	        stack);
14895    }
14896    if (ctxt->error != XPATH_EXPRESSION_OK) {
14897	xmlXPathFreeObject(res);
14898	res = NULL;
14899    }
14900
14901    xmlXPathFreeParserContext(ctxt);
14902    return(res);
14903}
14904
14905/**
14906 * xmlXPathEvalExpression:
14907 * @str:  the XPath expression
14908 * @ctxt:  the XPath context
14909 *
14910 * Evaluate the XPath expression in the given context.
14911 *
14912 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14913 *         the caller has to free the object.
14914 */
14915xmlXPathObjectPtr
14916xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14917    xmlXPathParserContextPtr pctxt;
14918    xmlXPathObjectPtr res, tmp;
14919    int stack = 0;
14920
14921    CHECK_CTXT(ctxt)
14922
14923    xmlXPathInit();
14924
14925    pctxt = xmlXPathNewParserContext(str, ctxt);
14926    if (pctxt == NULL)
14927        return NULL;
14928    xmlXPathEvalExpr(pctxt);
14929
14930    if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
14931	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14932	res = NULL;
14933    } else {
14934	res = valuePop(pctxt);
14935    }
14936    do {
14937        tmp = valuePop(pctxt);
14938	if (tmp != NULL) {
14939	    xmlXPathReleaseObject(ctxt, tmp);
14940	    stack++;
14941	}
14942    } while (tmp != NULL);
14943    if ((stack != 0) && (res != NULL)) {
14944	xmlGenericError(xmlGenericErrorContext,
14945		"xmlXPathEvalExpression: %d object left on the stack\n",
14946	        stack);
14947    }
14948    xmlXPathFreeParserContext(pctxt);
14949    return(res);
14950}
14951
14952/************************************************************************
14953 *									*
14954 *	Extra functions not pertaining to the XPath spec		*
14955 *									*
14956 ************************************************************************/
14957/**
14958 * xmlXPathEscapeUriFunction:
14959 * @ctxt:  the XPath Parser context
14960 * @nargs:  the number of arguments
14961 *
14962 * Implement the escape-uri() XPath function
14963 *    string escape-uri(string $str, bool $escape-reserved)
14964 *
14965 * This function applies the URI escaping rules defined in section 2 of [RFC
14966 * 2396] to the string supplied as $uri-part, which typically represents all
14967 * or part of a URI. The effect of the function is to replace any special
14968 * character in the string by an escape sequence of the form %xx%yy...,
14969 * where xxyy... is the hexadecimal representation of the octets used to
14970 * represent the character in UTF-8.
14971 *
14972 * The set of characters that are escaped depends on the setting of the
14973 * boolean argument $escape-reserved.
14974 *
14975 * If $escape-reserved is true, all characters are escaped other than lower
14976 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14977 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14978 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14979 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14980 * A-F).
14981 *
14982 * If $escape-reserved is false, the behavior differs in that characters
14983 * referred to in [RFC 2396] as reserved characters are not escaped. These
14984 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14985 *
14986 * [RFC 2396] does not define whether escaped URIs should use lower case or
14987 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14988 * compared using string comparison functions, this function must always use
14989 * the upper-case letters A-F.
14990 *
14991 * Generally, $escape-reserved should be set to true when escaping a string
14992 * that is to form a single part of a URI, and to false when escaping an
14993 * entire URI or URI reference.
14994 *
14995 * In the case of non-ascii characters, the string is encoded according to
14996 * utf-8 and then converted according to RFC 2396.
14997 *
14998 * Examples
14999 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15000 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15001 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15002 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15003 *
15004 */
15005static void
15006xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15007    xmlXPathObjectPtr str;
15008    int escape_reserved;
15009    xmlBufferPtr target;
15010    xmlChar *cptr;
15011    xmlChar escape[4];
15012
15013    CHECK_ARITY(2);
15014
15015    escape_reserved = xmlXPathPopBoolean(ctxt);
15016
15017    CAST_TO_STRING;
15018    str = valuePop(ctxt);
15019
15020    target = xmlBufferCreate();
15021
15022    escape[0] = '%';
15023    escape[3] = 0;
15024
15025    if (target) {
15026	for (cptr = str->stringval; *cptr; cptr++) {
15027	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15028		(*cptr >= 'a' && *cptr <= 'z') ||
15029		(*cptr >= '0' && *cptr <= '9') ||
15030		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15031		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15032		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15033		(*cptr == '%' &&
15034		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15035		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15036		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15037		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15038		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15039		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15040		(!escape_reserved &&
15041		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15042		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15043		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15044		  *cptr == ','))) {
15045		xmlBufferAdd(target, cptr, 1);
15046	    } else {
15047		if ((*cptr >> 4) < 10)
15048		    escape[1] = '0' + (*cptr >> 4);
15049		else
15050		    escape[1] = 'A' - 10 + (*cptr >> 4);
15051		if ((*cptr & 0xF) < 10)
15052		    escape[2] = '0' + (*cptr & 0xF);
15053		else
15054		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15055
15056		xmlBufferAdd(target, &escape[0], 3);
15057	    }
15058	}
15059    }
15060    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15061	xmlBufferContent(target)));
15062    xmlBufferFree(target);
15063    xmlXPathReleaseObject(ctxt->context, str);
15064}
15065
15066/**
15067 * xmlXPathRegisterAllFunctions:
15068 * @ctxt:  the XPath context
15069 *
15070 * Registers all default XPath functions in this context
15071 */
15072void
15073xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15074{
15075    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15076                         xmlXPathBooleanFunction);
15077    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15078                         xmlXPathCeilingFunction);
15079    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15080                         xmlXPathCountFunction);
15081    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15082                         xmlXPathConcatFunction);
15083    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15084                         xmlXPathContainsFunction);
15085    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15086                         xmlXPathIdFunction);
15087    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15088                         xmlXPathFalseFunction);
15089    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15090                         xmlXPathFloorFunction);
15091    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15092                         xmlXPathLastFunction);
15093    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15094                         xmlXPathLangFunction);
15095    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15096                         xmlXPathLocalNameFunction);
15097    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15098                         xmlXPathNotFunction);
15099    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15100                         xmlXPathNameFunction);
15101    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15102                         xmlXPathNamespaceURIFunction);
15103    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15104                         xmlXPathNormalizeFunction);
15105    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15106                         xmlXPathNumberFunction);
15107    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15108                         xmlXPathPositionFunction);
15109    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15110                         xmlXPathRoundFunction);
15111    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15112                         xmlXPathStringFunction);
15113    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15114                         xmlXPathStringLengthFunction);
15115    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15116                         xmlXPathStartsWithFunction);
15117    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15118                         xmlXPathSubstringFunction);
15119    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15120                         xmlXPathSubstringBeforeFunction);
15121    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15122                         xmlXPathSubstringAfterFunction);
15123    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15124                         xmlXPathSumFunction);
15125    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15126                         xmlXPathTrueFunction);
15127    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15128                         xmlXPathTranslateFunction);
15129
15130    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15131	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15132                         xmlXPathEscapeUriFunction);
15133}
15134
15135#endif /* LIBXML_XPATH_ENABLED */
15136#define bottom_xpath
15137#include "elfgcchack.h"
15138