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_PATTERN_TO_ANY_NODE_ENABLED: when an XPath expression can be
69*   evaluated using the streaming mode (pattern.c) then this is used to
70*   enable resolution to nodes of type text-node, cdata-section-node,
71*   comment-node and pi-node. The only known scenario where this is
72*   needed is an expression like "foo//.", "//.", etc.; i.e. an expression
73*   where the final node to be selected can be of any type.
74*   Disabling this #define will result in an incorrect evaluation to
75*   only element-nodes and the document node.
76*/
77#define XP_PATTERN_TO_ANY_NODE_ENABLED
78
79/*
80* XP_OPTIMIZED_NON_ELEM_COMPARISON:
81* If defined, this will use xmlXPathCmpNodesExt() instead of
82* xmlXPathCmpNodes(). The new function is optimized comparison of
83* non-element nodes; actually it will speed up comparison only if
84* xmlXPathOrderDocElems() was called in order to index the elements of
85* a tree in document order; Libxslt does such an indexing, thus it will
86* benefit from this optimization.
87*/
88#define XP_OPTIMIZED_NON_ELEM_COMPARISON
89
90/*
91* XP_OPTIMIZED_FILTER_FIRST:
92* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
93* in a way, that it stop evaluation at the first node.
94*/
95#define XP_OPTIMIZED_FILTER_FIRST
96
97/*
98* XP_DEBUG_OBJ_USAGE:
99* Internal flag to enable tracking of how much XPath objects have been
100* created.
101*/
102/* #define XP_DEBUG_OBJ_USAGE */
103
104/*
105 * TODO:
106 * There are a few spots where some tests are done which depend upon ascii
107 * data.  These should be enhanced for full UTF8 support (see particularly
108 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
109 */
110
111#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
112/************************************************************************
113 * 									*
114 * 			Forward declarations				*
115 * 									*
116 ************************************************************************/
117static void
118xmlXPathFreeValueTree(xmlNodeSetPtr obj);
119static void
120xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
121
122/************************************************************************
123 * 									*
124 * 			Floating point stuff				*
125 * 									*
126 ************************************************************************/
127
128#ifndef TRIO_REPLACE_STDIO
129#define TRIO_PUBLIC static
130#endif
131#include "trionan.c"
132
133/*
134 * The lack of portability of this section of the libc is annoying !
135 */
136double xmlXPathNAN = 0;
137double xmlXPathPINF = 1;
138double xmlXPathNINF = -1;
139static double xmlXPathNZERO = 0; /* not exported from headers */
140static int xmlXPathInitialized = 0;
141
142/**
143 * xmlXPathInit:
144 *
145 * Initialize the XPath environment
146 */
147void
148xmlXPathInit(void) {
149    if (xmlXPathInitialized) return;
150
151    xmlXPathPINF = trio_pinf();
152    xmlXPathNINF = trio_ninf();
153    xmlXPathNAN = trio_nan();
154    xmlXPathNZERO = trio_nzero();
155
156    xmlXPathInitialized = 1;
157}
158
159/**
160 * xmlXPathIsNaN:
161 * @val:  a double value
162 *
163 * Provides a portable isnan() function to detect whether a double
164 * is a NotaNumber. Based on trio code
165 * http://sourceforge.net/projects/ctrio/
166 *
167 * Returns 1 if the value is a NaN, 0 otherwise
168 */
169int
170xmlXPathIsNaN(double val) {
171    return(trio_isnan(val));
172}
173
174/**
175 * xmlXPathIsInf:
176 * @val:  a double value
177 *
178 * Provides a portable isinf() function to detect whether a double
179 * is a +Infinite or -Infinite. Based on trio code
180 * http://sourceforge.net/projects/ctrio/
181 *
182 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
183 */
184int
185xmlXPathIsInf(double val) {
186    return(trio_isinf(val));
187}
188
189#endif /* SCHEMAS or XPATH */
190#ifdef LIBXML_XPATH_ENABLED
191/**
192 * xmlXPathGetSign:
193 * @val:  a double value
194 *
195 * Provides a portable function to detect the sign of a double
196 * Modified from trio code
197 * http://sourceforge.net/projects/ctrio/
198 *
199 * Returns 1 if the value is Negative, 0 if positive
200 */
201static int
202xmlXPathGetSign(double val) {
203    return(trio_signbit(val));
204}
205
206
207/*
208 * TODO: when compatibility allows remove all "fake node libxslt" strings
209 *       the test should just be name[0] = ' '
210 */
211/* #define DEBUG */
212/* #define DEBUG_STEP */
213/* #define DEBUG_STEP_NTH */
214/* #define DEBUG_EXPR */
215/* #define DEBUG_EVAL_COUNTS */
216
217static xmlNs xmlXPathXMLNamespaceStruct = {
218    NULL,
219    XML_NAMESPACE_DECL,
220    XML_XML_NAMESPACE,
221    BAD_CAST "xml",
222    NULL
223};
224static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
225#ifndef LIBXML_THREAD_ENABLED
226/*
227 * Optimizer is disabled only when threaded apps are detected while
228 * the library ain't compiled for thread safety.
229 */
230static int xmlXPathDisableOptimizer = 0;
231#endif
232
233/************************************************************************
234 *									*
235 *			Error handling routines				*
236 *									*
237 ************************************************************************/
238
239/**
240 * XP_ERRORNULL:
241 * @X:  the error code
242 *
243 * Macro to raise an XPath error and return NULL.
244 */
245#define XP_ERRORNULL(X)							\
246    { xmlXPathErr(ctxt, X); return(NULL); }
247
248/*
249 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
250 */
251static const char *xmlXPathErrorMessages[] = {
252    "Ok\n",
253    "Number encoding\n",
254    "Unfinished literal\n",
255    "Start of literal\n",
256    "Expected $ for variable reference\n",
257    "Undefined variable\n",
258    "Invalid predicate\n",
259    "Invalid expression\n",
260    "Missing closing curly brace\n",
261    "Unregistered function\n",
262    "Invalid operand\n",
263    "Invalid type\n",
264    "Invalid number of arguments\n",
265    "Invalid context size\n",
266    "Invalid context position\n",
267    "Memory allocation error\n",
268    "Syntax error\n",
269    "Resource error\n",
270    "Sub resource error\n",
271    "Undefined namespace prefix\n",
272    "Encoding error\n",
273    "Char out of XML range\n",
274    "Invalid or incomplete context\n",
275    "?? Unknown error ??\n"	/* Must be last in the list! */
276};
277#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
278		   sizeof(xmlXPathErrorMessages[0])) - 1)
279/**
280 * xmlXPathErrMemory:
281 * @ctxt:  an XPath context
282 * @extra:  extra informations
283 *
284 * Handle a redefinition of attribute error
285 */
286static void
287xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
288{
289    if (ctxt != NULL) {
290        if (extra) {
291            xmlChar buf[200];
292
293            xmlStrPrintf(buf, 200,
294                         BAD_CAST "Memory allocation failed : %s\n",
295                         extra);
296            ctxt->lastError.message = (char *) xmlStrdup(buf);
297        } else {
298            ctxt->lastError.message = (char *)
299	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
300        }
301        ctxt->lastError.domain = XML_FROM_XPATH;
302        ctxt->lastError.code = XML_ERR_NO_MEMORY;
303	if (ctxt->error != NULL)
304	    ctxt->error(ctxt->userData, &ctxt->lastError);
305    } else {
306        if (extra)
307            __xmlRaiseError(NULL, NULL, NULL,
308                            NULL, NULL, XML_FROM_XPATH,
309                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
310                            extra, NULL, NULL, 0, 0,
311                            "Memory allocation failed : %s\n", extra);
312        else
313            __xmlRaiseError(NULL, NULL, NULL,
314                            NULL, NULL, XML_FROM_XPATH,
315                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
316                            NULL, NULL, NULL, 0, 0,
317                            "Memory allocation failed\n");
318    }
319}
320
321/**
322 * xmlXPathPErrMemory:
323 * @ctxt:  an XPath parser context
324 * @extra:  extra informations
325 *
326 * Handle a redefinition of attribute error
327 */
328static void
329xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
330{
331    if (ctxt == NULL)
332	xmlXPathErrMemory(NULL, extra);
333    else {
334	ctxt->error = XPATH_MEMORY_ERROR;
335	xmlXPathErrMemory(ctxt->context, extra);
336    }
337}
338
339/**
340 * xmlXPathErr:
341 * @ctxt:  a XPath parser context
342 * @error:  the error code
343 *
344 * Handle an XPath error
345 */
346void
347xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
348{
349    if ((error < 0) || (error > MAXERRNO))
350	error = MAXERRNO;
351    if (ctxt == NULL) {
352	__xmlRaiseError(NULL, NULL, NULL,
353			NULL, NULL, XML_FROM_XPATH,
354			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
355			XML_ERR_ERROR, NULL, 0,
356			NULL, NULL, NULL, 0, 0,
357			xmlXPathErrorMessages[error]);
358	return;
359    }
360    ctxt->error = error;
361    if (ctxt->context == NULL) {
362	__xmlRaiseError(NULL, NULL, NULL,
363			NULL, NULL, XML_FROM_XPATH,
364			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
365			XML_ERR_ERROR, NULL, 0,
366			(const char *) ctxt->base, NULL, NULL,
367			ctxt->cur - ctxt->base, 0,
368			xmlXPathErrorMessages[error]);
369	return;
370    }
371
372    /* cleanup current last error */
373    xmlResetError(&ctxt->context->lastError);
374
375    ctxt->context->lastError.domain = XML_FROM_XPATH;
376    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
377                           XPATH_EXPRESSION_OK;
378    ctxt->context->lastError.level = XML_ERR_ERROR;
379    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
380    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
381    ctxt->context->lastError.node = ctxt->context->debugNode;
382    if (ctxt->context->error != NULL) {
383	ctxt->context->error(ctxt->context->userData,
384	                     &ctxt->context->lastError);
385    } else {
386	__xmlRaiseError(NULL, NULL, NULL,
387			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
388			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
389			XML_ERR_ERROR, NULL, 0,
390			(const char *) ctxt->base, NULL, NULL,
391			ctxt->cur - ctxt->base, 0,
392			xmlXPathErrorMessages[error]);
393    }
394
395}
396
397/**
398 * xmlXPatherror:
399 * @ctxt:  the XPath Parser context
400 * @file:  the file name
401 * @line:  the line number
402 * @no:  the error number
403 *
404 * Formats an error message.
405 */
406void
407xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
408              int line ATTRIBUTE_UNUSED, int no) {
409    xmlXPathErr(ctxt, no);
410}
411
412/************************************************************************
413 * 									*
414 * 			Utilities	    				*
415 * 									*
416 ************************************************************************/
417
418/**
419 * xsltPointerList:
420 *
421 * Pointer-list for various purposes.
422 */
423typedef struct _xmlPointerList xmlPointerList;
424typedef xmlPointerList *xmlPointerListPtr;
425struct _xmlPointerList {
426    void **items;
427    int number;
428    int size;
429};
430/*
431* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
432* and here, we should make the functions public.
433*/
434static int
435xmlPointerListAddSize(xmlPointerListPtr list,
436		       void *item,
437		       int initialSize)
438{
439    if (list->items == NULL) {
440	if (initialSize <= 0)
441	    initialSize = 1;
442	list->items = (void **) xmlMalloc(
443	    initialSize * sizeof(void *));
444	if (list->items == NULL) {
445	    xmlXPathErrMemory(NULL,
446		"xmlPointerListCreate: allocating item\n");
447	    return(-1);
448	}
449	list->number = 0;
450	list->size = initialSize;
451    } else if (list->size <= list->number) {
452	list->size *= 2;
453	list->items = (void **) xmlRealloc(list->items,
454	    list->size * sizeof(void *));
455	if (list->items == NULL) {
456	    xmlXPathErrMemory(NULL,
457		"xmlPointerListCreate: re-allocating item\n");
458	    list->size = 0;
459	    return(-1);
460	}
461    }
462    list->items[list->number++] = item;
463    return(0);
464}
465
466/**
467 * xsltPointerListCreate:
468 *
469 * Creates an xsltPointerList structure.
470 *
471 * Returns a xsltPointerList structure or NULL in case of an error.
472 */
473static xmlPointerListPtr
474xmlPointerListCreate(int initialSize)
475{
476    xmlPointerListPtr ret;
477
478    ret = xmlMalloc(sizeof(xmlPointerList));
479    if (ret == NULL) {
480	xmlXPathErrMemory(NULL,
481	    "xmlPointerListCreate: allocating item\n");
482	return (NULL);
483    }
484    memset(ret, 0, sizeof(xmlPointerList));
485    if (initialSize > 0) {
486	xmlPointerListAddSize(ret, NULL, initialSize);
487	ret->number = 0;
488    }
489    return (ret);
490}
491
492/**
493 * xsltPointerListFree:
494 *
495 * Frees the xsltPointerList structure. This does not free
496 * the content of the list.
497 */
498static void
499xmlPointerListFree(xmlPointerListPtr list)
500{
501    if (list == NULL)
502	return;
503    if (list->items != NULL)
504	xmlFree(list->items);
505    xmlFree(list);
506}
507
508/************************************************************************
509 * 									*
510 * 			Parser Types					*
511 * 									*
512 ************************************************************************/
513
514/*
515 * Types are private:
516 */
517
518typedef enum {
519    XPATH_OP_END=0,
520    XPATH_OP_AND,
521    XPATH_OP_OR,
522    XPATH_OP_EQUAL,
523    XPATH_OP_CMP,
524    XPATH_OP_PLUS,
525    XPATH_OP_MULT,
526    XPATH_OP_UNION,
527    XPATH_OP_ROOT,
528    XPATH_OP_NODE,
529    XPATH_OP_RESET, /* 10 */
530    XPATH_OP_COLLECT,
531    XPATH_OP_VALUE, /* 12 */
532    XPATH_OP_VARIABLE,
533    XPATH_OP_FUNCTION,
534    XPATH_OP_ARG,
535    XPATH_OP_PREDICATE,
536    XPATH_OP_FILTER, /* 17 */
537    XPATH_OP_SORT /* 18 */
538#ifdef LIBXML_XPTR_ENABLED
539    ,XPATH_OP_RANGETO
540#endif
541} xmlXPathOp;
542
543typedef enum {
544    AXIS_ANCESTOR = 1,
545    AXIS_ANCESTOR_OR_SELF,
546    AXIS_ATTRIBUTE,
547    AXIS_CHILD,
548    AXIS_DESCENDANT,
549    AXIS_DESCENDANT_OR_SELF,
550    AXIS_FOLLOWING,
551    AXIS_FOLLOWING_SIBLING,
552    AXIS_NAMESPACE,
553    AXIS_PARENT,
554    AXIS_PRECEDING,
555    AXIS_PRECEDING_SIBLING,
556    AXIS_SELF
557} xmlXPathAxisVal;
558
559typedef enum {
560    NODE_TEST_NONE = 0,
561    NODE_TEST_TYPE = 1,
562    NODE_TEST_PI = 2,
563    NODE_TEST_ALL = 3,
564    NODE_TEST_NS = 4,
565    NODE_TEST_NAME = 5
566} xmlXPathTestVal;
567
568typedef enum {
569    NODE_TYPE_NODE = 0,
570    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
571    NODE_TYPE_TEXT = XML_TEXT_NODE,
572    NODE_TYPE_PI = XML_PI_NODE
573} xmlXPathTypeVal;
574
575#define XP_REWRITE_DOS_CHILD_ELEM 1
576
577typedef struct _xmlXPathStepOp xmlXPathStepOp;
578typedef xmlXPathStepOp *xmlXPathStepOpPtr;
579struct _xmlXPathStepOp {
580    xmlXPathOp op;		/* The identifier of the operation */
581    int ch1;			/* First child */
582    int ch2;			/* Second child */
583    int value;
584    int value2;
585    int value3;
586    void *value4;
587    void *value5;
588    void *cache;
589    void *cacheURI;
590    int rewriteType;
591};
592
593struct _xmlXPathCompExpr {
594    int nbStep;			/* Number of steps in this expression */
595    int maxStep;		/* Maximum number of steps allocated */
596    xmlXPathStepOp *steps;	/* ops for computation of this expression */
597    int last;			/* index of last step in expression */
598    xmlChar *expr;		/* the expression being computed */
599    xmlDictPtr dict;		/* the dictionnary to use if any */
600#ifdef DEBUG_EVAL_COUNTS
601    int nb;
602    xmlChar *string;
603#endif
604#ifdef XPATH_STREAMING
605    xmlPatternPtr stream;
606#endif
607};
608
609/************************************************************************
610 * 									*
611 * 			Parser Type functions 				*
612 * 									*
613 ************************************************************************/
614
615/**
616 * xmlXPathNewCompExpr:
617 *
618 * Create a new Xpath component
619 *
620 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
621 */
622static xmlXPathCompExprPtr
623xmlXPathNewCompExpr(void) {
624    xmlXPathCompExprPtr cur;
625
626    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
627    if (cur == NULL) {
628        xmlXPathErrMemory(NULL, "allocating component\n");
629	return(NULL);
630    }
631    memset(cur, 0, sizeof(xmlXPathCompExpr));
632    cur->maxStep = 10;
633    cur->nbStep = 0;
634    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
635	                                   sizeof(xmlXPathStepOp));
636    if (cur->steps == NULL) {
637        xmlXPathErrMemory(NULL, "allocating steps\n");
638	xmlFree(cur);
639	return(NULL);
640    }
641    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
642    cur->last = -1;
643#ifdef DEBUG_EVAL_COUNTS
644    cur->nb = 0;
645#endif
646    return(cur);
647}
648
649/**
650 * xmlXPathFreeCompExpr:
651 * @comp:  an XPATH comp
652 *
653 * Free up the memory allocated by @comp
654 */
655void
656xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
657{
658    xmlXPathStepOpPtr op;
659    int i;
660
661    if (comp == NULL)
662        return;
663    if (comp->dict == NULL) {
664	for (i = 0; i < comp->nbStep; i++) {
665	    op = &comp->steps[i];
666	    if (op->value4 != NULL) {
667		if (op->op == XPATH_OP_VALUE)
668		    xmlXPathFreeObject(op->value4);
669		else
670		    xmlFree(op->value4);
671	    }
672	    if (op->value5 != NULL)
673		xmlFree(op->value5);
674	}
675    } else {
676	for (i = 0; i < comp->nbStep; i++) {
677	    op = &comp->steps[i];
678	    if (op->value4 != NULL) {
679		if (op->op == XPATH_OP_VALUE)
680		    xmlXPathFreeObject(op->value4);
681	    }
682	}
683        xmlDictFree(comp->dict);
684    }
685    if (comp->steps != NULL) {
686        xmlFree(comp->steps);
687    }
688#ifdef DEBUG_EVAL_COUNTS
689    if (comp->string != NULL) {
690        xmlFree(comp->string);
691    }
692#endif
693#ifdef XPATH_STREAMING
694    if (comp->stream != NULL) {
695        xmlFreePatternList(comp->stream);
696    }
697#endif
698    if (comp->expr != NULL) {
699        xmlFree(comp->expr);
700    }
701
702    xmlFree(comp);
703}
704
705/**
706 * xmlXPathCompExprAdd:
707 * @comp:  the compiled expression
708 * @ch1: first child index
709 * @ch2: second child index
710 * @op:  an op
711 * @value:  the first int value
712 * @value2:  the second int value
713 * @value3:  the third int value
714 * @value4:  the first string value
715 * @value5:  the second string value
716 *
717 * Add a step to an XPath Compiled Expression
718 *
719 * Returns -1 in case of failure, the index otherwise
720 */
721static int
722xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
723   xmlXPathOp op, int value,
724   int value2, int value3, void *value4, void *value5) {
725    if (comp->nbStep >= comp->maxStep) {
726	xmlXPathStepOp *real;
727
728	comp->maxStep *= 2;
729	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
730		                      comp->maxStep * sizeof(xmlXPathStepOp));
731	if (real == NULL) {
732	    comp->maxStep /= 2;
733	    xmlXPathErrMemory(NULL, "adding step\n");
734	    return(-1);
735	}
736	comp->steps = real;
737    }
738    comp->last = comp->nbStep;
739    comp->steps[comp->nbStep].ch1 = ch1;
740    comp->steps[comp->nbStep].ch2 = ch2;
741    comp->steps[comp->nbStep].op = op;
742    comp->steps[comp->nbStep].value = value;
743    comp->steps[comp->nbStep].value2 = value2;
744    comp->steps[comp->nbStep].value3 = value3;
745    if ((comp->dict != NULL) &&
746        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
747	 (op == XPATH_OP_COLLECT))) {
748        if (value4 != NULL) {
749	    comp->steps[comp->nbStep].value4 = (xmlChar *)
750	        (void *)xmlDictLookup(comp->dict, value4, -1);
751	    xmlFree(value4);
752	} else
753	    comp->steps[comp->nbStep].value4 = NULL;
754        if (value5 != NULL) {
755	    comp->steps[comp->nbStep].value5 = (xmlChar *)
756	        (void *)xmlDictLookup(comp->dict, value5, -1);
757	    xmlFree(value5);
758	} else
759	    comp->steps[comp->nbStep].value5 = NULL;
760    } else {
761	comp->steps[comp->nbStep].value4 = value4;
762	comp->steps[comp->nbStep].value5 = value5;
763    }
764    comp->steps[comp->nbStep].cache = NULL;
765    return(comp->nbStep++);
766}
767
768/**
769 * xmlXPathCompSwap:
770 * @comp:  the compiled expression
771 * @op: operation index
772 *
773 * Swaps 2 operations in the compiled expression
774 */
775static void
776xmlXPathCompSwap(xmlXPathStepOpPtr op) {
777    int tmp;
778
779#ifndef LIBXML_THREAD_ENABLED
780    /*
781     * Since this manipulates possibly shared variables, this is
782     * disabled if one detects that the library is used in a multithreaded
783     * application
784     */
785    if (xmlXPathDisableOptimizer)
786	return;
787#endif
788
789    tmp = op->ch1;
790    op->ch1 = op->ch2;
791    op->ch2 = tmp;
792}
793
794#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
795    xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
796	                (op), (val), (val2), (val3), (val4), (val5))
797#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
798    xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
799	                (op), (val), (val2), (val3), (val4), (val5))
800
801#define PUSH_LEAVE_EXPR(op, val, val2) 					\
802xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
803
804#define PUSH_UNARY_EXPR(op, ch, val, val2) 				\
805xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
806
807#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) 			\
808xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
809			(val), (val2), 0 ,NULL ,NULL)
810
811/************************************************************************
812 *									*
813 * 		XPath object cache structures				*
814 *									*
815 ************************************************************************/
816
817/* #define XP_DEFAULT_CACHE_ON */
818
819#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
820
821typedef struct _xmlXPathContextCache xmlXPathContextCache;
822typedef xmlXPathContextCache *xmlXPathContextCachePtr;
823struct _xmlXPathContextCache {
824    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
825    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
826    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
827    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
828    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
829    int maxNodeset;
830    int maxString;
831    int maxBoolean;
832    int maxNumber;
833    int maxMisc;
834#ifdef XP_DEBUG_OBJ_USAGE
835    int dbgCachedAll;
836    int dbgCachedNodeset;
837    int dbgCachedString;
838    int dbgCachedBool;
839    int dbgCachedNumber;
840    int dbgCachedPoint;
841    int dbgCachedRange;
842    int dbgCachedLocset;
843    int dbgCachedUsers;
844    int dbgCachedXSLTTree;
845    int dbgCachedUndefined;
846
847
848    int dbgReusedAll;
849    int dbgReusedNodeset;
850    int dbgReusedString;
851    int dbgReusedBool;
852    int dbgReusedNumber;
853    int dbgReusedPoint;
854    int dbgReusedRange;
855    int dbgReusedLocset;
856    int dbgReusedUsers;
857    int dbgReusedXSLTTree;
858    int dbgReusedUndefined;
859
860#endif
861};
862
863/************************************************************************
864 *									*
865 * 		Debugging related functions				*
866 *									*
867 ************************************************************************/
868
869#define STRANGE 							\
870    xmlGenericError(xmlGenericErrorContext,				\
871	    "Internal error at %s:%d\n",				\
872            __FILE__, __LINE__);
873
874#ifdef LIBXML_DEBUG_ENABLED
875static void
876xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
877    int i;
878    char shift[100];
879
880    for (i = 0;((i < depth) && (i < 25));i++)
881        shift[2 * i] = shift[2 * i + 1] = ' ';
882    shift[2 * i] = shift[2 * i + 1] = 0;
883    if (cur == NULL) {
884	fprintf(output, shift);
885	fprintf(output, "Node is NULL !\n");
886	return;
887
888    }
889
890    if ((cur->type == XML_DOCUMENT_NODE) ||
891	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
892	fprintf(output, shift);
893	fprintf(output, " /\n");
894    } else if (cur->type == XML_ATTRIBUTE_NODE)
895	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
896    else
897	xmlDebugDumpOneNode(output, cur, depth);
898}
899static void
900xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
901    xmlNodePtr tmp;
902    int i;
903    char shift[100];
904
905    for (i = 0;((i < depth) && (i < 25));i++)
906        shift[2 * i] = shift[2 * i + 1] = ' ';
907    shift[2 * i] = shift[2 * i + 1] = 0;
908    if (cur == NULL) {
909	fprintf(output, shift);
910	fprintf(output, "Node is NULL !\n");
911	return;
912
913    }
914
915    while (cur != NULL) {
916	tmp = cur;
917	cur = cur->next;
918	xmlDebugDumpOneNode(output, tmp, depth);
919    }
920}
921
922static void
923xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
924    int i;
925    char shift[100];
926
927    for (i = 0;((i < depth) && (i < 25));i++)
928        shift[2 * i] = shift[2 * i + 1] = ' ';
929    shift[2 * i] = shift[2 * i + 1] = 0;
930
931    if (cur == NULL) {
932	fprintf(output, shift);
933	fprintf(output, "NodeSet is NULL !\n");
934	return;
935
936    }
937
938    if (cur != NULL) {
939	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
940	for (i = 0;i < cur->nodeNr;i++) {
941	    fprintf(output, shift);
942	    fprintf(output, "%d", i + 1);
943	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
944	}
945    }
946}
947
948static void
949xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
950    int i;
951    char shift[100];
952
953    for (i = 0;((i < depth) && (i < 25));i++)
954        shift[2 * i] = shift[2 * i + 1] = ' ';
955    shift[2 * i] = shift[2 * i + 1] = 0;
956
957    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
958	fprintf(output, shift);
959	fprintf(output, "Value Tree is NULL !\n");
960	return;
961
962    }
963
964    fprintf(output, shift);
965    fprintf(output, "%d", i + 1);
966    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
967}
968#if defined(LIBXML_XPTR_ENABLED)
969static void
970xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
971    int i;
972    char shift[100];
973
974    for (i = 0;((i < depth) && (i < 25));i++)
975        shift[2 * i] = shift[2 * i + 1] = ' ';
976    shift[2 * i] = shift[2 * i + 1] = 0;
977
978    if (cur == NULL) {
979	fprintf(output, shift);
980	fprintf(output, "LocationSet is NULL !\n");
981	return;
982
983    }
984
985    for (i = 0;i < cur->locNr;i++) {
986	fprintf(output, shift);
987        fprintf(output, "%d : ", i + 1);
988	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
989    }
990}
991#endif /* LIBXML_XPTR_ENABLED */
992
993/**
994 * xmlXPathDebugDumpObject:
995 * @output:  the FILE * to dump the output
996 * @cur:  the object to inspect
997 * @depth:  indentation level
998 *
999 * Dump the content of the object for debugging purposes
1000 */
1001void
1002xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1003    int i;
1004    char shift[100];
1005
1006    if (output == NULL) return;
1007
1008    for (i = 0;((i < depth) && (i < 25));i++)
1009        shift[2 * i] = shift[2 * i + 1] = ' ';
1010    shift[2 * i] = shift[2 * i + 1] = 0;
1011
1012
1013    fprintf(output, shift);
1014
1015    if (cur == NULL) {
1016        fprintf(output, "Object is empty (NULL)\n");
1017	return;
1018    }
1019    switch(cur->type) {
1020        case XPATH_UNDEFINED:
1021	    fprintf(output, "Object is uninitialized\n");
1022	    break;
1023        case XPATH_NODESET:
1024	    fprintf(output, "Object is a Node Set :\n");
1025	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1026	    break;
1027	case XPATH_XSLT_TREE:
1028	    fprintf(output, "Object is an XSLT value tree :\n");
1029	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1030	    break;
1031        case XPATH_BOOLEAN:
1032	    fprintf(output, "Object is a Boolean : ");
1033	    if (cur->boolval) fprintf(output, "true\n");
1034	    else fprintf(output, "false\n");
1035	    break;
1036        case XPATH_NUMBER:
1037	    switch (xmlXPathIsInf(cur->floatval)) {
1038	    case 1:
1039		fprintf(output, "Object is a number : Infinity\n");
1040		break;
1041	    case -1:
1042		fprintf(output, "Object is a number : -Infinity\n");
1043		break;
1044	    default:
1045		if (xmlXPathIsNaN(cur->floatval)) {
1046		    fprintf(output, "Object is a number : NaN\n");
1047		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1048		    fprintf(output, "Object is a number : 0\n");
1049		} else {
1050		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1051		}
1052	    }
1053	    break;
1054        case XPATH_STRING:
1055	    fprintf(output, "Object is a string : ");
1056	    xmlDebugDumpString(output, cur->stringval);
1057	    fprintf(output, "\n");
1058	    break;
1059	case XPATH_POINT:
1060	    fprintf(output, "Object is a point : index %d in node", cur->index);
1061	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1062	    fprintf(output, "\n");
1063	    break;
1064	case XPATH_RANGE:
1065	    if ((cur->user2 == NULL) ||
1066		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1067		fprintf(output, "Object is a collapsed range :\n");
1068		fprintf(output, shift);
1069		if (cur->index >= 0)
1070		    fprintf(output, "index %d in ", cur->index);
1071		fprintf(output, "node\n");
1072		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1073			              depth + 1);
1074	    } else  {
1075		fprintf(output, "Object is a range :\n");
1076		fprintf(output, shift);
1077		fprintf(output, "From ");
1078		if (cur->index >= 0)
1079		    fprintf(output, "index %d in ", cur->index);
1080		fprintf(output, "node\n");
1081		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1082			              depth + 1);
1083		fprintf(output, shift);
1084		fprintf(output, "To ");
1085		if (cur->index2 >= 0)
1086		    fprintf(output, "index %d in ", cur->index2);
1087		fprintf(output, "node\n");
1088		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1089			              depth + 1);
1090		fprintf(output, "\n");
1091	    }
1092	    break;
1093	case XPATH_LOCATIONSET:
1094#if defined(LIBXML_XPTR_ENABLED)
1095	    fprintf(output, "Object is a Location Set:\n");
1096	    xmlXPathDebugDumpLocationSet(output,
1097		    (xmlLocationSetPtr) cur->user, depth);
1098#endif
1099	    break;
1100	case XPATH_USERS:
1101	    fprintf(output, "Object is user defined\n");
1102	    break;
1103    }
1104}
1105
1106static void
1107xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1108	                     xmlXPathStepOpPtr op, int depth) {
1109    int i;
1110    char shift[100];
1111
1112    for (i = 0;((i < depth) && (i < 25));i++)
1113        shift[2 * i] = shift[2 * i + 1] = ' ';
1114    shift[2 * i] = shift[2 * i + 1] = 0;
1115
1116    fprintf(output, shift);
1117    if (op == NULL) {
1118	fprintf(output, "Step is NULL\n");
1119	return;
1120    }
1121    switch (op->op) {
1122        case XPATH_OP_END:
1123	    fprintf(output, "END"); break;
1124        case XPATH_OP_AND:
1125	    fprintf(output, "AND"); break;
1126        case XPATH_OP_OR:
1127	    fprintf(output, "OR"); break;
1128        case XPATH_OP_EQUAL:
1129	     if (op->value)
1130		 fprintf(output, "EQUAL =");
1131	     else
1132		 fprintf(output, "EQUAL !=");
1133	     break;
1134        case XPATH_OP_CMP:
1135	     if (op->value)
1136		 fprintf(output, "CMP <");
1137	     else
1138		 fprintf(output, "CMP >");
1139	     if (!op->value2)
1140		 fprintf(output, "=");
1141	     break;
1142        case XPATH_OP_PLUS:
1143	     if (op->value == 0)
1144		 fprintf(output, "PLUS -");
1145	     else if (op->value == 1)
1146		 fprintf(output, "PLUS +");
1147	     else if (op->value == 2)
1148		 fprintf(output, "PLUS unary -");
1149	     else if (op->value == 3)
1150		 fprintf(output, "PLUS unary - -");
1151	     break;
1152        case XPATH_OP_MULT:
1153	     if (op->value == 0)
1154		 fprintf(output, "MULT *");
1155	     else if (op->value == 1)
1156		 fprintf(output, "MULT div");
1157	     else
1158		 fprintf(output, "MULT mod");
1159	     break;
1160        case XPATH_OP_UNION:
1161	     fprintf(output, "UNION"); break;
1162        case XPATH_OP_ROOT:
1163	     fprintf(output, "ROOT"); break;
1164        case XPATH_OP_NODE:
1165	     fprintf(output, "NODE"); break;
1166        case XPATH_OP_RESET:
1167	     fprintf(output, "RESET"); break;
1168        case XPATH_OP_SORT:
1169	     fprintf(output, "SORT"); break;
1170        case XPATH_OP_COLLECT: {
1171	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1172	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1173	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1174	    const xmlChar *prefix = op->value4;
1175	    const xmlChar *name = op->value5;
1176
1177	    fprintf(output, "COLLECT ");
1178	    switch (axis) {
1179		case AXIS_ANCESTOR:
1180		    fprintf(output, " 'ancestors' "); break;
1181		case AXIS_ANCESTOR_OR_SELF:
1182		    fprintf(output, " 'ancestors-or-self' "); break;
1183		case AXIS_ATTRIBUTE:
1184		    fprintf(output, " 'attributes' "); break;
1185		case AXIS_CHILD:
1186		    fprintf(output, " 'child' "); break;
1187		case AXIS_DESCENDANT:
1188		    fprintf(output, " 'descendant' "); break;
1189		case AXIS_DESCENDANT_OR_SELF:
1190		    fprintf(output, " 'descendant-or-self' "); break;
1191		case AXIS_FOLLOWING:
1192		    fprintf(output, " 'following' "); break;
1193		case AXIS_FOLLOWING_SIBLING:
1194		    fprintf(output, " 'following-siblings' "); break;
1195		case AXIS_NAMESPACE:
1196		    fprintf(output, " 'namespace' "); break;
1197		case AXIS_PARENT:
1198		    fprintf(output, " 'parent' "); break;
1199		case AXIS_PRECEDING:
1200		    fprintf(output, " 'preceding' "); break;
1201		case AXIS_PRECEDING_SIBLING:
1202		    fprintf(output, " 'preceding-sibling' "); break;
1203		case AXIS_SELF:
1204		    fprintf(output, " 'self' "); break;
1205	    }
1206	    switch (test) {
1207                case NODE_TEST_NONE:
1208		    fprintf(output, "'none' "); break;
1209                case NODE_TEST_TYPE:
1210		    fprintf(output, "'type' "); break;
1211                case NODE_TEST_PI:
1212		    fprintf(output, "'PI' "); break;
1213                case NODE_TEST_ALL:
1214		    fprintf(output, "'all' "); break;
1215                case NODE_TEST_NS:
1216		    fprintf(output, "'namespace' "); break;
1217                case NODE_TEST_NAME:
1218		    fprintf(output, "'name' "); break;
1219	    }
1220	    switch (type) {
1221                case NODE_TYPE_NODE:
1222		    fprintf(output, "'node' "); break;
1223                case NODE_TYPE_COMMENT:
1224		    fprintf(output, "'comment' "); break;
1225                case NODE_TYPE_TEXT:
1226		    fprintf(output, "'text' "); break;
1227                case NODE_TYPE_PI:
1228		    fprintf(output, "'PI' "); break;
1229	    }
1230	    if (prefix != NULL)
1231		fprintf(output, "%s:", prefix);
1232	    if (name != NULL)
1233		fprintf(output, "%s", (const char *) name);
1234	    break;
1235
1236        }
1237	case XPATH_OP_VALUE: {
1238	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1239
1240	    fprintf(output, "ELEM ");
1241	    xmlXPathDebugDumpObject(output, object, 0);
1242	    goto finish;
1243	}
1244	case XPATH_OP_VARIABLE: {
1245	    const xmlChar *prefix = op->value5;
1246	    const xmlChar *name = op->value4;
1247
1248	    if (prefix != NULL)
1249		fprintf(output, "VARIABLE %s:%s", prefix, name);
1250	    else
1251		fprintf(output, "VARIABLE %s", name);
1252	    break;
1253	}
1254	case XPATH_OP_FUNCTION: {
1255	    int nbargs = op->value;
1256	    const xmlChar *prefix = op->value5;
1257	    const xmlChar *name = op->value4;
1258
1259	    if (prefix != NULL)
1260		fprintf(output, "FUNCTION %s:%s(%d args)",
1261			prefix, name, nbargs);
1262	    else
1263		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1264	    break;
1265	}
1266        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1267        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1268        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1269#ifdef LIBXML_XPTR_ENABLED
1270        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1271#endif
1272	default:
1273        fprintf(output, "UNKNOWN %d\n", op->op); return;
1274    }
1275    fprintf(output, "\n");
1276finish:
1277    if (op->ch1 >= 0)
1278	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1279    if (op->ch2 >= 0)
1280	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1281}
1282
1283/**
1284 * xmlXPathDebugDumpCompExpr:
1285 * @output:  the FILE * for the output
1286 * @comp:  the precompiled XPath expression
1287 * @depth:  the indentation level.
1288 *
1289 * Dumps the tree of the compiled XPath expression.
1290 */
1291void
1292xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1293	                  int depth) {
1294    int i;
1295    char shift[100];
1296
1297    if ((output == NULL) || (comp == NULL)) return;
1298
1299    for (i = 0;((i < depth) && (i < 25));i++)
1300        shift[2 * i] = shift[2 * i + 1] = ' ';
1301    shift[2 * i] = shift[2 * i + 1] = 0;
1302
1303    fprintf(output, shift);
1304
1305    fprintf(output, "Compiled Expression : %d elements\n",
1306	    comp->nbStep);
1307    i = comp->last;
1308    xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1309}
1310
1311#ifdef XP_DEBUG_OBJ_USAGE
1312
1313/*
1314* XPath object usage related debugging variables.
1315*/
1316static int xmlXPathDebugObjCounterUndefined = 0;
1317static int xmlXPathDebugObjCounterNodeset = 0;
1318static int xmlXPathDebugObjCounterBool = 0;
1319static int xmlXPathDebugObjCounterNumber = 0;
1320static int xmlXPathDebugObjCounterString = 0;
1321static int xmlXPathDebugObjCounterPoint = 0;
1322static int xmlXPathDebugObjCounterRange = 0;
1323static int xmlXPathDebugObjCounterLocset = 0;
1324static int xmlXPathDebugObjCounterUsers = 0;
1325static int xmlXPathDebugObjCounterXSLTTree = 0;
1326static int xmlXPathDebugObjCounterAll = 0;
1327
1328static int xmlXPathDebugObjTotalUndefined = 0;
1329static int xmlXPathDebugObjTotalNodeset = 0;
1330static int xmlXPathDebugObjTotalBool = 0;
1331static int xmlXPathDebugObjTotalNumber = 0;
1332static int xmlXPathDebugObjTotalString = 0;
1333static int xmlXPathDebugObjTotalPoint = 0;
1334static int xmlXPathDebugObjTotalRange = 0;
1335static int xmlXPathDebugObjTotalLocset = 0;
1336static int xmlXPathDebugObjTotalUsers = 0;
1337static int xmlXPathDebugObjTotalXSLTTree = 0;
1338static int xmlXPathDebugObjTotalAll = 0;
1339
1340static int xmlXPathDebugObjMaxUndefined = 0;
1341static int xmlXPathDebugObjMaxNodeset = 0;
1342static int xmlXPathDebugObjMaxBool = 0;
1343static int xmlXPathDebugObjMaxNumber = 0;
1344static int xmlXPathDebugObjMaxString = 0;
1345static int xmlXPathDebugObjMaxPoint = 0;
1346static int xmlXPathDebugObjMaxRange = 0;
1347static int xmlXPathDebugObjMaxLocset = 0;
1348static int xmlXPathDebugObjMaxUsers = 0;
1349static int xmlXPathDebugObjMaxXSLTTree = 0;
1350static int xmlXPathDebugObjMaxAll = 0;
1351
1352/* REVISIT TODO: Make this static when committing */
1353static void
1354xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1355{
1356    if (ctxt != NULL) {
1357	if (ctxt->cache != NULL) {
1358	    xmlXPathContextCachePtr cache =
1359		(xmlXPathContextCachePtr) ctxt->cache;
1360
1361	    cache->dbgCachedAll = 0;
1362	    cache->dbgCachedNodeset = 0;
1363	    cache->dbgCachedString = 0;
1364	    cache->dbgCachedBool = 0;
1365	    cache->dbgCachedNumber = 0;
1366	    cache->dbgCachedPoint = 0;
1367	    cache->dbgCachedRange = 0;
1368	    cache->dbgCachedLocset = 0;
1369	    cache->dbgCachedUsers = 0;
1370	    cache->dbgCachedXSLTTree = 0;
1371	    cache->dbgCachedUndefined = 0;
1372
1373	    cache->dbgReusedAll = 0;
1374	    cache->dbgReusedNodeset = 0;
1375	    cache->dbgReusedString = 0;
1376	    cache->dbgReusedBool = 0;
1377	    cache->dbgReusedNumber = 0;
1378	    cache->dbgReusedPoint = 0;
1379	    cache->dbgReusedRange = 0;
1380	    cache->dbgReusedLocset = 0;
1381	    cache->dbgReusedUsers = 0;
1382	    cache->dbgReusedXSLTTree = 0;
1383	    cache->dbgReusedUndefined = 0;
1384	}
1385    }
1386
1387    xmlXPathDebugObjCounterUndefined = 0;
1388    xmlXPathDebugObjCounterNodeset = 0;
1389    xmlXPathDebugObjCounterBool = 0;
1390    xmlXPathDebugObjCounterNumber = 0;
1391    xmlXPathDebugObjCounterString = 0;
1392    xmlXPathDebugObjCounterPoint = 0;
1393    xmlXPathDebugObjCounterRange = 0;
1394    xmlXPathDebugObjCounterLocset = 0;
1395    xmlXPathDebugObjCounterUsers = 0;
1396    xmlXPathDebugObjCounterXSLTTree = 0;
1397    xmlXPathDebugObjCounterAll = 0;
1398
1399    xmlXPathDebugObjTotalUndefined = 0;
1400    xmlXPathDebugObjTotalNodeset = 0;
1401    xmlXPathDebugObjTotalBool = 0;
1402    xmlXPathDebugObjTotalNumber = 0;
1403    xmlXPathDebugObjTotalString = 0;
1404    xmlXPathDebugObjTotalPoint = 0;
1405    xmlXPathDebugObjTotalRange = 0;
1406    xmlXPathDebugObjTotalLocset = 0;
1407    xmlXPathDebugObjTotalUsers = 0;
1408    xmlXPathDebugObjTotalXSLTTree = 0;
1409    xmlXPathDebugObjTotalAll = 0;
1410
1411    xmlXPathDebugObjMaxUndefined = 0;
1412    xmlXPathDebugObjMaxNodeset = 0;
1413    xmlXPathDebugObjMaxBool = 0;
1414    xmlXPathDebugObjMaxNumber = 0;
1415    xmlXPathDebugObjMaxString = 0;
1416    xmlXPathDebugObjMaxPoint = 0;
1417    xmlXPathDebugObjMaxRange = 0;
1418    xmlXPathDebugObjMaxLocset = 0;
1419    xmlXPathDebugObjMaxUsers = 0;
1420    xmlXPathDebugObjMaxXSLTTree = 0;
1421    xmlXPathDebugObjMaxAll = 0;
1422
1423}
1424
1425static void
1426xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1427			      xmlXPathObjectType objType)
1428{
1429    int isCached = 0;
1430
1431    if (ctxt != NULL) {
1432	if (ctxt->cache != NULL) {
1433	    xmlXPathContextCachePtr cache =
1434		(xmlXPathContextCachePtr) ctxt->cache;
1435
1436	    isCached = 1;
1437
1438	    cache->dbgReusedAll++;
1439	    switch (objType) {
1440		case XPATH_UNDEFINED:
1441		    cache->dbgReusedUndefined++;
1442		    break;
1443		case XPATH_NODESET:
1444		    cache->dbgReusedNodeset++;
1445		    break;
1446		case XPATH_BOOLEAN:
1447		    cache->dbgReusedBool++;
1448		    break;
1449		case XPATH_NUMBER:
1450		    cache->dbgReusedNumber++;
1451		    break;
1452		case XPATH_STRING:
1453		    cache->dbgReusedString++;
1454		    break;
1455		case XPATH_POINT:
1456		    cache->dbgReusedPoint++;
1457		    break;
1458		case XPATH_RANGE:
1459		    cache->dbgReusedRange++;
1460		    break;
1461		case XPATH_LOCATIONSET:
1462		    cache->dbgReusedLocset++;
1463		    break;
1464		case XPATH_USERS:
1465		    cache->dbgReusedUsers++;
1466		    break;
1467		case XPATH_XSLT_TREE:
1468		    cache->dbgReusedXSLTTree++;
1469		    break;
1470		default:
1471		    break;
1472	    }
1473	}
1474    }
1475
1476    switch (objType) {
1477	case XPATH_UNDEFINED:
1478	    if (! isCached)
1479		xmlXPathDebugObjTotalUndefined++;
1480	    xmlXPathDebugObjCounterUndefined++;
1481	    if (xmlXPathDebugObjCounterUndefined >
1482		xmlXPathDebugObjMaxUndefined)
1483		xmlXPathDebugObjMaxUndefined =
1484		    xmlXPathDebugObjCounterUndefined;
1485	    break;
1486	case XPATH_NODESET:
1487	    if (! isCached)
1488		xmlXPathDebugObjTotalNodeset++;
1489	    xmlXPathDebugObjCounterNodeset++;
1490	    if (xmlXPathDebugObjCounterNodeset >
1491		xmlXPathDebugObjMaxNodeset)
1492		xmlXPathDebugObjMaxNodeset =
1493		    xmlXPathDebugObjCounterNodeset;
1494	    break;
1495	case XPATH_BOOLEAN:
1496	    if (! isCached)
1497		xmlXPathDebugObjTotalBool++;
1498	    xmlXPathDebugObjCounterBool++;
1499	    if (xmlXPathDebugObjCounterBool >
1500		xmlXPathDebugObjMaxBool)
1501		xmlXPathDebugObjMaxBool =
1502		    xmlXPathDebugObjCounterBool;
1503	    break;
1504	case XPATH_NUMBER:
1505	    if (! isCached)
1506		xmlXPathDebugObjTotalNumber++;
1507	    xmlXPathDebugObjCounterNumber++;
1508	    if (xmlXPathDebugObjCounterNumber >
1509		xmlXPathDebugObjMaxNumber)
1510		xmlXPathDebugObjMaxNumber =
1511		    xmlXPathDebugObjCounterNumber;
1512	    break;
1513	case XPATH_STRING:
1514	    if (! isCached)
1515		xmlXPathDebugObjTotalString++;
1516	    xmlXPathDebugObjCounterString++;
1517	    if (xmlXPathDebugObjCounterString >
1518		xmlXPathDebugObjMaxString)
1519		xmlXPathDebugObjMaxString =
1520		    xmlXPathDebugObjCounterString;
1521	    break;
1522	case XPATH_POINT:
1523	    if (! isCached)
1524		xmlXPathDebugObjTotalPoint++;
1525	    xmlXPathDebugObjCounterPoint++;
1526	    if (xmlXPathDebugObjCounterPoint >
1527		xmlXPathDebugObjMaxPoint)
1528		xmlXPathDebugObjMaxPoint =
1529		    xmlXPathDebugObjCounterPoint;
1530	    break;
1531	case XPATH_RANGE:
1532	    if (! isCached)
1533		xmlXPathDebugObjTotalRange++;
1534	    xmlXPathDebugObjCounterRange++;
1535	    if (xmlXPathDebugObjCounterRange >
1536		xmlXPathDebugObjMaxRange)
1537		xmlXPathDebugObjMaxRange =
1538		    xmlXPathDebugObjCounterRange;
1539	    break;
1540	case XPATH_LOCATIONSET:
1541	    if (! isCached)
1542		xmlXPathDebugObjTotalLocset++;
1543	    xmlXPathDebugObjCounterLocset++;
1544	    if (xmlXPathDebugObjCounterLocset >
1545		xmlXPathDebugObjMaxLocset)
1546		xmlXPathDebugObjMaxLocset =
1547		    xmlXPathDebugObjCounterLocset;
1548	    break;
1549	case XPATH_USERS:
1550	    if (! isCached)
1551		xmlXPathDebugObjTotalUsers++;
1552	    xmlXPathDebugObjCounterUsers++;
1553	    if (xmlXPathDebugObjCounterUsers >
1554		xmlXPathDebugObjMaxUsers)
1555		xmlXPathDebugObjMaxUsers =
1556		    xmlXPathDebugObjCounterUsers;
1557	    break;
1558	case XPATH_XSLT_TREE:
1559	    if (! isCached)
1560		xmlXPathDebugObjTotalXSLTTree++;
1561	    xmlXPathDebugObjCounterXSLTTree++;
1562	    if (xmlXPathDebugObjCounterXSLTTree >
1563		xmlXPathDebugObjMaxXSLTTree)
1564		xmlXPathDebugObjMaxXSLTTree =
1565		    xmlXPathDebugObjCounterXSLTTree;
1566	    break;
1567	default:
1568	    break;
1569    }
1570    if (! isCached)
1571	xmlXPathDebugObjTotalAll++;
1572    xmlXPathDebugObjCounterAll++;
1573    if (xmlXPathDebugObjCounterAll >
1574	xmlXPathDebugObjMaxAll)
1575	xmlXPathDebugObjMaxAll =
1576	    xmlXPathDebugObjCounterAll;
1577}
1578
1579static void
1580xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1581			      xmlXPathObjectType objType)
1582{
1583    int isCached = 0;
1584
1585    if (ctxt != NULL) {
1586	if (ctxt->cache != NULL) {
1587	    xmlXPathContextCachePtr cache =
1588		(xmlXPathContextCachePtr) ctxt->cache;
1589
1590	    isCached = 1;
1591
1592	    cache->dbgCachedAll++;
1593	    switch (objType) {
1594		case XPATH_UNDEFINED:
1595		    cache->dbgCachedUndefined++;
1596		    break;
1597		case XPATH_NODESET:
1598		    cache->dbgCachedNodeset++;
1599		    break;
1600		case XPATH_BOOLEAN:
1601		    cache->dbgCachedBool++;
1602		    break;
1603		case XPATH_NUMBER:
1604		    cache->dbgCachedNumber++;
1605		    break;
1606		case XPATH_STRING:
1607		    cache->dbgCachedString++;
1608		    break;
1609		case XPATH_POINT:
1610		    cache->dbgCachedPoint++;
1611		    break;
1612		case XPATH_RANGE:
1613		    cache->dbgCachedRange++;
1614		    break;
1615		case XPATH_LOCATIONSET:
1616		    cache->dbgCachedLocset++;
1617		    break;
1618		case XPATH_USERS:
1619		    cache->dbgCachedUsers++;
1620		    break;
1621		case XPATH_XSLT_TREE:
1622		    cache->dbgCachedXSLTTree++;
1623		    break;
1624		default:
1625		    break;
1626	    }
1627
1628	}
1629    }
1630    switch (objType) {
1631	case XPATH_UNDEFINED:
1632	    xmlXPathDebugObjCounterUndefined--;
1633	    break;
1634	case XPATH_NODESET:
1635	    xmlXPathDebugObjCounterNodeset--;
1636	    break;
1637	case XPATH_BOOLEAN:
1638	    xmlXPathDebugObjCounterBool--;
1639	    break;
1640	case XPATH_NUMBER:
1641	    xmlXPathDebugObjCounterNumber--;
1642	    break;
1643	case XPATH_STRING:
1644	    xmlXPathDebugObjCounterString--;
1645	    break;
1646	case XPATH_POINT:
1647	    xmlXPathDebugObjCounterPoint--;
1648	    break;
1649	case XPATH_RANGE:
1650	    xmlXPathDebugObjCounterRange--;
1651	    break;
1652	case XPATH_LOCATIONSET:
1653	    xmlXPathDebugObjCounterLocset--;
1654	    break;
1655	case XPATH_USERS:
1656	    xmlXPathDebugObjCounterUsers--;
1657	    break;
1658	case XPATH_XSLT_TREE:
1659	    xmlXPathDebugObjCounterXSLTTree--;
1660	    break;
1661	default:
1662	    break;
1663    }
1664    xmlXPathDebugObjCounterAll--;
1665}
1666
1667/* REVISIT TODO: Make this static when committing */
1668static void
1669xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1670{
1671    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1672	reqXSLTTree, reqUndefined;
1673    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1674	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1675    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1676	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1677    int leftObjs = xmlXPathDebugObjCounterAll;
1678
1679    reqAll = xmlXPathDebugObjTotalAll;
1680    reqNodeset = xmlXPathDebugObjTotalNodeset;
1681    reqString = xmlXPathDebugObjTotalString;
1682    reqBool = xmlXPathDebugObjTotalBool;
1683    reqNumber = xmlXPathDebugObjTotalNumber;
1684    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1685    reqUndefined = xmlXPathDebugObjTotalUndefined;
1686
1687    printf("# XPath object usage:\n");
1688
1689    if (ctxt != NULL) {
1690	if (ctxt->cache != NULL) {
1691	    xmlXPathContextCachePtr cache =
1692		(xmlXPathContextCachePtr) ctxt->cache;
1693
1694	    reAll = cache->dbgReusedAll;
1695	    reqAll += reAll;
1696	    reNodeset = cache->dbgReusedNodeset;
1697	    reqNodeset += reNodeset;
1698	    reString = cache->dbgReusedString;
1699	    reqString += reString;
1700	    reBool = cache->dbgReusedBool;
1701	    reqBool += reBool;
1702	    reNumber = cache->dbgReusedNumber;
1703	    reqNumber += reNumber;
1704	    reXSLTTree = cache->dbgReusedXSLTTree;
1705	    reqXSLTTree += reXSLTTree;
1706	    reUndefined = cache->dbgReusedUndefined;
1707	    reqUndefined += reUndefined;
1708
1709	    caAll = cache->dbgCachedAll;
1710	    caBool = cache->dbgCachedBool;
1711	    caNodeset = cache->dbgCachedNodeset;
1712	    caString = cache->dbgCachedString;
1713	    caNumber = cache->dbgCachedNumber;
1714	    caXSLTTree = cache->dbgCachedXSLTTree;
1715	    caUndefined = cache->dbgCachedUndefined;
1716
1717	    if (cache->nodesetObjs)
1718		leftObjs -= cache->nodesetObjs->number;
1719	    if (cache->stringObjs)
1720		leftObjs -= cache->stringObjs->number;
1721	    if (cache->booleanObjs)
1722		leftObjs -= cache->booleanObjs->number;
1723	    if (cache->numberObjs)
1724		leftObjs -= cache->numberObjs->number;
1725	    if (cache->miscObjs)
1726		leftObjs -= cache->miscObjs->number;
1727	}
1728    }
1729
1730    printf("# all\n");
1731    printf("#   total  : %d\n", reqAll);
1732    printf("#   left  : %d\n", leftObjs);
1733    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
1734    printf("#   reused : %d\n", reAll);
1735    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
1736
1737    printf("# node-sets\n");
1738    printf("#   total  : %d\n", reqNodeset);
1739    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
1740    printf("#   reused : %d\n", reNodeset);
1741    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
1742
1743    printf("# strings\n");
1744    printf("#   total  : %d\n", reqString);
1745    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
1746    printf("#   reused : %d\n", reString);
1747    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
1748
1749    printf("# booleans\n");
1750    printf("#   total  : %d\n", reqBool);
1751    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
1752    printf("#   reused : %d\n", reBool);
1753    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
1754
1755    printf("# numbers\n");
1756    printf("#   total  : %d\n", reqNumber);
1757    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
1758    printf("#   reused : %d\n", reNumber);
1759    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
1760
1761    printf("# XSLT result tree fragments\n");
1762    printf("#   total  : %d\n", reqXSLTTree);
1763    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1764    printf("#   reused : %d\n", reXSLTTree);
1765    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
1766
1767    printf("# undefined\n");
1768    printf("#   total  : %d\n", reqUndefined);
1769    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
1770    printf("#   reused : %d\n", reUndefined);
1771    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
1772
1773}
1774
1775#endif /* XP_DEBUG_OBJ_USAGE */
1776
1777#endif /* LIBXML_DEBUG_ENABLED */
1778
1779/************************************************************************
1780 *									*
1781 *			XPath object caching				*
1782 *									*
1783 ************************************************************************/
1784
1785/**
1786 * xmlXPathNewCache:
1787 *
1788 * Create a new object cache
1789 *
1790 * Returns the xmlXPathCache just allocated.
1791 */
1792static xmlXPathContextCachePtr
1793xmlXPathNewCache(void)
1794{
1795    xmlXPathContextCachePtr ret;
1796
1797    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1798    if (ret == NULL) {
1799        xmlXPathErrMemory(NULL, "creating object cache\n");
1800	return(NULL);
1801    }
1802    memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1803    ret->maxNodeset = 100;
1804    ret->maxString = 100;
1805    ret->maxBoolean = 100;
1806    ret->maxNumber = 100;
1807    ret->maxMisc = 100;
1808    return(ret);
1809}
1810
1811static void
1812xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1813{
1814    int i;
1815    xmlXPathObjectPtr obj;
1816
1817    if (list == NULL)
1818	return;
1819
1820    for (i = 0; i < list->number; i++) {
1821	obj = list->items[i];
1822	/*
1823	* Note that it is already assured that we don't need to
1824	* look out for namespace nodes in the node-set.
1825	*/
1826	if (obj->nodesetval != NULL) {
1827	    if (obj->nodesetval->nodeTab != NULL)
1828		xmlFree(obj->nodesetval->nodeTab);
1829	    xmlFree(obj->nodesetval);
1830	}
1831	xmlFree(obj);
1832#ifdef XP_DEBUG_OBJ_USAGE
1833	xmlXPathDebugObjCounterAll--;
1834#endif
1835    }
1836    xmlPointerListFree(list);
1837}
1838
1839static void
1840xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1841{
1842    if (cache == NULL)
1843	return;
1844    if (cache->nodesetObjs)
1845	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1846    if (cache->stringObjs)
1847	xmlXPathCacheFreeObjectList(cache->stringObjs);
1848    if (cache->booleanObjs)
1849	xmlXPathCacheFreeObjectList(cache->booleanObjs);
1850    if (cache->numberObjs)
1851	xmlXPathCacheFreeObjectList(cache->numberObjs);
1852    if (cache->miscObjs)
1853	xmlXPathCacheFreeObjectList(cache->miscObjs);
1854    xmlFree(cache);
1855}
1856
1857/**
1858 * xmlXPathContextSetCache:
1859 *
1860 * @ctxt:  the XPath context
1861 * @active: enables/disables (creates/frees) the cache
1862 * @value: a value with semantics dependant on @options
1863 * @options: options (currently only the value 0 is used)
1864 *
1865 * Creates/frees an object cache on the XPath context.
1866 * If activates XPath objects (xmlXPathObject) will be cached internally
1867 * to be reused.
1868 * @options:
1869 *   0: This will set the XPath object caching:
1870 *      @value:
1871 *        This will set the maximum number of XPath objects
1872 *        to be cached per slot
1873 *        There are 5 slots for: node-set, string, number, boolean, and
1874 *        misc objects. Use <0 for the default number (100).
1875 *   Other values for @options have currently no effect.
1876 *
1877 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1878 */
1879int
1880xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1881			int active,
1882			int value,
1883			int options)
1884{
1885    if (ctxt == NULL)
1886	return(-1);
1887    if (active) {
1888	xmlXPathContextCachePtr cache;
1889
1890	if (ctxt->cache == NULL) {
1891	    ctxt->cache = xmlXPathNewCache();
1892	    if (ctxt->cache == NULL)
1893		return(-1);
1894	}
1895	cache = (xmlXPathContextCachePtr) ctxt->cache;
1896	if (options == 0) {
1897	    if (value < 0)
1898		value = 100;
1899	    cache->maxNodeset = value;
1900	    cache->maxString = value;
1901	    cache->maxNumber = value;
1902	    cache->maxBoolean = value;
1903	    cache->maxMisc = value;
1904	}
1905    } else if (ctxt->cache != NULL) {
1906	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1907	ctxt->cache = NULL;
1908    }
1909    return(0);
1910}
1911
1912/**
1913 * xmlXPathCacheWrapNodeSet:
1914 * @ctxt: the XPath context
1915 * @val:  the NodePtr value
1916 *
1917 * This is the cached version of xmlXPathWrapNodeSet().
1918 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1919 *
1920 * Returns the created or reused object.
1921 */
1922static xmlXPathObjectPtr
1923xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1924{
1925    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1926	xmlXPathContextCachePtr cache =
1927	    (xmlXPathContextCachePtr) ctxt->cache;
1928
1929	if ((cache->miscObjs != NULL) &&
1930	    (cache->miscObjs->number != 0))
1931	{
1932	    xmlXPathObjectPtr ret;
1933
1934	    ret = (xmlXPathObjectPtr)
1935		cache->miscObjs->items[--cache->miscObjs->number];
1936	    ret->type = XPATH_NODESET;
1937	    ret->nodesetval = val;
1938#ifdef XP_DEBUG_OBJ_USAGE
1939	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1940#endif
1941	    return(ret);
1942	}
1943    }
1944
1945    return(xmlXPathWrapNodeSet(val));
1946
1947}
1948
1949/**
1950 * xmlXPathCacheWrapString:
1951 * @ctxt: the XPath context
1952 * @val:  the xmlChar * value
1953 *
1954 * This is the cached version of xmlXPathWrapString().
1955 * Wraps the @val string into an XPath object.
1956 *
1957 * Returns the created or reused object.
1958 */
1959static xmlXPathObjectPtr
1960xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1961{
1962    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1963	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1964
1965	if ((cache->stringObjs != NULL) &&
1966	    (cache->stringObjs->number != 0))
1967	{
1968
1969	    xmlXPathObjectPtr ret;
1970
1971	    ret = (xmlXPathObjectPtr)
1972		cache->stringObjs->items[--cache->stringObjs->number];
1973	    ret->type = XPATH_STRING;
1974	    ret->stringval = val;
1975#ifdef XP_DEBUG_OBJ_USAGE
1976	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1977#endif
1978	    return(ret);
1979	} else if ((cache->miscObjs != NULL) &&
1980	    (cache->miscObjs->number != 0))
1981	{
1982	    xmlXPathObjectPtr ret;
1983	    /*
1984	    * Fallback to misc-cache.
1985	    */
1986	    ret = (xmlXPathObjectPtr)
1987		cache->miscObjs->items[--cache->miscObjs->number];
1988
1989	    ret->type = XPATH_STRING;
1990	    ret->stringval = val;
1991#ifdef XP_DEBUG_OBJ_USAGE
1992	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1993#endif
1994	    return(ret);
1995	}
1996    }
1997    return(xmlXPathWrapString(val));
1998}
1999
2000/**
2001 * xmlXPathCacheNewNodeSet:
2002 * @ctxt: the XPath context
2003 * @val:  the NodePtr value
2004 *
2005 * This is the cached version of xmlXPathNewNodeSet().
2006 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2007 * it with the single Node @val
2008 *
2009 * Returns the created or reused object.
2010 */
2011static xmlXPathObjectPtr
2012xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2013{
2014    if ((ctxt != NULL) && (ctxt->cache)) {
2015	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2016
2017	if ((cache->nodesetObjs != NULL) &&
2018	    (cache->nodesetObjs->number != 0))
2019	{
2020	    xmlXPathObjectPtr ret;
2021	    /*
2022	    * Use the nodset-cache.
2023	    */
2024	    ret = (xmlXPathObjectPtr)
2025		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2026	    ret->type = XPATH_NODESET;
2027	    ret->boolval = 0;
2028	    if (val) {
2029		if ((ret->nodesetval->nodeMax == 0) ||
2030		    (val->type == XML_NAMESPACE_DECL))
2031		{
2032		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2033		} else {
2034		    ret->nodesetval->nodeTab[0] = val;
2035		    ret->nodesetval->nodeNr = 1;
2036		}
2037	    }
2038#ifdef XP_DEBUG_OBJ_USAGE
2039	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2040#endif
2041	    return(ret);
2042	} else if ((cache->miscObjs != NULL) &&
2043	    (cache->miscObjs->number != 0))
2044	{
2045	    xmlXPathObjectPtr ret;
2046	    /*
2047	    * Fallback to misc-cache.
2048	    */
2049
2050	    ret = (xmlXPathObjectPtr)
2051		cache->miscObjs->items[--cache->miscObjs->number];
2052
2053	    ret->type = XPATH_NODESET;
2054	    ret->boolval = 0;
2055	    ret->nodesetval = xmlXPathNodeSetCreate(val);
2056#ifdef XP_DEBUG_OBJ_USAGE
2057	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2058#endif
2059	    return(ret);
2060	}
2061    }
2062    return(xmlXPathNewNodeSet(val));
2063}
2064
2065/**
2066 * xmlXPathCacheNewCString:
2067 * @ctxt: the XPath context
2068 * @val:  the char * value
2069 *
2070 * This is the cached version of xmlXPathNewCString().
2071 * Acquire an xmlXPathObjectPtr of type string and of value @val
2072 *
2073 * Returns the created or reused object.
2074 */
2075static xmlXPathObjectPtr
2076xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2077{
2078    if ((ctxt != NULL) && (ctxt->cache)) {
2079	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2080
2081	if ((cache->stringObjs != NULL) &&
2082	    (cache->stringObjs->number != 0))
2083	{
2084	    xmlXPathObjectPtr ret;
2085
2086	    ret = (xmlXPathObjectPtr)
2087		cache->stringObjs->items[--cache->stringObjs->number];
2088
2089	    ret->type = XPATH_STRING;
2090	    ret->stringval = xmlStrdup(BAD_CAST val);
2091#ifdef XP_DEBUG_OBJ_USAGE
2092	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2093#endif
2094	    return(ret);
2095	} else if ((cache->miscObjs != NULL) &&
2096	    (cache->miscObjs->number != 0))
2097	{
2098	    xmlXPathObjectPtr ret;
2099
2100	    ret = (xmlXPathObjectPtr)
2101		cache->miscObjs->items[--cache->miscObjs->number];
2102
2103	    ret->type = XPATH_STRING;
2104	    ret->stringval = xmlStrdup(BAD_CAST val);
2105#ifdef XP_DEBUG_OBJ_USAGE
2106	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2107#endif
2108	    return(ret);
2109	}
2110    }
2111    return(xmlXPathNewCString(val));
2112}
2113
2114/**
2115 * xmlXPathCacheNewString:
2116 * @ctxt: the XPath context
2117 * @val:  the xmlChar * value
2118 *
2119 * This is the cached version of xmlXPathNewString().
2120 * Acquire an xmlXPathObjectPtr of type string and of value @val
2121 *
2122 * Returns the created or reused object.
2123 */
2124static xmlXPathObjectPtr
2125xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2126{
2127    if ((ctxt != NULL) && (ctxt->cache)) {
2128	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2129
2130	if ((cache->stringObjs != NULL) &&
2131	    (cache->stringObjs->number != 0))
2132	{
2133	    xmlXPathObjectPtr ret;
2134
2135	    ret = (xmlXPathObjectPtr)
2136		cache->stringObjs->items[--cache->stringObjs->number];
2137	    ret->type = XPATH_STRING;
2138	    if (val != NULL)
2139		ret->stringval = xmlStrdup(val);
2140	    else
2141		ret->stringval = xmlStrdup((const xmlChar *)"");
2142#ifdef XP_DEBUG_OBJ_USAGE
2143	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2144#endif
2145	    return(ret);
2146	} else if ((cache->miscObjs != NULL) &&
2147	    (cache->miscObjs->number != 0))
2148	{
2149	    xmlXPathObjectPtr ret;
2150
2151	    ret = (xmlXPathObjectPtr)
2152		cache->miscObjs->items[--cache->miscObjs->number];
2153
2154	    ret->type = XPATH_STRING;
2155	    if (val != NULL)
2156		ret->stringval = xmlStrdup(val);
2157	    else
2158		ret->stringval = xmlStrdup((const xmlChar *)"");
2159#ifdef XP_DEBUG_OBJ_USAGE
2160	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2161#endif
2162	    return(ret);
2163	}
2164    }
2165    return(xmlXPathNewString(val));
2166}
2167
2168/**
2169 * xmlXPathCacheNewBoolean:
2170 * @ctxt: the XPath context
2171 * @val:  the boolean value
2172 *
2173 * This is the cached version of xmlXPathNewBoolean().
2174 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2175 *
2176 * Returns the created or reused object.
2177 */
2178static xmlXPathObjectPtr
2179xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2180{
2181    if ((ctxt != NULL) && (ctxt->cache)) {
2182	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2183
2184	if ((cache->booleanObjs != NULL) &&
2185	    (cache->booleanObjs->number != 0))
2186	{
2187	    xmlXPathObjectPtr ret;
2188
2189	    ret = (xmlXPathObjectPtr)
2190		cache->booleanObjs->items[--cache->booleanObjs->number];
2191	    ret->type = XPATH_BOOLEAN;
2192	    ret->boolval = (val != 0);
2193#ifdef XP_DEBUG_OBJ_USAGE
2194	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2195#endif
2196	    return(ret);
2197	} else if ((cache->miscObjs != NULL) &&
2198	    (cache->miscObjs->number != 0))
2199	{
2200	    xmlXPathObjectPtr ret;
2201
2202	    ret = (xmlXPathObjectPtr)
2203		cache->miscObjs->items[--cache->miscObjs->number];
2204
2205	    ret->type = XPATH_BOOLEAN;
2206	    ret->boolval = (val != 0);
2207#ifdef XP_DEBUG_OBJ_USAGE
2208	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2209#endif
2210	    return(ret);
2211	}
2212    }
2213    return(xmlXPathNewBoolean(val));
2214}
2215
2216/**
2217 * xmlXPathCacheNewFloat:
2218 * @ctxt: the XPath context
2219 * @val:  the double value
2220 *
2221 * This is the cached version of xmlXPathNewFloat().
2222 * Acquires an xmlXPathObjectPtr of type double and of value @val
2223 *
2224 * Returns the created or reused object.
2225 */
2226static xmlXPathObjectPtr
2227xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2228{
2229     if ((ctxt != NULL) && (ctxt->cache)) {
2230	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2231
2232	if ((cache->numberObjs != NULL) &&
2233	    (cache->numberObjs->number != 0))
2234	{
2235	    xmlXPathObjectPtr ret;
2236
2237	    ret = (xmlXPathObjectPtr)
2238		cache->numberObjs->items[--cache->numberObjs->number];
2239	    ret->type = XPATH_NUMBER;
2240	    ret->floatval = val;
2241#ifdef XP_DEBUG_OBJ_USAGE
2242	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2243#endif
2244	    return(ret);
2245	} else if ((cache->miscObjs != NULL) &&
2246	    (cache->miscObjs->number != 0))
2247	{
2248	    xmlXPathObjectPtr ret;
2249
2250	    ret = (xmlXPathObjectPtr)
2251		cache->miscObjs->items[--cache->miscObjs->number];
2252
2253	    ret->type = XPATH_NUMBER;
2254	    ret->floatval = val;
2255#ifdef XP_DEBUG_OBJ_USAGE
2256	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2257#endif
2258	    return(ret);
2259	}
2260    }
2261    return(xmlXPathNewFloat(val));
2262}
2263
2264/**
2265 * xmlXPathCacheConvertString:
2266 * @ctxt: the XPath context
2267 * @val:  an XPath object
2268 *
2269 * This is the cached version of xmlXPathConvertString().
2270 * Converts an existing object to its string() equivalent
2271 *
2272 * Returns a created or reused object, the old one is freed (cached)
2273 *         (or the operation is done directly on @val)
2274 */
2275
2276static xmlXPathObjectPtr
2277xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2278    xmlChar *res = NULL;
2279
2280    if (val == NULL)
2281	return(xmlXPathCacheNewCString(ctxt, ""));
2282
2283    switch (val->type) {
2284    case XPATH_UNDEFINED:
2285#ifdef DEBUG_EXPR
2286	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2287#endif
2288	break;
2289    case XPATH_NODESET:
2290    case XPATH_XSLT_TREE:
2291	res = xmlXPathCastNodeSetToString(val->nodesetval);
2292	break;
2293    case XPATH_STRING:
2294	return(val);
2295    case XPATH_BOOLEAN:
2296	res = xmlXPathCastBooleanToString(val->boolval);
2297	break;
2298    case XPATH_NUMBER:
2299	res = xmlXPathCastNumberToString(val->floatval);
2300	break;
2301    case XPATH_USERS:
2302    case XPATH_POINT:
2303    case XPATH_RANGE:
2304    case XPATH_LOCATIONSET:
2305	TODO;
2306	break;
2307    }
2308    xmlXPathReleaseObject(ctxt, val);
2309    if (res == NULL)
2310	return(xmlXPathCacheNewCString(ctxt, ""));
2311    return(xmlXPathCacheWrapString(ctxt, res));
2312}
2313
2314/**
2315 * xmlXPathCacheObjectCopy:
2316 * @ctxt: the XPath context
2317 * @val:  the original object
2318 *
2319 * This is the cached version of xmlXPathObjectCopy().
2320 * Acquire a copy of a given object
2321 *
2322 * Returns a created or reused created object.
2323 */
2324static xmlXPathObjectPtr
2325xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2326{
2327    if (val == NULL)
2328	return(NULL);
2329
2330    switch (val->type) {
2331	case XPATH_NODESET:
2332	    if (XP_HAS_CACHE(ctxt))
2333		return(xmlXPathCacheWrapNodeSet(ctxt,
2334		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2335	case XPATH_STRING:
2336	    if (XP_HAS_CACHE(ctxt))
2337		return(xmlXPathCacheNewString(ctxt, val->stringval));
2338	case XPATH_BOOLEAN:
2339	    if (XP_HAS_CACHE(ctxt))
2340		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2341	case XPATH_NUMBER:
2342	    if (XP_HAS_CACHE(ctxt))
2343		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2344	default:
2345	    break;
2346    }
2347    return(xmlXPathObjectCopy(val));
2348}
2349
2350/**
2351 * xmlXPathCacheConvertBoolean:
2352 * @ctxt: the XPath context
2353 * @val:  an XPath object
2354 *
2355 * This is the cached version of xmlXPathConvertBoolean().
2356 * Converts an existing object to its boolean() equivalent
2357 *
2358 * Returns a created or reused object, the old one is freed (or the operation
2359 *         is done directly on @val)
2360 */
2361static xmlXPathObjectPtr
2362xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2363    xmlXPathObjectPtr ret;
2364
2365    if (val == NULL)
2366	return(xmlXPathCacheNewBoolean(ctxt, 0));
2367    if (val->type == XPATH_BOOLEAN)
2368	return(val);
2369    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2370    xmlXPathReleaseObject(ctxt, val);
2371    return(ret);
2372}
2373
2374/**
2375 * xmlXPathCacheConvertNumber:
2376 * @ctxt: the XPath context
2377 * @val:  an XPath object
2378 *
2379 * This is the cached version of xmlXPathConvertNumber().
2380 * Converts an existing object to its number() equivalent
2381 *
2382 * Returns a created or reused object, the old one is freed (or the operation
2383 *         is done directly on @val)
2384 */
2385static xmlXPathObjectPtr
2386xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2387    xmlXPathObjectPtr ret;
2388
2389    if (val == NULL)
2390	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2391    if (val->type == XPATH_NUMBER)
2392	return(val);
2393    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2394    xmlXPathReleaseObject(ctxt, val);
2395    return(ret);
2396}
2397
2398/************************************************************************
2399 *									*
2400 * 		Parser stacks related functions and macros		*
2401 *									*
2402 ************************************************************************/
2403
2404/**
2405 * valuePop:
2406 * @ctxt: an XPath evaluation context
2407 *
2408 * Pops the top XPath object from the value stack
2409 *
2410 * Returns the XPath object just removed
2411 */
2412xmlXPathObjectPtr
2413valuePop(xmlXPathParserContextPtr ctxt)
2414{
2415    xmlXPathObjectPtr ret;
2416
2417    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2418        return (NULL);
2419    ctxt->valueNr--;
2420    if (ctxt->valueNr > 0)
2421        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2422    else
2423        ctxt->value = NULL;
2424    ret = ctxt->valueTab[ctxt->valueNr];
2425    ctxt->valueTab[ctxt->valueNr] = NULL;
2426    return (ret);
2427}
2428/**
2429 * valuePush:
2430 * @ctxt:  an XPath evaluation context
2431 * @value:  the XPath object
2432 *
2433 * Pushes a new XPath object on top of the value stack
2434 *
2435 * returns the number of items on the value stack
2436 */
2437int
2438valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2439{
2440    if ((ctxt == NULL) || (value == NULL)) return(-1);
2441    if (ctxt->valueNr >= ctxt->valueMax) {
2442        xmlXPathObjectPtr *tmp;
2443
2444        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2445                                             2 * ctxt->valueMax *
2446                                             sizeof(ctxt->valueTab[0]));
2447        if (tmp == NULL) {
2448            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2449            return (0);
2450        }
2451        ctxt->valueMax *= 2;
2452	ctxt->valueTab = tmp;
2453    }
2454    ctxt->valueTab[ctxt->valueNr] = value;
2455    ctxt->value = value;
2456    return (ctxt->valueNr++);
2457}
2458
2459/**
2460 * xmlXPathPopBoolean:
2461 * @ctxt:  an XPath parser context
2462 *
2463 * Pops a boolean from the stack, handling conversion if needed.
2464 * Check error with #xmlXPathCheckError.
2465 *
2466 * Returns the boolean
2467 */
2468int
2469xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2470    xmlXPathObjectPtr obj;
2471    int ret;
2472
2473    obj = valuePop(ctxt);
2474    if (obj == NULL) {
2475	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2476	return(0);
2477    }
2478    if (obj->type != XPATH_BOOLEAN)
2479	ret = xmlXPathCastToBoolean(obj);
2480    else
2481        ret = obj->boolval;
2482    xmlXPathReleaseObject(ctxt->context, obj);
2483    return(ret);
2484}
2485
2486/**
2487 * xmlXPathPopNumber:
2488 * @ctxt:  an XPath parser context
2489 *
2490 * Pops a number from the stack, handling conversion if needed.
2491 * Check error with #xmlXPathCheckError.
2492 *
2493 * Returns the number
2494 */
2495double
2496xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2497    xmlXPathObjectPtr obj;
2498    double ret;
2499
2500    obj = valuePop(ctxt);
2501    if (obj == NULL) {
2502	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2503	return(0);
2504    }
2505    if (obj->type != XPATH_NUMBER)
2506	ret = xmlXPathCastToNumber(obj);
2507    else
2508        ret = obj->floatval;
2509    xmlXPathReleaseObject(ctxt->context, obj);
2510    return(ret);
2511}
2512
2513/**
2514 * xmlXPathPopString:
2515 * @ctxt:  an XPath parser context
2516 *
2517 * Pops a string from the stack, handling conversion if needed.
2518 * Check error with #xmlXPathCheckError.
2519 *
2520 * Returns the string
2521 */
2522xmlChar *
2523xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2524    xmlXPathObjectPtr obj;
2525    xmlChar * ret;
2526
2527    obj = valuePop(ctxt);
2528    if (obj == NULL) {
2529	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2530	return(NULL);
2531    }
2532    ret = xmlXPathCastToString(obj);	/* this does required strdup */
2533    /* TODO: needs refactoring somewhere else */
2534    if (obj->stringval == ret)
2535	obj->stringval = NULL;
2536    xmlXPathReleaseObject(ctxt->context, obj);
2537    return(ret);
2538}
2539
2540/**
2541 * xmlXPathPopNodeSet:
2542 * @ctxt:  an XPath parser context
2543 *
2544 * Pops a node-set from the stack, handling conversion if needed.
2545 * Check error with #xmlXPathCheckError.
2546 *
2547 * Returns the node-set
2548 */
2549xmlNodeSetPtr
2550xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2551    xmlXPathObjectPtr obj;
2552    xmlNodeSetPtr ret;
2553
2554    if (ctxt == NULL) return(NULL);
2555    if (ctxt->value == NULL) {
2556	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2557	return(NULL);
2558    }
2559    if (!xmlXPathStackIsNodeSet(ctxt)) {
2560	xmlXPathSetTypeError(ctxt);
2561	return(NULL);
2562    }
2563    obj = valuePop(ctxt);
2564    ret = obj->nodesetval;
2565#if 0
2566    /* to fix memory leak of not clearing obj->user */
2567    if (obj->boolval && obj->user != NULL)
2568        xmlFreeNodeList((xmlNodePtr) obj->user);
2569#endif
2570    obj->nodesetval = NULL;
2571    xmlXPathReleaseObject(ctxt->context, obj);
2572    return(ret);
2573}
2574
2575/**
2576 * xmlXPathPopExternal:
2577 * @ctxt:  an XPath parser context
2578 *
2579 * Pops an external object from the stack, handling conversion if needed.
2580 * Check error with #xmlXPathCheckError.
2581 *
2582 * Returns the object
2583 */
2584void *
2585xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2586    xmlXPathObjectPtr obj;
2587    void * ret;
2588
2589    if ((ctxt == NULL) || (ctxt->value == NULL)) {
2590	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2591	return(NULL);
2592    }
2593    if (ctxt->value->type != XPATH_USERS) {
2594	xmlXPathSetTypeError(ctxt);
2595	return(NULL);
2596    }
2597    obj = valuePop(ctxt);
2598    ret = obj->user;
2599    obj->user = NULL;
2600    xmlXPathReleaseObject(ctxt->context, obj);
2601    return(ret);
2602}
2603
2604/*
2605 * Macros for accessing the content. Those should be used only by the parser,
2606 * and not exported.
2607 *
2608 * Dirty macros, i.e. one need to make assumption on the context to use them
2609 *
2610 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2611 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2612 *           in ISO-Latin or UTF-8.
2613 *           This should be used internally by the parser
2614 *           only to compare to ASCII values otherwise it would break when
2615 *           running with UTF-8 encoding.
2616 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2617 *           to compare on ASCII based substring.
2618 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2619 *           strings within the parser.
2620 *   CURRENT Returns the current char value, with the full decoding of
2621 *           UTF-8 if we are using this mode. It returns an int.
2622 *   NEXT    Skip to the next character, this does the proper decoding
2623 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2624 *           It returns the pointer to the current xmlChar.
2625 */
2626
2627#define CUR (*ctxt->cur)
2628#define SKIP(val) ctxt->cur += (val)
2629#define NXT(val) ctxt->cur[(val)]
2630#define CUR_PTR ctxt->cur
2631#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2632
2633#define COPY_BUF(l,b,i,v)                                              \
2634    if (l == 1) b[i++] = (xmlChar) v;                                  \
2635    else i += xmlCopyChar(l,&b[i],v)
2636
2637#define NEXTL(l)  ctxt->cur += l
2638
2639#define SKIP_BLANKS 							\
2640    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2641
2642#define CURRENT (*ctxt->cur)
2643#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2644
2645
2646#ifndef DBL_DIG
2647#define DBL_DIG 16
2648#endif
2649#ifndef DBL_EPSILON
2650#define DBL_EPSILON 1E-9
2651#endif
2652
2653#define UPPER_DOUBLE 1E9
2654#define LOWER_DOUBLE 1E-5
2655
2656#define INTEGER_DIGITS DBL_DIG
2657#define FRACTION_DIGITS (DBL_DIG + 1)
2658#define EXPONENT_DIGITS (3 + 2)
2659
2660/**
2661 * xmlXPathFormatNumber:
2662 * @number:     number to format
2663 * @buffer:     output buffer
2664 * @buffersize: size of output buffer
2665 *
2666 * Convert the number into a string representation.
2667 */
2668static void
2669xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2670{
2671    switch (xmlXPathIsInf(number)) {
2672    case 1:
2673	if (buffersize > (int)sizeof("Infinity"))
2674	    snprintf(buffer, buffersize, "Infinity");
2675	break;
2676    case -1:
2677	if (buffersize > (int)sizeof("-Infinity"))
2678	    snprintf(buffer, buffersize, "-Infinity");
2679	break;
2680    default:
2681	if (xmlXPathIsNaN(number)) {
2682	    if (buffersize > (int)sizeof("NaN"))
2683		snprintf(buffer, buffersize, "NaN");
2684	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
2685	    snprintf(buffer, buffersize, "0");
2686	} else if (number == ((int) number)) {
2687	    char work[30];
2688	    char *ptr, *cur;
2689	    int value = (int) number;
2690
2691            ptr = &buffer[0];
2692	    if (value == 0) {
2693		*ptr++ = '0';
2694	    } else {
2695		snprintf(work, 29, "%d", value);
2696		cur = &work[0];
2697		while ((*cur) && (ptr - buffer < buffersize)) {
2698		    *ptr++ = *cur++;
2699		}
2700	    }
2701	    if (ptr - buffer < buffersize) {
2702		*ptr = 0;
2703	    } else if (buffersize > 0) {
2704		ptr--;
2705		*ptr = 0;
2706	    }
2707	} else {
2708	    /* 3 is sign, decimal point, and terminating zero */
2709	    char work[DBL_DIG + EXPONENT_DIGITS + 3];
2710	    int integer_place, fraction_place;
2711	    char *ptr;
2712	    char *after_fraction;
2713	    double absolute_value;
2714	    int size;
2715
2716	    absolute_value = fabs(number);
2717
2718	    /*
2719	     * First choose format - scientific or regular floating point.
2720	     * In either case, result is in work, and after_fraction points
2721	     * just past the fractional part.
2722	    */
2723	    if ( ((absolute_value > UPPER_DOUBLE) ||
2724		  (absolute_value < LOWER_DOUBLE)) &&
2725		 (absolute_value != 0.0) ) {
2726		/* Use scientific notation */
2727		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2728		fraction_place = DBL_DIG - 1;
2729		size = snprintf(work, sizeof(work),"%*.*e",
2730			 integer_place, fraction_place, number);
2731		while ((size > 0) && (work[size] != 'e')) size--;
2732		after_fraction = work + size;
2733
2734	    }
2735	    else {
2736		/* Use regular notation */
2737		if (absolute_value > 0.0)
2738		    integer_place = 1 + (int)log10(absolute_value);
2739		else
2740		    integer_place = 0;
2741		fraction_place = (integer_place > 0)
2742		    ? DBL_DIG - integer_place
2743		    : DBL_DIG;
2744		size = snprintf(work, sizeof(work), "%0.*f",
2745				fraction_place, number);
2746		after_fraction = work + size;
2747	    }
2748
2749	    /* Remove fractional trailing zeroes */
2750	    ptr = after_fraction;
2751	    while (*(--ptr) == '0')
2752		;
2753	    if (*ptr != '.')
2754	        ptr++;
2755	    while ((*ptr++ = *after_fraction++) != 0);
2756
2757	    /* Finally copy result back to caller */
2758	    size = strlen(work) + 1;
2759	    if (size > buffersize) {
2760		work[buffersize - 1] = 0;
2761		size = buffersize;
2762	    }
2763	    memmove(buffer, work, size);
2764	}
2765	break;
2766    }
2767}
2768
2769
2770/************************************************************************
2771 *									*
2772 *			Routines to handle NodeSets			*
2773 *									*
2774 ************************************************************************/
2775
2776/**
2777 * xmlXPathOrderDocElems:
2778 * @doc:  an input document
2779 *
2780 * Call this routine to speed up XPath computation on static documents.
2781 * This stamps all the element nodes with the document order
2782 * Like for line information, the order is kept in the element->content
2783 * field, the value stored is actually - the node number (starting at -1)
2784 * to be able to differentiate from line numbers.
2785 *
2786 * Returns the number of elements found in the document or -1 in case
2787 *    of error.
2788 */
2789long
2790xmlXPathOrderDocElems(xmlDocPtr doc) {
2791    long count = 0;
2792    xmlNodePtr cur;
2793
2794    if (doc == NULL)
2795	return(-1);
2796    cur = doc->children;
2797    while (cur != NULL) {
2798	if (cur->type == XML_ELEMENT_NODE) {
2799	    cur->content = (void *) (-(++count));
2800	    if (cur->children != NULL) {
2801		cur = cur->children;
2802		continue;
2803	    }
2804	}
2805	if (cur->next != NULL) {
2806	    cur = cur->next;
2807	    continue;
2808	}
2809	do {
2810	    cur = cur->parent;
2811	    if (cur == NULL)
2812		break;
2813	    if (cur == (xmlNodePtr) doc) {
2814		cur = NULL;
2815		break;
2816	    }
2817	    if (cur->next != NULL) {
2818		cur = cur->next;
2819		break;
2820	    }
2821	} while (cur != NULL);
2822    }
2823    return(count);
2824}
2825
2826/**
2827 * xmlXPathCmpNodes:
2828 * @node1:  the first node
2829 * @node2:  the second node
2830 *
2831 * Compare two nodes w.r.t document order
2832 *
2833 * Returns -2 in case of error 1 if first point < second point, 0 if
2834 *         it's the same node, -1 otherwise
2835 */
2836int
2837xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2838    int depth1, depth2;
2839    int attr1 = 0, attr2 = 0;
2840    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2841    xmlNodePtr cur, root;
2842
2843    if ((node1 == NULL) || (node2 == NULL))
2844	return(-2);
2845    /*
2846     * a couple of optimizations which will avoid computations in most cases
2847     */
2848    if (node1->type == XML_ATTRIBUTE_NODE) {
2849	attr1 = 1;
2850	attrNode1 = node1;
2851	node1 = node1->parent;
2852    }
2853    if (node2->type == XML_ATTRIBUTE_NODE) {
2854	attr2 = 1;
2855	attrNode2 = node2;
2856	node2 = node2->parent;
2857    }
2858    if (node1 == node2) {
2859	if (attr1 == attr2) {
2860	    /* not required, but we keep attributes in order */
2861	    if (attr1 != 0) {
2862	        cur = attrNode2->prev;
2863		while (cur != NULL) {
2864		    if (cur == attrNode1)
2865		        return (1);
2866		    cur = cur->prev;
2867		}
2868		return (-1);
2869	    }
2870	    return(0);
2871	}
2872	if (attr2 == 1)
2873	    return(1);
2874	return(-1);
2875    }
2876    if ((node1->type == XML_NAMESPACE_DECL) ||
2877        (node2->type == XML_NAMESPACE_DECL))
2878	return(1);
2879    if (node1 == node2->prev)
2880	return(1);
2881    if (node1 == node2->next)
2882	return(-1);
2883
2884    /*
2885     * Speedup using document order if availble.
2886     */
2887    if ((node1->type == XML_ELEMENT_NODE) &&
2888	(node2->type == XML_ELEMENT_NODE) &&
2889	(0 > (long) node1->content) &&
2890	(0 > (long) node2->content) &&
2891	(node1->doc == node2->doc)) {
2892	long l1, l2;
2893
2894	l1 = -((long) node1->content);
2895	l2 = -((long) node2->content);
2896	if (l1 < l2)
2897	    return(1);
2898	if (l1 > l2)
2899	    return(-1);
2900    }
2901
2902    /*
2903     * compute depth to root
2904     */
2905    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2906	if (cur == node1)
2907	    return(1);
2908	depth2++;
2909    }
2910    root = cur;
2911    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2912	if (cur == node2)
2913	    return(-1);
2914	depth1++;
2915    }
2916    /*
2917     * Distinct document (or distinct entities :-( ) case.
2918     */
2919    if (root != cur) {
2920	return(-2);
2921    }
2922    /*
2923     * get the nearest common ancestor.
2924     */
2925    while (depth1 > depth2) {
2926	depth1--;
2927	node1 = node1->parent;
2928    }
2929    while (depth2 > depth1) {
2930	depth2--;
2931	node2 = node2->parent;
2932    }
2933    while (node1->parent != node2->parent) {
2934	node1 = node1->parent;
2935	node2 = node2->parent;
2936	/* should not happen but just in case ... */
2937	if ((node1 == NULL) || (node2 == NULL))
2938	    return(-2);
2939    }
2940    /*
2941     * Find who's first.
2942     */
2943    if (node1 == node2->prev)
2944	return(1);
2945    if (node1 == node2->next)
2946	return(-1);
2947    /*
2948     * Speedup using document order if availble.
2949     */
2950    if ((node1->type == XML_ELEMENT_NODE) &&
2951	(node2->type == XML_ELEMENT_NODE) &&
2952	(0 > (long) node1->content) &&
2953	(0 > (long) node2->content) &&
2954	(node1->doc == node2->doc)) {
2955	long l1, l2;
2956
2957	l1 = -((long) node1->content);
2958	l2 = -((long) node2->content);
2959	if (l1 < l2)
2960	    return(1);
2961	if (l1 > l2)
2962	    return(-1);
2963    }
2964
2965    for (cur = node1->next;cur != NULL;cur = cur->next)
2966	if (cur == node2)
2967	    return(1);
2968    return(-1); /* assume there is no sibling list corruption */
2969}
2970
2971#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2972/**
2973 * xmlXPathCmpNodesExt:
2974 * @node1:  the first node
2975 * @node2:  the second node
2976 *
2977 * Compare two nodes w.r.t document order.
2978 * This one is optimized for handling of non-element nodes.
2979 *
2980 * Returns -2 in case of error 1 if first point < second point, 0 if
2981 *         it's the same node, -1 otherwise
2982 */
2983static int
2984xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2985    int depth1, depth2;
2986    int misc = 0, precedence1 = 0, precedence2 = 0;
2987    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2988    xmlNodePtr cur, root;
2989    long l1, l2;
2990
2991    if ((node1 == NULL) || (node2 == NULL))
2992	return(-2);
2993
2994    if (node1 == node2)
2995	return(0);
2996
2997    /*
2998     * a couple of optimizations which will avoid computations in most cases
2999     */
3000    switch (node1->type) {
3001	case XML_ELEMENT_NODE:
3002	    if (node2->type == XML_ELEMENT_NODE) {
3003		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3004		    (0 > (long) node2->content) &&
3005		    (node1->doc == node2->doc))
3006		{
3007		    l1 = -((long) node1->content);
3008		    l2 = -((long) node2->content);
3009		    if (l1 < l2)
3010			return(1);
3011		    if (l1 > l2)
3012			return(-1);
3013		} else
3014		    goto turtle_comparison;
3015	    }
3016	    break;
3017	case XML_ATTRIBUTE_NODE:
3018	    precedence1 = 1; /* element is owner */
3019	    miscNode1 = node1;
3020	    node1 = node1->parent;
3021	    misc = 1;
3022	    break;
3023	case XML_TEXT_NODE:
3024	case XML_CDATA_SECTION_NODE:
3025	case XML_COMMENT_NODE:
3026	case XML_PI_NODE: {
3027	    miscNode1 = node1;
3028	    /*
3029	    * Find nearest element node.
3030	    */
3031	    if (node1->prev != NULL) {
3032		do {
3033		    node1 = node1->prev;
3034		    if (node1->type == XML_ELEMENT_NODE) {
3035			precedence1 = 3; /* element in prev-sibl axis */
3036			break;
3037		    }
3038		    if (node1->prev == NULL) {
3039			precedence1 = 2; /* element is parent */
3040			/*
3041			* URGENT TODO: Are there any cases, where the
3042			* parent of such a node is not an element node?
3043			*/
3044			node1 = node1->parent;
3045			break;
3046		    }
3047		} while (1);
3048	    } else {
3049		precedence1 = 2; /* element is parent */
3050		node1 = node1->parent;
3051	    }
3052	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
3053		/*
3054		* Fallback for whatever case.
3055		*/
3056		node1 = miscNode1;
3057		precedence1 = 0;
3058	    } else
3059		misc = 1;
3060	}
3061	    break;
3062	case XML_NAMESPACE_DECL:
3063	    /*
3064	    * TODO: why do we return 1 for namespace nodes?
3065	    */
3066	    return(1);
3067	default:
3068	    break;
3069    }
3070    switch (node2->type) {
3071	case XML_ELEMENT_NODE:
3072	    break;
3073	case XML_ATTRIBUTE_NODE:
3074	    precedence2 = 1; /* element is owner */
3075	    miscNode2 = node2;
3076	    node2 = node2->parent;
3077	    misc = 1;
3078	    break;
3079	case XML_TEXT_NODE:
3080	case XML_CDATA_SECTION_NODE:
3081	case XML_COMMENT_NODE:
3082	case XML_PI_NODE: {
3083	    miscNode2 = node2;
3084	    if (node2->prev != NULL) {
3085		do {
3086		    node2 = node2->prev;
3087		    if (node2->type == XML_ELEMENT_NODE) {
3088			precedence2 = 3; /* element in prev-sibl axis */
3089			break;
3090		    }
3091		    if (node2->prev == NULL) {
3092			precedence2 = 2; /* element is parent */
3093			node2 = node2->parent;
3094			break;
3095		    }
3096		} while (1);
3097	    } else {
3098		precedence2 = 2; /* element is parent */
3099		node2 = node2->parent;
3100	    }
3101	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3102		(0 <= (long) node1->content))
3103	    {
3104		node2 = miscNode2;
3105		precedence2 = 0;
3106	    } else
3107		misc = 1;
3108	}
3109	    break;
3110	case XML_NAMESPACE_DECL:
3111	    return(1);
3112	default:
3113	    break;
3114    }
3115    if (misc) {
3116	if (node1 == node2) {
3117	    if (precedence1 == precedence2) {
3118		/*
3119		* The ugly case; but normally there aren't many
3120		* adjacent non-element nodes around.
3121		*/
3122		cur = miscNode2->prev;
3123		while (cur != NULL) {
3124		    if (cur == miscNode1)
3125			return(1);
3126		    if (cur->type == XML_ELEMENT_NODE)
3127			return(-1);
3128		    cur = cur->prev;
3129		}
3130		return (-1);
3131	    } else {
3132		/*
3133		* Evaluate based on higher precedence wrt to the element.
3134		* TODO: This assumes attributes are sorted before content.
3135		*   Is this 100% correct?
3136		*/
3137		if (precedence1 < precedence2)
3138		    return(1);
3139		else
3140		    return(-1);
3141	    }
3142	}
3143	/*
3144	* Special case: One of the helper-elements is contained by the other.
3145	* <foo>
3146	*   <node2>
3147	*     <node1>Text-1(precedence1 == 2)</node1>
3148	*   </node2>
3149	*   Text-6(precedence2 == 3)
3150	* </foo>
3151	*/
3152	if ((precedence2 == 3) && (precedence1 > 1)) {
3153	    cur = node1->parent;
3154	    while (cur) {
3155		if (cur == node2)
3156		    return(1);
3157		cur = cur->parent;
3158	    }
3159	}
3160	if ((precedence1 == 3) && (precedence2 > 1)) {
3161	    cur = node2->parent;
3162	    while (cur) {
3163		if (cur == node1)
3164		    return(-1);
3165		cur = cur->parent;
3166	    }
3167	}
3168    }
3169
3170    /*
3171     * Speedup using document order if availble.
3172     */
3173    if ((node1->type == XML_ELEMENT_NODE) &&
3174	(node2->type == XML_ELEMENT_NODE) &&
3175	(0 > (long) node1->content) &&
3176	(0 > (long) node2->content) &&
3177	(node1->doc == node2->doc)) {
3178
3179	l1 = -((long) node1->content);
3180	l2 = -((long) node2->content);
3181	if (l1 < l2)
3182	    return(1);
3183	if (l1 > l2)
3184	    return(-1);
3185    }
3186
3187turtle_comparison:
3188
3189    if (node1 == node2->prev)
3190	return(1);
3191    if (node1 == node2->next)
3192	return(-1);
3193    /*
3194     * compute depth to root
3195     */
3196    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3197	if (cur == node1)
3198	    return(1);
3199	depth2++;
3200    }
3201    root = cur;
3202    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3203	if (cur == node2)
3204	    return(-1);
3205	depth1++;
3206    }
3207    /*
3208     * Distinct document (or distinct entities :-( ) case.
3209     */
3210    if (root != cur) {
3211	return(-2);
3212    }
3213    /*
3214     * get the nearest common ancestor.
3215     */
3216    while (depth1 > depth2) {
3217	depth1--;
3218	node1 = node1->parent;
3219    }
3220    while (depth2 > depth1) {
3221	depth2--;
3222	node2 = node2->parent;
3223    }
3224    while (node1->parent != node2->parent) {
3225	node1 = node1->parent;
3226	node2 = node2->parent;
3227	/* should not happen but just in case ... */
3228	if ((node1 == NULL) || (node2 == NULL))
3229	    return(-2);
3230    }
3231    /*
3232     * Find who's first.
3233     */
3234    if (node1 == node2->prev)
3235	return(1);
3236    if (node1 == node2->next)
3237	return(-1);
3238    /*
3239     * Speedup using document order if availble.
3240     */
3241    if ((node1->type == XML_ELEMENT_NODE) &&
3242	(node2->type == XML_ELEMENT_NODE) &&
3243	(0 > (long) node1->content) &&
3244	(0 > (long) node2->content) &&
3245	(node1->doc == node2->doc)) {
3246
3247	l1 = -((long) node1->content);
3248	l2 = -((long) node2->content);
3249	if (l1 < l2)
3250	    return(1);
3251	if (l1 > l2)
3252	    return(-1);
3253    }
3254
3255    for (cur = node1->next;cur != NULL;cur = cur->next)
3256	if (cur == node2)
3257	    return(1);
3258    return(-1); /* assume there is no sibling list corruption */
3259}
3260#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3261
3262/**
3263 * xmlXPathNodeSetSort:
3264 * @set:  the node set
3265 *
3266 * Sort the node set in document order
3267 */
3268void
3269xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3270    int i, j, incr, len;
3271    xmlNodePtr tmp;
3272
3273    if (set == NULL)
3274	return;
3275
3276    /* Use Shell's sort to sort the node-set */
3277    len = set->nodeNr;
3278    for (incr = len / 2; incr > 0; incr /= 2) {
3279	for (i = incr; i < len; i++) {
3280	    j = i - incr;
3281	    while (j >= 0) {
3282#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3283		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3284			set->nodeTab[j + incr]) == -1)
3285#else
3286		if (xmlXPathCmpNodes(set->nodeTab[j],
3287			set->nodeTab[j + incr]) == -1)
3288#endif
3289		{
3290		    tmp = set->nodeTab[j];
3291		    set->nodeTab[j] = set->nodeTab[j + incr];
3292		    set->nodeTab[j + incr] = tmp;
3293		    j -= incr;
3294		} else
3295		    break;
3296	    }
3297	}
3298    }
3299}
3300
3301#define XML_NODESET_DEFAULT	10
3302/**
3303 * xmlXPathNodeSetDupNs:
3304 * @node:  the parent node of the namespace XPath node
3305 * @ns:  the libxml namespace declaration node.
3306 *
3307 * Namespace node in libxml don't match the XPath semantic. In a node set
3308 * the namespace nodes are duplicated and the next pointer is set to the
3309 * parent node in the XPath semantic.
3310 *
3311 * Returns the newly created object.
3312 */
3313static xmlNodePtr
3314xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3315    xmlNsPtr cur;
3316
3317    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3318	return(NULL);
3319    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3320	return((xmlNodePtr) ns);
3321
3322    /*
3323     * Allocate a new Namespace and fill the fields.
3324     */
3325    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3326    if (cur == NULL) {
3327        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3328	return(NULL);
3329    }
3330    memset(cur, 0, sizeof(xmlNs));
3331    cur->type = XML_NAMESPACE_DECL;
3332    if (ns->href != NULL)
3333	cur->href = xmlStrdup(ns->href);
3334    if (ns->prefix != NULL)
3335	cur->prefix = xmlStrdup(ns->prefix);
3336    cur->next = (xmlNsPtr) node;
3337    return((xmlNodePtr) cur);
3338}
3339
3340/**
3341 * xmlXPathNodeSetFreeNs:
3342 * @ns:  the XPath namespace node found in a nodeset.
3343 *
3344 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3345 * the namespace nodes are duplicated and the next pointer is set to the
3346 * parent node in the XPath semantic. Check if such a node needs to be freed
3347 */
3348void
3349xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3350    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3351	return;
3352
3353    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3354	if (ns->href != NULL)
3355	    xmlFree((xmlChar *)ns->href);
3356	if (ns->prefix != NULL)
3357	    xmlFree((xmlChar *)ns->prefix);
3358	xmlFree(ns);
3359    }
3360}
3361
3362/**
3363 * xmlXPathNodeSetCreate:
3364 * @val:  an initial xmlNodePtr, or NULL
3365 *
3366 * Create a new xmlNodeSetPtr of type double and of value @val
3367 *
3368 * Returns the newly created object.
3369 */
3370xmlNodeSetPtr
3371xmlXPathNodeSetCreate(xmlNodePtr val) {
3372    xmlNodeSetPtr ret;
3373
3374    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3375    if (ret == NULL) {
3376        xmlXPathErrMemory(NULL, "creating nodeset\n");
3377	return(NULL);
3378    }
3379    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3380    if (val != NULL) {
3381        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3382					     sizeof(xmlNodePtr));
3383	if (ret->nodeTab == NULL) {
3384	    xmlXPathErrMemory(NULL, "creating nodeset\n");
3385	    xmlFree(ret);
3386	    return(NULL);
3387	}
3388	memset(ret->nodeTab, 0 ,
3389	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3390        ret->nodeMax = XML_NODESET_DEFAULT;
3391	if (val->type == XML_NAMESPACE_DECL) {
3392	    xmlNsPtr ns = (xmlNsPtr) val;
3393
3394	    ret->nodeTab[ret->nodeNr++] =
3395		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3396	} else
3397	    ret->nodeTab[ret->nodeNr++] = val;
3398    }
3399    return(ret);
3400}
3401
3402/**
3403 * xmlXPathNodeSetContains:
3404 * @cur:  the node-set
3405 * @val:  the node
3406 *
3407 * checks whether @cur contains @val
3408 *
3409 * Returns true (1) if @cur contains @val, false (0) otherwise
3410 */
3411int
3412xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3413    int i;
3414
3415    if ((cur == NULL) || (val == NULL)) return(0);
3416    if (val->type == XML_NAMESPACE_DECL) {
3417	for (i = 0; i < cur->nodeNr; i++) {
3418	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3419		xmlNsPtr ns1, ns2;
3420
3421		ns1 = (xmlNsPtr) val;
3422		ns2 = (xmlNsPtr) cur->nodeTab[i];
3423		if (ns1 == ns2)
3424		    return(1);
3425		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3426	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3427		    return(1);
3428	    }
3429	}
3430    } else {
3431	for (i = 0; i < cur->nodeNr; i++) {
3432	    if (cur->nodeTab[i] == val)
3433		return(1);
3434	}
3435    }
3436    return(0);
3437}
3438
3439/**
3440 * xmlXPathNodeSetAddNs:
3441 * @cur:  the initial node set
3442 * @node:  the hosting node
3443 * @ns:  a the namespace node
3444 *
3445 * add a new namespace node to an existing NodeSet
3446 */
3447void
3448xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3449    int i;
3450
3451
3452    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3453        (ns->type != XML_NAMESPACE_DECL) ||
3454	(node->type != XML_ELEMENT_NODE))
3455	return;
3456
3457    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3458    /*
3459     * prevent duplicates
3460     */
3461    for (i = 0;i < cur->nodeNr;i++) {
3462        if ((cur->nodeTab[i] != NULL) &&
3463	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3464	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3465	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3466	    return;
3467    }
3468
3469    /*
3470     * grow the nodeTab if needed
3471     */
3472    if (cur->nodeMax == 0) {
3473        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3474					     sizeof(xmlNodePtr));
3475	if (cur->nodeTab == NULL) {
3476	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3477	    return;
3478	}
3479	memset(cur->nodeTab, 0 ,
3480	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3481        cur->nodeMax = XML_NODESET_DEFAULT;
3482    } else if (cur->nodeNr == cur->nodeMax) {
3483        xmlNodePtr *temp;
3484
3485        cur->nodeMax *= 2;
3486	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3487				      sizeof(xmlNodePtr));
3488	if (temp == NULL) {
3489	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3490	    return;
3491	}
3492	cur->nodeTab = temp;
3493    }
3494    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3495}
3496
3497/**
3498 * xmlXPathNodeSetAdd:
3499 * @cur:  the initial node set
3500 * @val:  a new xmlNodePtr
3501 *
3502 * add a new xmlNodePtr to an existing NodeSet
3503 */
3504void
3505xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3506    int i;
3507
3508    if ((cur == NULL) || (val == NULL)) return;
3509
3510#if 0
3511    if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3512	return;	/* an XSLT fake node */
3513#endif
3514
3515    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3516    /*
3517     * prevent duplcates
3518     */
3519    for (i = 0;i < cur->nodeNr;i++)
3520        if (cur->nodeTab[i] == val) return;
3521
3522    /*
3523     * grow the nodeTab if needed
3524     */
3525    if (cur->nodeMax == 0) {
3526        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3527					     sizeof(xmlNodePtr));
3528	if (cur->nodeTab == NULL) {
3529	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3530	    return;
3531	}
3532	memset(cur->nodeTab, 0 ,
3533	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3534        cur->nodeMax = XML_NODESET_DEFAULT;
3535    } else if (cur->nodeNr == cur->nodeMax) {
3536        xmlNodePtr *temp;
3537
3538        cur->nodeMax *= 2;
3539	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3540				      sizeof(xmlNodePtr));
3541	if (temp == NULL) {
3542	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3543	    return;
3544	}
3545	cur->nodeTab = temp;
3546    }
3547    if (val->type == XML_NAMESPACE_DECL) {
3548	xmlNsPtr ns = (xmlNsPtr) val;
3549
3550	cur->nodeTab[cur->nodeNr++] =
3551	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3552    } else
3553	cur->nodeTab[cur->nodeNr++] = val;
3554}
3555
3556/**
3557 * xmlXPathNodeSetAddUnique:
3558 * @cur:  the initial node set
3559 * @val:  a new xmlNodePtr
3560 *
3561 * add a new xmlNodePtr to an existing NodeSet, optimized version
3562 * when we are sure the node is not already in the set.
3563 */
3564void
3565xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3566    if ((cur == NULL) || (val == NULL)) return;
3567
3568#if 0
3569    if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3570	return;	/* an XSLT fake node */
3571#endif
3572
3573    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3574    /*
3575     * grow the nodeTab if needed
3576     */
3577    if (cur->nodeMax == 0) {
3578        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3579					     sizeof(xmlNodePtr));
3580	if (cur->nodeTab == NULL) {
3581	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3582	    return;
3583	}
3584	memset(cur->nodeTab, 0 ,
3585	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3586        cur->nodeMax = XML_NODESET_DEFAULT;
3587    } else if (cur->nodeNr == cur->nodeMax) {
3588        xmlNodePtr *temp;
3589
3590        cur->nodeMax *= 2;
3591	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3592				      sizeof(xmlNodePtr));
3593	if (temp == NULL) {
3594	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3595	    return;
3596	}
3597	cur->nodeTab = temp;
3598    }
3599    if (val->type == XML_NAMESPACE_DECL) {
3600	xmlNsPtr ns = (xmlNsPtr) val;
3601
3602	cur->nodeTab[cur->nodeNr++] =
3603	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3604    } else
3605	cur->nodeTab[cur->nodeNr++] = val;
3606}
3607
3608/**
3609 * xmlXPathNodeSetMerge:
3610 * @val1:  the first NodeSet or NULL
3611 * @val2:  the second NodeSet
3612 *
3613 * Merges two nodesets, all nodes from @val2 are added to @val1
3614 * if @val1 is NULL, a new set is created and copied from @val2
3615 *
3616 * Returns @val1 once extended or NULL in case of error.
3617 */
3618xmlNodeSetPtr
3619xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3620    int i, j, initNr, skip;
3621    xmlNodePtr n1, n2;
3622
3623    if (val2 == NULL) return(val1);
3624    if (val1 == NULL) {
3625	val1 = xmlXPathNodeSetCreate(NULL);
3626#if 0
3627	/*
3628	* TODO: The optimization won't work in every case, since
3629	*  those nasty namespace nodes need to be added with
3630	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3631	*  memcpy is not possible.
3632	*  If there was a flag on the nodesetval, indicating that
3633	*  some temporary nodes are in, that would be helpfull.
3634	*/
3635	/*
3636	* Optimization: Create an equally sized node-set
3637	* and memcpy the content.
3638	*/
3639	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3640	if (val1 == NULL)
3641	    return(NULL);
3642	if (val2->nodeNr != 0) {
3643	    if (val2->nodeNr == 1)
3644		*(val1->nodeTab) = *(val2->nodeTab);
3645	    else {
3646		memcpy(val1->nodeTab, val2->nodeTab,
3647		    val2->nodeNr * sizeof(xmlNodePtr));
3648	    }
3649	    val1->nodeNr = val2->nodeNr;
3650	}
3651	return(val1);
3652#endif
3653    }
3654
3655    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3656    initNr = val1->nodeNr;
3657
3658    for (i = 0;i < val2->nodeNr;i++) {
3659	n2 = val2->nodeTab[i];
3660	/*
3661	 * check against duplicates
3662	 */
3663	skip = 0;
3664	for (j = 0; j < initNr; j++) {
3665	    n1 = val1->nodeTab[j];
3666	    if (n1 == n2) {
3667		skip = 1;
3668		break;
3669	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3670		       (n2->type == XML_NAMESPACE_DECL)) {
3671		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3672		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3673			((xmlNsPtr) n2)->prefix)))
3674		{
3675		    skip = 1;
3676		    break;
3677		}
3678	    }
3679	}
3680	if (skip)
3681	    continue;
3682
3683	/*
3684	 * grow the nodeTab if needed
3685	 */
3686	if (val1->nodeMax == 0) {
3687	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3688						    sizeof(xmlNodePtr));
3689	    if (val1->nodeTab == NULL) {
3690	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3691		return(NULL);
3692	    }
3693	    memset(val1->nodeTab, 0 ,
3694		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3695	    val1->nodeMax = XML_NODESET_DEFAULT;
3696	} else if (val1->nodeNr == val1->nodeMax) {
3697	    xmlNodePtr *temp;
3698
3699	    val1->nodeMax *= 2;
3700	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3701					     sizeof(xmlNodePtr));
3702	    if (temp == NULL) {
3703	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3704		return(NULL);
3705	    }
3706	    val1->nodeTab = temp;
3707	}
3708	if (n2->type == XML_NAMESPACE_DECL) {
3709	    xmlNsPtr ns = (xmlNsPtr) n2;
3710
3711	    val1->nodeTab[val1->nodeNr++] =
3712		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3713	} else
3714	    val1->nodeTab[val1->nodeNr++] = n2;
3715    }
3716
3717    return(val1);
3718}
3719
3720/**
3721 * xmlXPathNodeSetMergeUnique:
3722 * @val1:  the first NodeSet or NULL
3723 * @val2:  the second NodeSet
3724 *
3725 * Merges two nodesets, all nodes from @val2 are added to @val1
3726 * if @val1 is NULL, a new set is created and copied from @val2
3727 *
3728 * Returns @val1 once extended or NULL in case of error.
3729 */
3730static xmlNodeSetPtr
3731xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3732    int i;
3733
3734    if (val2 == NULL) return(val1);
3735    if (val1 == NULL) {
3736	val1 = xmlXPathNodeSetCreate(NULL);
3737    }
3738
3739    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3740
3741    for (i = 0;i < val2->nodeNr;i++) {
3742	/*
3743	 * grow the nodeTab if needed
3744	 */
3745	if (val1->nodeMax == 0) {
3746	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3747						    sizeof(xmlNodePtr));
3748	    if (val1->nodeTab == NULL) {
3749	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3750		return(NULL);
3751	    }
3752	    memset(val1->nodeTab, 0 ,
3753		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3754	    val1->nodeMax = XML_NODESET_DEFAULT;
3755	} else if (val1->nodeNr == val1->nodeMax) {
3756	    xmlNodePtr *temp;
3757
3758	    val1->nodeMax *= 2;
3759	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3760					     sizeof(xmlNodePtr));
3761	    if (temp == NULL) {
3762	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3763		return(NULL);
3764	    }
3765	    val1->nodeTab = temp;
3766	}
3767	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3768	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3769
3770	    val1->nodeTab[val1->nodeNr++] =
3771		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3772	} else
3773	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3774    }
3775
3776    return(val1);
3777}
3778
3779/**
3780 * xmlXPathNodeSetDel:
3781 * @cur:  the initial node set
3782 * @val:  an xmlNodePtr
3783 *
3784 * Removes an xmlNodePtr from an existing NodeSet
3785 */
3786void
3787xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3788    int i;
3789
3790    if (cur == NULL) return;
3791    if (val == NULL) return;
3792
3793    /*
3794     * find node in nodeTab
3795     */
3796    for (i = 0;i < cur->nodeNr;i++)
3797        if (cur->nodeTab[i] == val) break;
3798
3799    if (i >= cur->nodeNr) {	/* not found */
3800#ifdef DEBUG
3801        xmlGenericError(xmlGenericErrorContext,
3802	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
3803		val->name);
3804#endif
3805        return;
3806    }
3807    if ((cur->nodeTab[i] != NULL) &&
3808	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3809	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3810    cur->nodeNr--;
3811    for (;i < cur->nodeNr;i++)
3812        cur->nodeTab[i] = cur->nodeTab[i + 1];
3813    cur->nodeTab[cur->nodeNr] = NULL;
3814}
3815
3816/**
3817 * xmlXPathNodeSetRemove:
3818 * @cur:  the initial node set
3819 * @val:  the index to remove
3820 *
3821 * Removes an entry from an existing NodeSet list.
3822 */
3823void
3824xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3825    if (cur == NULL) return;
3826    if (val >= cur->nodeNr) return;
3827    if ((cur->nodeTab[val] != NULL) &&
3828	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3829	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3830    cur->nodeNr--;
3831    for (;val < cur->nodeNr;val++)
3832        cur->nodeTab[val] = cur->nodeTab[val + 1];
3833    cur->nodeTab[cur->nodeNr] = NULL;
3834}
3835
3836/**
3837 * xmlXPathFreeNodeSet:
3838 * @obj:  the xmlNodeSetPtr to free
3839 *
3840 * Free the NodeSet compound (not the actual nodes !).
3841 */
3842void
3843xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3844    if (obj == NULL) return;
3845    if (obj->nodeTab != NULL) {
3846	int i;
3847
3848	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
3849	for (i = 0;i < obj->nodeNr;i++)
3850	    if ((obj->nodeTab[i] != NULL) &&
3851		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3852		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3853	xmlFree(obj->nodeTab);
3854    }
3855    xmlFree(obj);
3856}
3857
3858/**
3859 * xmlXPathNodeSetClear:
3860 * @set:  the xmlNodeSetPtr to free
3861 *
3862 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3863 * are feed), but does *not* free the list itself. Sets the length of the
3864 * list to 0.
3865 */
3866static void
3867xmlXPathNodeSetClear(xmlNodeSetPtr set)
3868{
3869    int i;
3870    xmlNodePtr node;
3871
3872    if ((set == NULL) || (set->nodeNr <= 0))
3873	return;
3874
3875    for (i = 0; i < set->nodeNr; i++) {
3876	node = set->nodeTab[i];
3877	if ((node != NULL) &&
3878	    (node->type == XML_NAMESPACE_DECL))
3879	{
3880	    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3881	}
3882    }
3883    set->nodeNr = 0;
3884}
3885
3886/**
3887 * xmlXPathFreeValueTree:
3888 * @obj:  the xmlNodeSetPtr to free
3889 *
3890 * Free the NodeSet compound and the actual tree, this is different
3891 * from xmlXPathFreeNodeSet()
3892 */
3893static void
3894xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
3895    int i;
3896
3897    if (obj == NULL) return;
3898
3899    if (obj->nodeTab != NULL) {
3900	for (i = 0;i < obj->nodeNr;i++) {
3901	    if (obj->nodeTab[i] != NULL) {
3902		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3903		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3904		} else {
3905		    xmlFreeNodeList(obj->nodeTab[i]);
3906		}
3907	    }
3908	}
3909	xmlFree(obj->nodeTab);
3910    }
3911    xmlFree(obj);
3912}
3913
3914#if defined(DEBUG) || defined(DEBUG_STEP)
3915/**
3916 * xmlGenericErrorContextNodeSet:
3917 * @output:  a FILE * for the output
3918 * @obj:  the xmlNodeSetPtr to display
3919 *
3920 * Quick display of a NodeSet
3921 */
3922void
3923xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
3924    int i;
3925
3926    if (output == NULL) output = xmlGenericErrorContext;
3927    if (obj == NULL)  {
3928        fprintf(output, "NodeSet == NULL !\n");
3929	return;
3930    }
3931    if (obj->nodeNr == 0) {
3932        fprintf(output, "NodeSet is empty\n");
3933	return;
3934    }
3935    if (obj->nodeTab == NULL) {
3936	fprintf(output, " nodeTab == NULL !\n");
3937	return;
3938    }
3939    for (i = 0; i < obj->nodeNr; i++) {
3940        if (obj->nodeTab[i] == NULL) {
3941	    fprintf(output, " NULL !\n");
3942	    return;
3943        }
3944	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
3945	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
3946	    fprintf(output, " /");
3947	else if (obj->nodeTab[i]->name == NULL)
3948	    fprintf(output, " noname!");
3949	else fprintf(output, " %s", obj->nodeTab[i]->name);
3950    }
3951    fprintf(output, "\n");
3952}
3953#endif
3954
3955/**
3956 * xmlXPathNewNodeSet:
3957 * @val:  the NodePtr value
3958 *
3959 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3960 * it with the single Node @val
3961 *
3962 * Returns the newly created object.
3963 */
3964xmlXPathObjectPtr
3965xmlXPathNewNodeSet(xmlNodePtr val) {
3966    xmlXPathObjectPtr ret;
3967
3968    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3969    if (ret == NULL) {
3970        xmlXPathErrMemory(NULL, "creating nodeset\n");
3971	return(NULL);
3972    }
3973    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3974    ret->type = XPATH_NODESET;
3975    ret->boolval = 0;
3976    ret->nodesetval = xmlXPathNodeSetCreate(val);
3977    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3978#ifdef XP_DEBUG_OBJ_USAGE
3979    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
3980#endif
3981    return(ret);
3982}
3983
3984/**
3985 * xmlXPathNewValueTree:
3986 * @val:  the NodePtr value
3987 *
3988 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
3989 * it with the tree root @val
3990 *
3991 * Returns the newly created object.
3992 */
3993xmlXPathObjectPtr
3994xmlXPathNewValueTree(xmlNodePtr val) {
3995    xmlXPathObjectPtr ret;
3996
3997    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3998    if (ret == NULL) {
3999        xmlXPathErrMemory(NULL, "creating result value tree\n");
4000	return(NULL);
4001    }
4002    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4003    ret->type = XPATH_XSLT_TREE;
4004    ret->boolval = 1;
4005    ret->user = (void *) val;
4006    ret->nodesetval = xmlXPathNodeSetCreate(val);
4007#ifdef XP_DEBUG_OBJ_USAGE
4008    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4009#endif
4010    return(ret);
4011}
4012
4013/**
4014 * xmlXPathNewNodeSetList:
4015 * @val:  an existing NodeSet
4016 *
4017 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4018 * it with the Nodeset @val
4019 *
4020 * Returns the newly created object.
4021 */
4022xmlXPathObjectPtr
4023xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4024{
4025    xmlXPathObjectPtr ret;
4026    int i;
4027
4028    if (val == NULL)
4029        ret = NULL;
4030    else if (val->nodeTab == NULL)
4031        ret = xmlXPathNewNodeSet(NULL);
4032    else {
4033        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4034        for (i = 1; i < val->nodeNr; ++i)
4035            xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4036    }
4037
4038    return (ret);
4039}
4040
4041/**
4042 * xmlXPathWrapNodeSet:
4043 * @val:  the NodePtr value
4044 *
4045 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4046 *
4047 * Returns the newly created object.
4048 */
4049xmlXPathObjectPtr
4050xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4051    xmlXPathObjectPtr ret;
4052
4053    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4054    if (ret == NULL) {
4055        xmlXPathErrMemory(NULL, "creating node set object\n");
4056	return(NULL);
4057    }
4058    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4059    ret->type = XPATH_NODESET;
4060    ret->nodesetval = val;
4061#ifdef XP_DEBUG_OBJ_USAGE
4062    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4063#endif
4064    return(ret);
4065}
4066
4067/**
4068 * xmlXPathFreeNodeSetList:
4069 * @obj:  an existing NodeSetList object
4070 *
4071 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4072 * the list contrary to xmlXPathFreeObject().
4073 */
4074void
4075xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4076    if (obj == NULL) return;
4077#ifdef XP_DEBUG_OBJ_USAGE
4078    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4079#endif
4080    xmlFree(obj);
4081}
4082
4083/**
4084 * xmlXPathDifference:
4085 * @nodes1:  a node-set
4086 * @nodes2:  a node-set
4087 *
4088 * Implements the EXSLT - Sets difference() function:
4089 *    node-set set:difference (node-set, node-set)
4090 *
4091 * Returns the difference between the two node sets, or nodes1 if
4092 *         nodes2 is empty
4093 */
4094xmlNodeSetPtr
4095xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4096    xmlNodeSetPtr ret;
4097    int i, l1;
4098    xmlNodePtr cur;
4099
4100    if (xmlXPathNodeSetIsEmpty(nodes2))
4101	return(nodes1);
4102
4103    ret = xmlXPathNodeSetCreate(NULL);
4104    if (xmlXPathNodeSetIsEmpty(nodes1))
4105	return(ret);
4106
4107    l1 = xmlXPathNodeSetGetLength(nodes1);
4108
4109    for (i = 0; i < l1; i++) {
4110	cur = xmlXPathNodeSetItem(nodes1, i);
4111	if (!xmlXPathNodeSetContains(nodes2, cur))
4112	    xmlXPathNodeSetAddUnique(ret, cur);
4113    }
4114    return(ret);
4115}
4116
4117/**
4118 * xmlXPathIntersection:
4119 * @nodes1:  a node-set
4120 * @nodes2:  a node-set
4121 *
4122 * Implements the EXSLT - Sets intersection() function:
4123 *    node-set set:intersection (node-set, node-set)
4124 *
4125 * Returns a node set comprising the nodes that are within both the
4126 *         node sets passed as arguments
4127 */
4128xmlNodeSetPtr
4129xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4130    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4131    int i, l1;
4132    xmlNodePtr cur;
4133
4134    if (xmlXPathNodeSetIsEmpty(nodes1))
4135	return(ret);
4136    if (xmlXPathNodeSetIsEmpty(nodes2))
4137	return(ret);
4138
4139    l1 = xmlXPathNodeSetGetLength(nodes1);
4140
4141    for (i = 0; i < l1; i++) {
4142	cur = xmlXPathNodeSetItem(nodes1, i);
4143	if (xmlXPathNodeSetContains(nodes2, cur))
4144	    xmlXPathNodeSetAddUnique(ret, cur);
4145    }
4146    return(ret);
4147}
4148
4149/**
4150 * xmlXPathDistinctSorted:
4151 * @nodes:  a node-set, sorted by document order
4152 *
4153 * Implements the EXSLT - Sets distinct() function:
4154 *    node-set set:distinct (node-set)
4155 *
4156 * Returns a subset of the nodes contained in @nodes, or @nodes if
4157 *         it is empty
4158 */
4159xmlNodeSetPtr
4160xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4161    xmlNodeSetPtr ret;
4162    xmlHashTablePtr hash;
4163    int i, l;
4164    xmlChar * strval;
4165    xmlNodePtr cur;
4166
4167    if (xmlXPathNodeSetIsEmpty(nodes))
4168	return(nodes);
4169
4170    ret = xmlXPathNodeSetCreate(NULL);
4171    l = xmlXPathNodeSetGetLength(nodes);
4172    hash = xmlHashCreate (l);
4173    for (i = 0; i < l; i++) {
4174	cur = xmlXPathNodeSetItem(nodes, i);
4175	strval = xmlXPathCastNodeToString(cur);
4176	if (xmlHashLookup(hash, strval) == NULL) {
4177	    xmlHashAddEntry(hash, strval, strval);
4178	    xmlXPathNodeSetAddUnique(ret, cur);
4179	} else {
4180	    xmlFree(strval);
4181	}
4182    }
4183    xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4184    return(ret);
4185}
4186
4187/**
4188 * xmlXPathDistinct:
4189 * @nodes:  a node-set
4190 *
4191 * Implements the EXSLT - Sets distinct() function:
4192 *    node-set set:distinct (node-set)
4193 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4194 * is called with the sorted node-set
4195 *
4196 * Returns a subset of the nodes contained in @nodes, or @nodes if
4197 *         it is empty
4198 */
4199xmlNodeSetPtr
4200xmlXPathDistinct (xmlNodeSetPtr nodes) {
4201    if (xmlXPathNodeSetIsEmpty(nodes))
4202	return(nodes);
4203
4204    xmlXPathNodeSetSort(nodes);
4205    return(xmlXPathDistinctSorted(nodes));
4206}
4207
4208/**
4209 * xmlXPathHasSameNodes:
4210 * @nodes1:  a node-set
4211 * @nodes2:  a node-set
4212 *
4213 * Implements the EXSLT - Sets has-same-nodes function:
4214 *    boolean set:has-same-node(node-set, node-set)
4215 *
4216 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4217 *         otherwise
4218 */
4219int
4220xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4221    int i, l;
4222    xmlNodePtr cur;
4223
4224    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4225	xmlXPathNodeSetIsEmpty(nodes2))
4226	return(0);
4227
4228    l = xmlXPathNodeSetGetLength(nodes1);
4229    for (i = 0; i < l; i++) {
4230	cur = xmlXPathNodeSetItem(nodes1, i);
4231	if (xmlXPathNodeSetContains(nodes2, cur))
4232	    return(1);
4233    }
4234    return(0);
4235}
4236
4237/**
4238 * xmlXPathNodeLeadingSorted:
4239 * @nodes: a node-set, sorted by document order
4240 * @node: a node
4241 *
4242 * Implements the EXSLT - Sets leading() function:
4243 *    node-set set:leading (node-set, node-set)
4244 *
4245 * Returns the nodes in @nodes that precede @node in document order,
4246 *         @nodes if @node is NULL or an empty node-set if @nodes
4247 *         doesn't contain @node
4248 */
4249xmlNodeSetPtr
4250xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4251    int i, l;
4252    xmlNodePtr cur;
4253    xmlNodeSetPtr ret;
4254
4255    if (node == NULL)
4256	return(nodes);
4257
4258    ret = xmlXPathNodeSetCreate(NULL);
4259    if (xmlXPathNodeSetIsEmpty(nodes) ||
4260	(!xmlXPathNodeSetContains(nodes, node)))
4261	return(ret);
4262
4263    l = xmlXPathNodeSetGetLength(nodes);
4264    for (i = 0; i < l; i++) {
4265	cur = xmlXPathNodeSetItem(nodes, i);
4266	if (cur == node)
4267	    break;
4268	xmlXPathNodeSetAddUnique(ret, cur);
4269    }
4270    return(ret);
4271}
4272
4273/**
4274 * xmlXPathNodeLeading:
4275 * @nodes:  a node-set
4276 * @node:  a node
4277 *
4278 * Implements the EXSLT - Sets leading() function:
4279 *    node-set set:leading (node-set, node-set)
4280 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4281 * is called.
4282 *
4283 * Returns the nodes in @nodes that precede @node in document order,
4284 *         @nodes if @node is NULL or an empty node-set if @nodes
4285 *         doesn't contain @node
4286 */
4287xmlNodeSetPtr
4288xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4289    xmlXPathNodeSetSort(nodes);
4290    return(xmlXPathNodeLeadingSorted(nodes, node));
4291}
4292
4293/**
4294 * xmlXPathLeadingSorted:
4295 * @nodes1:  a node-set, sorted by document order
4296 * @nodes2:  a node-set, sorted by document order
4297 *
4298 * Implements the EXSLT - Sets leading() function:
4299 *    node-set set:leading (node-set, node-set)
4300 *
4301 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4302 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4303 *         an empty node-set if @nodes1 doesn't contain @nodes2
4304 */
4305xmlNodeSetPtr
4306xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4307    if (xmlXPathNodeSetIsEmpty(nodes2))
4308	return(nodes1);
4309    return(xmlXPathNodeLeadingSorted(nodes1,
4310				     xmlXPathNodeSetItem(nodes2, 1)));
4311}
4312
4313/**
4314 * xmlXPathLeading:
4315 * @nodes1:  a node-set
4316 * @nodes2:  a node-set
4317 *
4318 * Implements the EXSLT - Sets leading() function:
4319 *    node-set set:leading (node-set, node-set)
4320 * @nodes1 and @nodes2 are sorted by document order, then
4321 * #exslSetsLeadingSorted is called.
4322 *
4323 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4324 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4325 *         an empty node-set if @nodes1 doesn't contain @nodes2
4326 */
4327xmlNodeSetPtr
4328xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4329    if (xmlXPathNodeSetIsEmpty(nodes2))
4330	return(nodes1);
4331    if (xmlXPathNodeSetIsEmpty(nodes1))
4332	return(xmlXPathNodeSetCreate(NULL));
4333    xmlXPathNodeSetSort(nodes1);
4334    xmlXPathNodeSetSort(nodes2);
4335    return(xmlXPathNodeLeadingSorted(nodes1,
4336				     xmlXPathNodeSetItem(nodes2, 1)));
4337}
4338
4339/**
4340 * xmlXPathNodeTrailingSorted:
4341 * @nodes: a node-set, sorted by document order
4342 * @node: a node
4343 *
4344 * Implements the EXSLT - Sets trailing() function:
4345 *    node-set set:trailing (node-set, node-set)
4346 *
4347 * Returns the nodes in @nodes that follow @node in document order,
4348 *         @nodes if @node is NULL or an empty node-set if @nodes
4349 *         doesn't contain @node
4350 */
4351xmlNodeSetPtr
4352xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4353    int i, l;
4354    xmlNodePtr cur;
4355    xmlNodeSetPtr ret;
4356
4357    if (node == NULL)
4358	return(nodes);
4359
4360    ret = xmlXPathNodeSetCreate(NULL);
4361    if (xmlXPathNodeSetIsEmpty(nodes) ||
4362	(!xmlXPathNodeSetContains(nodes, node)))
4363	return(ret);
4364
4365    l = xmlXPathNodeSetGetLength(nodes);
4366    for (i = l; i > 0; i--) {
4367	cur = xmlXPathNodeSetItem(nodes, i);
4368	if (cur == node)
4369	    break;
4370	xmlXPathNodeSetAddUnique(ret, cur);
4371    }
4372    return(ret);
4373}
4374
4375/**
4376 * xmlXPathNodeTrailing:
4377 * @nodes:  a node-set
4378 * @node:  a node
4379 *
4380 * Implements the EXSLT - Sets trailing() function:
4381 *    node-set set:trailing (node-set, node-set)
4382 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4383 * is called.
4384 *
4385 * Returns the nodes in @nodes that follow @node in document order,
4386 *         @nodes if @node is NULL or an empty node-set if @nodes
4387 *         doesn't contain @node
4388 */
4389xmlNodeSetPtr
4390xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4391    xmlXPathNodeSetSort(nodes);
4392    return(xmlXPathNodeTrailingSorted(nodes, node));
4393}
4394
4395/**
4396 * xmlXPathTrailingSorted:
4397 * @nodes1:  a node-set, sorted by document order
4398 * @nodes2:  a node-set, sorted by document order
4399 *
4400 * Implements the EXSLT - Sets trailing() function:
4401 *    node-set set:trailing (node-set, node-set)
4402 *
4403 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4404 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4405 *         an empty node-set if @nodes1 doesn't contain @nodes2
4406 */
4407xmlNodeSetPtr
4408xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4409    if (xmlXPathNodeSetIsEmpty(nodes2))
4410	return(nodes1);
4411    return(xmlXPathNodeTrailingSorted(nodes1,
4412				      xmlXPathNodeSetItem(nodes2, 0)));
4413}
4414
4415/**
4416 * xmlXPathTrailing:
4417 * @nodes1:  a node-set
4418 * @nodes2:  a node-set
4419 *
4420 * Implements the EXSLT - Sets trailing() function:
4421 *    node-set set:trailing (node-set, node-set)
4422 * @nodes1 and @nodes2 are sorted by document order, then
4423 * #xmlXPathTrailingSorted is called.
4424 *
4425 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4426 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4427 *         an empty node-set if @nodes1 doesn't contain @nodes2
4428 */
4429xmlNodeSetPtr
4430xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4431    if (xmlXPathNodeSetIsEmpty(nodes2))
4432	return(nodes1);
4433    if (xmlXPathNodeSetIsEmpty(nodes1))
4434	return(xmlXPathNodeSetCreate(NULL));
4435    xmlXPathNodeSetSort(nodes1);
4436    xmlXPathNodeSetSort(nodes2);
4437    return(xmlXPathNodeTrailingSorted(nodes1,
4438				      xmlXPathNodeSetItem(nodes2, 0)));
4439}
4440
4441/************************************************************************
4442 *									*
4443 *		Routines to handle extra functions			*
4444 *									*
4445 ************************************************************************/
4446
4447/**
4448 * xmlXPathRegisterFunc:
4449 * @ctxt:  the XPath context
4450 * @name:  the function name
4451 * @f:  the function implementation or NULL
4452 *
4453 * Register a new function. If @f is NULL it unregisters the function
4454 *
4455 * Returns 0 in case of success, -1 in case of error
4456 */
4457int
4458xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4459		     xmlXPathFunction f) {
4460    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4461}
4462
4463/**
4464 * xmlXPathRegisterFuncNS:
4465 * @ctxt:  the XPath context
4466 * @name:  the function name
4467 * @ns_uri:  the function namespace URI
4468 * @f:  the function implementation or NULL
4469 *
4470 * Register a new function. If @f is NULL it unregisters the function
4471 *
4472 * Returns 0 in case of success, -1 in case of error
4473 */
4474int
4475xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4476		       const xmlChar *ns_uri, xmlXPathFunction f) {
4477    if (ctxt == NULL)
4478	return(-1);
4479    if (name == NULL)
4480	return(-1);
4481
4482    if (ctxt->funcHash == NULL)
4483	ctxt->funcHash = xmlHashCreate(0);
4484    if (ctxt->funcHash == NULL)
4485	return(-1);
4486    if (f == NULL)
4487        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4488    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4489}
4490
4491/**
4492 * xmlXPathRegisterFuncLookup:
4493 * @ctxt:  the XPath context
4494 * @f:  the lookup function
4495 * @funcCtxt:  the lookup data
4496 *
4497 * Registers an external mechanism to do function lookup.
4498 */
4499void
4500xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4501			    xmlXPathFuncLookupFunc f,
4502			    void *funcCtxt) {
4503    if (ctxt == NULL)
4504	return;
4505    ctxt->funcLookupFunc = f;
4506    ctxt->funcLookupData = funcCtxt;
4507}
4508
4509/**
4510 * xmlXPathFunctionLookup:
4511 * @ctxt:  the XPath context
4512 * @name:  the function name
4513 *
4514 * Search in the Function array of the context for the given
4515 * function.
4516 *
4517 * Returns the xmlXPathFunction or NULL if not found
4518 */
4519xmlXPathFunction
4520xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4521    if (ctxt == NULL)
4522	return (NULL);
4523
4524    if (ctxt->funcLookupFunc != NULL) {
4525	xmlXPathFunction ret;
4526	xmlXPathFuncLookupFunc f;
4527
4528	f = ctxt->funcLookupFunc;
4529	ret = f(ctxt->funcLookupData, name, NULL);
4530	if (ret != NULL)
4531	    return(ret);
4532    }
4533    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4534}
4535
4536/**
4537 * xmlXPathFunctionLookupNS:
4538 * @ctxt:  the XPath context
4539 * @name:  the function name
4540 * @ns_uri:  the function namespace URI
4541 *
4542 * Search in the Function array of the context for the given
4543 * function.
4544 *
4545 * Returns the xmlXPathFunction or NULL if not found
4546 */
4547xmlXPathFunction
4548xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4549			 const xmlChar *ns_uri) {
4550    xmlXPathFunction ret;
4551
4552    if (ctxt == NULL)
4553	return(NULL);
4554    if (name == NULL)
4555	return(NULL);
4556
4557    if (ctxt->funcLookupFunc != NULL) {
4558	xmlXPathFuncLookupFunc f;
4559
4560	f = ctxt->funcLookupFunc;
4561	ret = f(ctxt->funcLookupData, name, ns_uri);
4562	if (ret != NULL)
4563	    return(ret);
4564    }
4565
4566    if (ctxt->funcHash == NULL)
4567	return(NULL);
4568
4569    XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4570    return(ret);
4571}
4572
4573/**
4574 * xmlXPathRegisteredFuncsCleanup:
4575 * @ctxt:  the XPath context
4576 *
4577 * Cleanup the XPath context data associated to registered functions
4578 */
4579void
4580xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4581    if (ctxt == NULL)
4582	return;
4583
4584    xmlHashFree(ctxt->funcHash, NULL);
4585    ctxt->funcHash = NULL;
4586}
4587
4588/************************************************************************
4589 *									*
4590 *			Routines to handle Variables			*
4591 *									*
4592 ************************************************************************/
4593
4594/**
4595 * xmlXPathRegisterVariable:
4596 * @ctxt:  the XPath context
4597 * @name:  the variable name
4598 * @value:  the variable value or NULL
4599 *
4600 * Register a new variable value. If @value is NULL it unregisters
4601 * the variable
4602 *
4603 * Returns 0 in case of success, -1 in case of error
4604 */
4605int
4606xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4607			 xmlXPathObjectPtr value) {
4608    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4609}
4610
4611/**
4612 * xmlXPathRegisterVariableNS:
4613 * @ctxt:  the XPath context
4614 * @name:  the variable name
4615 * @ns_uri:  the variable namespace URI
4616 * @value:  the variable value or NULL
4617 *
4618 * Register a new variable value. If @value is NULL it unregisters
4619 * the variable
4620 *
4621 * Returns 0 in case of success, -1 in case of error
4622 */
4623int
4624xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4625			   const xmlChar *ns_uri,
4626			   xmlXPathObjectPtr value) {
4627    if (ctxt == NULL)
4628	return(-1);
4629    if (name == NULL)
4630	return(-1);
4631
4632    if (ctxt->varHash == NULL)
4633	ctxt->varHash = xmlHashCreate(0);
4634    if (ctxt->varHash == NULL)
4635	return(-1);
4636    if (value == NULL)
4637        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4638	                           (xmlHashDeallocator)xmlXPathFreeObject));
4639    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4640			       (void *) value,
4641			       (xmlHashDeallocator)xmlXPathFreeObject));
4642}
4643
4644/**
4645 * xmlXPathRegisterVariableLookup:
4646 * @ctxt:  the XPath context
4647 * @f:  the lookup function
4648 * @data:  the lookup data
4649 *
4650 * register an external mechanism to do variable lookup
4651 */
4652void
4653xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4654	 xmlXPathVariableLookupFunc f, void *data) {
4655    if (ctxt == NULL)
4656	return;
4657    ctxt->varLookupFunc = f;
4658    ctxt->varLookupData = data;
4659}
4660
4661/**
4662 * xmlXPathVariableLookup:
4663 * @ctxt:  the XPath context
4664 * @name:  the variable name
4665 *
4666 * Search in the Variable array of the context for the given
4667 * variable value.
4668 *
4669 * Returns a copy of the value or NULL if not found
4670 */
4671xmlXPathObjectPtr
4672xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4673    if (ctxt == NULL)
4674	return(NULL);
4675
4676    if (ctxt->varLookupFunc != NULL) {
4677	xmlXPathObjectPtr ret;
4678
4679	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4680	        (ctxt->varLookupData, name, NULL);
4681	return(ret);
4682    }
4683    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4684}
4685
4686/**
4687 * xmlXPathVariableLookupNS:
4688 * @ctxt:  the XPath context
4689 * @name:  the variable name
4690 * @ns_uri:  the variable namespace URI
4691 *
4692 * Search in the Variable array of the context for the given
4693 * variable value.
4694 *
4695 * Returns the a copy of the value or NULL if not found
4696 */
4697xmlXPathObjectPtr
4698xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4699			 const xmlChar *ns_uri) {
4700    if (ctxt == NULL)
4701	return(NULL);
4702
4703    if (ctxt->varLookupFunc != NULL) {
4704	xmlXPathObjectPtr ret;
4705
4706	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4707	        (ctxt->varLookupData, name, ns_uri);
4708	if (ret != NULL) return(ret);
4709    }
4710
4711    if (ctxt->varHash == NULL)
4712	return(NULL);
4713    if (name == NULL)
4714	return(NULL);
4715
4716    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
4717		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4718}
4719
4720/**
4721 * xmlXPathRegisteredVariablesCleanup:
4722 * @ctxt:  the XPath context
4723 *
4724 * Cleanup the XPath context data associated to registered variables
4725 */
4726void
4727xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4728    if (ctxt == NULL)
4729	return;
4730
4731    xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
4732    ctxt->varHash = NULL;
4733}
4734
4735/**
4736 * xmlXPathRegisterNs:
4737 * @ctxt:  the XPath context
4738 * @prefix:  the namespace prefix
4739 * @ns_uri:  the namespace name
4740 *
4741 * Register a new namespace. If @ns_uri is NULL it unregisters
4742 * the namespace
4743 *
4744 * Returns 0 in case of success, -1 in case of error
4745 */
4746int
4747xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4748			   const xmlChar *ns_uri) {
4749    if (ctxt == NULL)
4750	return(-1);
4751    if (prefix == NULL)
4752	return(-1);
4753
4754    if (ctxt->nsHash == NULL)
4755	ctxt->nsHash = xmlHashCreate(10);
4756    if (ctxt->nsHash == NULL)
4757	return(-1);
4758    if (ns_uri == NULL)
4759        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4760	                          (xmlHashDeallocator)xmlFree));
4761    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
4762			      (xmlHashDeallocator)xmlFree));
4763}
4764
4765/**
4766 * xmlXPathNsLookup:
4767 * @ctxt:  the XPath context
4768 * @prefix:  the namespace prefix value
4769 *
4770 * Search in the namespace declaration array of the context for the given
4771 * namespace name associated to the given prefix
4772 *
4773 * Returns the value or NULL if not found
4774 */
4775const xmlChar *
4776xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4777    if (ctxt == NULL)
4778	return(NULL);
4779    if (prefix == NULL)
4780	return(NULL);
4781
4782#ifdef XML_XML_NAMESPACE
4783    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4784	return(XML_XML_NAMESPACE);
4785#endif
4786
4787    if (ctxt->namespaces != NULL) {
4788	int i;
4789
4790	for (i = 0;i < ctxt->nsNr;i++) {
4791	    if ((ctxt->namespaces[i] != NULL) &&
4792		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4793		return(ctxt->namespaces[i]->href);
4794	}
4795    }
4796
4797    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4798}
4799
4800/**
4801 * xmlXPathRegisteredNsCleanup:
4802 * @ctxt:  the XPath context
4803 *
4804 * Cleanup the XPath context data associated to registered variables
4805 */
4806void
4807xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4808    if (ctxt == NULL)
4809	return;
4810
4811    xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
4812    ctxt->nsHash = NULL;
4813}
4814
4815/************************************************************************
4816 *									*
4817 *			Routines to handle Values			*
4818 *									*
4819 ************************************************************************/
4820
4821/* Allocations are terrible, one needs to optimize all this !!! */
4822
4823/**
4824 * xmlXPathNewFloat:
4825 * @val:  the double value
4826 *
4827 * Create a new xmlXPathObjectPtr of type double and of value @val
4828 *
4829 * Returns the newly created object.
4830 */
4831xmlXPathObjectPtr
4832xmlXPathNewFloat(double val) {
4833    xmlXPathObjectPtr ret;
4834
4835    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4836    if (ret == NULL) {
4837        xmlXPathErrMemory(NULL, "creating float object\n");
4838	return(NULL);
4839    }
4840    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4841    ret->type = XPATH_NUMBER;
4842    ret->floatval = val;
4843#ifdef XP_DEBUG_OBJ_USAGE
4844    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
4845#endif
4846    return(ret);
4847}
4848
4849/**
4850 * xmlXPathNewBoolean:
4851 * @val:  the boolean value
4852 *
4853 * Create a new xmlXPathObjectPtr of type boolean and of value @val
4854 *
4855 * Returns the newly created object.
4856 */
4857xmlXPathObjectPtr
4858xmlXPathNewBoolean(int val) {
4859    xmlXPathObjectPtr ret;
4860
4861    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4862    if (ret == NULL) {
4863        xmlXPathErrMemory(NULL, "creating boolean object\n");
4864	return(NULL);
4865    }
4866    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4867    ret->type = XPATH_BOOLEAN;
4868    ret->boolval = (val != 0);
4869#ifdef XP_DEBUG_OBJ_USAGE
4870    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
4871#endif
4872    return(ret);
4873}
4874
4875/**
4876 * xmlXPathNewString:
4877 * @val:  the xmlChar * value
4878 *
4879 * Create a new xmlXPathObjectPtr of type string and of value @val
4880 *
4881 * Returns the newly created object.
4882 */
4883xmlXPathObjectPtr
4884xmlXPathNewString(const xmlChar *val) {
4885    xmlXPathObjectPtr ret;
4886
4887    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4888    if (ret == NULL) {
4889        xmlXPathErrMemory(NULL, "creating string object\n");
4890	return(NULL);
4891    }
4892    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4893    ret->type = XPATH_STRING;
4894    if (val != NULL)
4895	ret->stringval = xmlStrdup(val);
4896    else
4897	ret->stringval = xmlStrdup((const xmlChar *)"");
4898#ifdef XP_DEBUG_OBJ_USAGE
4899    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
4900#endif
4901    return(ret);
4902}
4903
4904/**
4905 * xmlXPathWrapString:
4906 * @val:  the xmlChar * value
4907 *
4908 * Wraps the @val string into an XPath object.
4909 *
4910 * Returns the newly created object.
4911 */
4912xmlXPathObjectPtr
4913xmlXPathWrapString (xmlChar *val) {
4914    xmlXPathObjectPtr ret;
4915
4916    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4917    if (ret == NULL) {
4918        xmlXPathErrMemory(NULL, "creating string object\n");
4919	return(NULL);
4920    }
4921    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4922    ret->type = XPATH_STRING;
4923    ret->stringval = val;
4924#ifdef XP_DEBUG_OBJ_USAGE
4925    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
4926#endif
4927    return(ret);
4928}
4929
4930/**
4931 * xmlXPathNewCString:
4932 * @val:  the char * value
4933 *
4934 * Create a new xmlXPathObjectPtr of type string and of value @val
4935 *
4936 * Returns the newly created object.
4937 */
4938xmlXPathObjectPtr
4939xmlXPathNewCString(const char *val) {
4940    xmlXPathObjectPtr ret;
4941
4942    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4943    if (ret == NULL) {
4944        xmlXPathErrMemory(NULL, "creating string object\n");
4945	return(NULL);
4946    }
4947    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4948    ret->type = XPATH_STRING;
4949    ret->stringval = xmlStrdup(BAD_CAST val);
4950#ifdef XP_DEBUG_OBJ_USAGE
4951    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
4952#endif
4953    return(ret);
4954}
4955
4956/**
4957 * xmlXPathWrapCString:
4958 * @val:  the char * value
4959 *
4960 * Wraps a string into an XPath object.
4961 *
4962 * Returns the newly created object.
4963 */
4964xmlXPathObjectPtr
4965xmlXPathWrapCString (char * val) {
4966    return(xmlXPathWrapString((xmlChar *)(val)));
4967}
4968
4969/**
4970 * xmlXPathWrapExternal:
4971 * @val:  the user data
4972 *
4973 * Wraps the @val data into an XPath object.
4974 *
4975 * Returns the newly created object.
4976 */
4977xmlXPathObjectPtr
4978xmlXPathWrapExternal (void *val) {
4979    xmlXPathObjectPtr ret;
4980
4981    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4982    if (ret == NULL) {
4983        xmlXPathErrMemory(NULL, "creating user object\n");
4984	return(NULL);
4985    }
4986    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4987    ret->type = XPATH_USERS;
4988    ret->user = val;
4989#ifdef XP_DEBUG_OBJ_USAGE
4990    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
4991#endif
4992    return(ret);
4993}
4994
4995/**
4996 * xmlXPathObjectCopy:
4997 * @val:  the original object
4998 *
4999 * allocate a new copy of a given object
5000 *
5001 * Returns the newly created object.
5002 */
5003xmlXPathObjectPtr
5004xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5005    xmlXPathObjectPtr ret;
5006
5007    if (val == NULL)
5008	return(NULL);
5009
5010    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5011    if (ret == NULL) {
5012        xmlXPathErrMemory(NULL, "copying object\n");
5013	return(NULL);
5014    }
5015    memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5016#ifdef XP_DEBUG_OBJ_USAGE
5017    xmlXPathDebugObjUsageRequested(NULL, val->type);
5018#endif
5019    switch (val->type) {
5020	case XPATH_BOOLEAN:
5021	case XPATH_NUMBER:
5022	case XPATH_POINT:
5023	case XPATH_RANGE:
5024	    break;
5025	case XPATH_STRING:
5026	    ret->stringval = xmlStrdup(val->stringval);
5027	    break;
5028	case XPATH_XSLT_TREE:
5029#if 0
5030/*
5031  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5032  this previous handling is no longer correct, and can cause some serious
5033  problems (ref. bug 145547)
5034*/
5035	    if ((val->nodesetval != NULL) &&
5036		(val->nodesetval->nodeTab != NULL)) {
5037		xmlNodePtr cur, tmp;
5038		xmlDocPtr top;
5039
5040		ret->boolval = 1;
5041		top =  xmlNewDoc(NULL);
5042		top->name = (char *)
5043		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5044		ret->user = top;
5045		if (top != NULL) {
5046		    top->doc = top;
5047		    cur = val->nodesetval->nodeTab[0]->children;
5048		    while (cur != NULL) {
5049			tmp = xmlDocCopyNode(cur, top, 1);
5050			xmlAddChild((xmlNodePtr) top, tmp);
5051			cur = cur->next;
5052		    }
5053		}
5054
5055		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5056	    } else
5057		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5058	    /* Deallocate the copied tree value */
5059	    break;
5060#endif
5061	case XPATH_NODESET:
5062	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5063	    /* Do not deallocate the copied tree value */
5064	    ret->boolval = 0;
5065	    break;
5066	case XPATH_LOCATIONSET:
5067#ifdef LIBXML_XPTR_ENABLED
5068	{
5069	    xmlLocationSetPtr loc = val->user;
5070	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5071	    break;
5072	}
5073#endif
5074        case XPATH_USERS:
5075	    ret->user = val->user;
5076	    break;
5077        case XPATH_UNDEFINED:
5078	    xmlGenericError(xmlGenericErrorContext,
5079		    "xmlXPathObjectCopy: unsupported type %d\n",
5080		    val->type);
5081	    break;
5082    }
5083    return(ret);
5084}
5085
5086/**
5087 * xmlXPathFreeObject:
5088 * @obj:  the object to free
5089 *
5090 * Free up an xmlXPathObjectPtr object.
5091 */
5092void
5093xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5094    if (obj == NULL) return;
5095    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5096	if (obj->boolval) {
5097#if 0
5098	    if (obj->user != NULL) {
5099                xmlXPathFreeNodeSet(obj->nodesetval);
5100		xmlFreeNodeList((xmlNodePtr) obj->user);
5101	    } else
5102#endif
5103	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5104	    if (obj->nodesetval != NULL)
5105		xmlXPathFreeValueTree(obj->nodesetval);
5106	} else {
5107	    if (obj->nodesetval != NULL)
5108		xmlXPathFreeNodeSet(obj->nodesetval);
5109	}
5110#ifdef LIBXML_XPTR_ENABLED
5111    } else if (obj->type == XPATH_LOCATIONSET) {
5112	if (obj->user != NULL)
5113	    xmlXPtrFreeLocationSet(obj->user);
5114#endif
5115    } else if (obj->type == XPATH_STRING) {
5116	if (obj->stringval != NULL)
5117	    xmlFree(obj->stringval);
5118    }
5119#ifdef XP_DEBUG_OBJ_USAGE
5120    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5121#endif
5122    xmlFree(obj);
5123}
5124
5125/**
5126 * xmlXPathReleaseObject:
5127 * @obj:  the xmlXPathObjectPtr to free or to cache
5128 *
5129 * Depending on the state of the cache this frees the given
5130 * XPath object or stores it in the cache.
5131 */
5132static void
5133xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5134{
5135#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5136	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5137    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5138
5139#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5140
5141    if (obj == NULL)
5142	return;
5143    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5144	 xmlXPathFreeObject(obj);
5145    } else {
5146	xmlXPathContextCachePtr cache =
5147	    (xmlXPathContextCachePtr) ctxt->cache;
5148
5149	switch (obj->type) {
5150	    case XPATH_NODESET:
5151	    case XPATH_XSLT_TREE:
5152		if (obj->nodesetval != NULL) {
5153		    if (obj->boolval) {
5154		    	/*
5155			* It looks like the @boolval is used for
5156			* evaluation if this an XSLT Result Tree Fragment.
5157			* TODO: Check if this assumption is correct.
5158			*/
5159			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5160			xmlXPathFreeValueTree(obj->nodesetval);
5161			obj->nodesetval = NULL;
5162		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5163			(XP_CACHE_WANTS(cache->nodesetObjs,
5164					cache->maxNodeset)))
5165		    {
5166			XP_CACHE_ADD(cache->nodesetObjs, obj);
5167			goto obj_cached;
5168		    } else {
5169			xmlXPathFreeNodeSet(obj->nodesetval);
5170			obj->nodesetval = NULL;
5171		    }
5172		}
5173		break;
5174	    case XPATH_STRING:
5175		if (obj->stringval != NULL)
5176		    xmlFree(obj->stringval);
5177
5178		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5179		    XP_CACHE_ADD(cache->stringObjs, obj);
5180		    goto obj_cached;
5181		}
5182		break;
5183	    case XPATH_BOOLEAN:
5184		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5185		    XP_CACHE_ADD(cache->booleanObjs, obj);
5186		    goto obj_cached;
5187		}
5188		break;
5189	    case XPATH_NUMBER:
5190		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5191		    XP_CACHE_ADD(cache->numberObjs, obj);
5192		    goto obj_cached;
5193		}
5194		break;
5195#ifdef LIBXML_XPTR_ENABLED
5196	    case XPATH_LOCATIONSET:
5197		if (obj->user != NULL) {
5198		    xmlXPtrFreeLocationSet(obj->user);
5199		}
5200		goto free_obj;
5201#endif
5202	    default:
5203		goto free_obj;
5204	}
5205
5206	/*
5207	* Fallback to adding to the misc-objects slot.
5208	*/
5209	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5210	    XP_CACHE_ADD(cache->miscObjs, obj);
5211	} else
5212	    goto free_obj;
5213
5214obj_cached:
5215
5216#ifdef XP_DEBUG_OBJ_USAGE
5217	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5218#endif
5219
5220	if (obj->nodesetval != NULL) {
5221	    xmlNodeSetPtr tmpset = obj->nodesetval;
5222
5223	    /*
5224	    * TODO: Due to those nasty ns-nodes, we need to traverse
5225	    *  the list and free the ns-nodes.
5226	    * URGENT TODO: Check if it's actually slowing things down.
5227	    *  Maybe we shouldn't try to preserve the list.
5228	    */
5229	    if (tmpset->nodeNr > 1) {
5230		int i;
5231		xmlNodePtr node;
5232
5233		for (i = 0; i < tmpset->nodeNr; i++) {
5234		    node = tmpset->nodeTab[i];
5235		    if ((node != NULL) &&
5236			(node->type == XML_NAMESPACE_DECL))
5237		    {
5238			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5239		    }
5240		}
5241	    } else if (tmpset->nodeNr == 1) {
5242		if ((tmpset->nodeTab[0] != NULL) &&
5243		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5244		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5245	    }
5246	    tmpset->nodeNr = 0;
5247	    memset(obj, 0, sizeof(xmlXPathObject));
5248	    obj->nodesetval = tmpset;
5249	} else
5250	    memset(obj, 0, sizeof(xmlXPathObject));
5251
5252	return;
5253
5254free_obj:
5255	/*
5256	* Cache is full; free the object.
5257	*/
5258	if (obj->nodesetval != NULL)
5259	    xmlXPathFreeNodeSet(obj->nodesetval);
5260#ifdef XP_DEBUG_OBJ_USAGE
5261	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5262#endif
5263	xmlFree(obj);
5264    }
5265    return;
5266}
5267
5268
5269/************************************************************************
5270 *									*
5271 *			Type Casting Routines				*
5272 *									*
5273 ************************************************************************/
5274
5275/**
5276 * xmlXPathCastBooleanToString:
5277 * @val:  a boolean
5278 *
5279 * Converts a boolean to its string value.
5280 *
5281 * Returns a newly allocated string.
5282 */
5283xmlChar *
5284xmlXPathCastBooleanToString (int val) {
5285    xmlChar *ret;
5286    if (val)
5287	ret = xmlStrdup((const xmlChar *) "true");
5288    else
5289	ret = xmlStrdup((const xmlChar *) "false");
5290    return(ret);
5291}
5292
5293/**
5294 * xmlXPathCastNumberToString:
5295 * @val:  a number
5296 *
5297 * Converts a number to its string value.
5298 *
5299 * Returns a newly allocated string.
5300 */
5301xmlChar *
5302xmlXPathCastNumberToString (double val) {
5303    xmlChar *ret;
5304    switch (xmlXPathIsInf(val)) {
5305    case 1:
5306	ret = xmlStrdup((const xmlChar *) "Infinity");
5307	break;
5308    case -1:
5309	ret = xmlStrdup((const xmlChar *) "-Infinity");
5310	break;
5311    default:
5312	if (xmlXPathIsNaN(val)) {
5313	    ret = xmlStrdup((const xmlChar *) "NaN");
5314	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
5315	    ret = xmlStrdup((const xmlChar *) "0");
5316	} else {
5317	    /* could be improved */
5318	    char buf[100];
5319	    xmlXPathFormatNumber(val, buf, 99);
5320	    buf[99] = 0;
5321	    ret = xmlStrdup((const xmlChar *) buf);
5322	}
5323    }
5324    return(ret);
5325}
5326
5327/**
5328 * xmlXPathCastNodeToString:
5329 * @node:  a node
5330 *
5331 * Converts a node to its string value.
5332 *
5333 * Returns a newly allocated string.
5334 */
5335xmlChar *
5336xmlXPathCastNodeToString (xmlNodePtr node) {
5337    return(xmlNodeGetContent(node));
5338}
5339
5340/**
5341 * xmlXPathCastNodeSetToString:
5342 * @ns:  a node-set
5343 *
5344 * Converts a node-set to its string value.
5345 *
5346 * Returns a newly allocated string.
5347 */
5348xmlChar *
5349xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5350    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5351	return(xmlStrdup((const xmlChar *) ""));
5352
5353    if (ns->nodeNr > 1)
5354	xmlXPathNodeSetSort(ns);
5355    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5356}
5357
5358/**
5359 * xmlXPathCastToString:
5360 * @val:  an XPath object
5361 *
5362 * Converts an existing object to its string() equivalent
5363 *
5364 * Returns the string value of the object, NULL in case of error.
5365 *         A new string is allocated only if needed (@val isn't a
5366 *         string object).
5367 */
5368xmlChar *
5369xmlXPathCastToString(xmlXPathObjectPtr val) {
5370    xmlChar *ret = NULL;
5371
5372    if (val == NULL)
5373	return(xmlStrdup((const xmlChar *) ""));
5374    switch (val->type) {
5375	case XPATH_UNDEFINED:
5376#ifdef DEBUG_EXPR
5377	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5378#endif
5379	    ret = xmlStrdup((const xmlChar *) "");
5380	    break;
5381        case XPATH_NODESET:
5382        case XPATH_XSLT_TREE:
5383	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5384	    break;
5385	case XPATH_STRING:
5386	    return(xmlStrdup(val->stringval));
5387        case XPATH_BOOLEAN:
5388	    ret = xmlXPathCastBooleanToString(val->boolval);
5389	    break;
5390	case XPATH_NUMBER: {
5391	    ret = xmlXPathCastNumberToString(val->floatval);
5392	    break;
5393	}
5394	case XPATH_USERS:
5395	case XPATH_POINT:
5396	case XPATH_RANGE:
5397	case XPATH_LOCATIONSET:
5398	    TODO
5399	    ret = xmlStrdup((const xmlChar *) "");
5400	    break;
5401    }
5402    return(ret);
5403}
5404
5405/**
5406 * xmlXPathConvertString:
5407 * @val:  an XPath object
5408 *
5409 * Converts an existing object to its string() equivalent
5410 *
5411 * Returns the new object, the old one is freed (or the operation
5412 *         is done directly on @val)
5413 */
5414xmlXPathObjectPtr
5415xmlXPathConvertString(xmlXPathObjectPtr val) {
5416    xmlChar *res = NULL;
5417
5418    if (val == NULL)
5419	return(xmlXPathNewCString(""));
5420
5421    switch (val->type) {
5422    case XPATH_UNDEFINED:
5423#ifdef DEBUG_EXPR
5424	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5425#endif
5426	break;
5427    case XPATH_NODESET:
5428    case XPATH_XSLT_TREE:
5429	res = xmlXPathCastNodeSetToString(val->nodesetval);
5430	break;
5431    case XPATH_STRING:
5432	return(val);
5433    case XPATH_BOOLEAN:
5434	res = xmlXPathCastBooleanToString(val->boolval);
5435	break;
5436    case XPATH_NUMBER:
5437	res = xmlXPathCastNumberToString(val->floatval);
5438	break;
5439    case XPATH_USERS:
5440    case XPATH_POINT:
5441    case XPATH_RANGE:
5442    case XPATH_LOCATIONSET:
5443	TODO;
5444	break;
5445    }
5446    xmlXPathFreeObject(val);
5447    if (res == NULL)
5448	return(xmlXPathNewCString(""));
5449    return(xmlXPathWrapString(res));
5450}
5451
5452/**
5453 * xmlXPathCastBooleanToNumber:
5454 * @val:  a boolean
5455 *
5456 * Converts a boolean to its number value
5457 *
5458 * Returns the number value
5459 */
5460double
5461xmlXPathCastBooleanToNumber(int val) {
5462    if (val)
5463	return(1.0);
5464    return(0.0);
5465}
5466
5467/**
5468 * xmlXPathCastStringToNumber:
5469 * @val:  a string
5470 *
5471 * Converts a string to its number value
5472 *
5473 * Returns the number value
5474 */
5475double
5476xmlXPathCastStringToNumber(const xmlChar * val) {
5477    return(xmlXPathStringEvalNumber(val));
5478}
5479
5480/**
5481 * xmlXPathCastNodeToNumber:
5482 * @node:  a node
5483 *
5484 * Converts a node to its number value
5485 *
5486 * Returns the number value
5487 */
5488double
5489xmlXPathCastNodeToNumber (xmlNodePtr node) {
5490    xmlChar *strval;
5491    double ret;
5492
5493    if (node == NULL)
5494	return(xmlXPathNAN);
5495    strval = xmlXPathCastNodeToString(node);
5496    if (strval == NULL)
5497	return(xmlXPathNAN);
5498    ret = xmlXPathCastStringToNumber(strval);
5499    xmlFree(strval);
5500
5501    return(ret);
5502}
5503
5504/**
5505 * xmlXPathCastNodeSetToNumber:
5506 * @ns:  a node-set
5507 *
5508 * Converts a node-set to its number value
5509 *
5510 * Returns the number value
5511 */
5512double
5513xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5514    xmlChar *str;
5515    double ret;
5516
5517    if (ns == NULL)
5518	return(xmlXPathNAN);
5519    str = xmlXPathCastNodeSetToString(ns);
5520    ret = xmlXPathCastStringToNumber(str);
5521    xmlFree(str);
5522    return(ret);
5523}
5524
5525/**
5526 * xmlXPathCastToNumber:
5527 * @val:  an XPath object
5528 *
5529 * Converts an XPath object to its number value
5530 *
5531 * Returns the number value
5532 */
5533double
5534xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5535    double ret = 0.0;
5536
5537    if (val == NULL)
5538	return(xmlXPathNAN);
5539    switch (val->type) {
5540    case XPATH_UNDEFINED:
5541#ifdef DEGUB_EXPR
5542	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5543#endif
5544	ret = xmlXPathNAN;
5545	break;
5546    case XPATH_NODESET:
5547    case XPATH_XSLT_TREE:
5548	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5549	break;
5550    case XPATH_STRING:
5551	ret = xmlXPathCastStringToNumber(val->stringval);
5552	break;
5553    case XPATH_NUMBER:
5554	ret = val->floatval;
5555	break;
5556    case XPATH_BOOLEAN:
5557	ret = xmlXPathCastBooleanToNumber(val->boolval);
5558	break;
5559    case XPATH_USERS:
5560    case XPATH_POINT:
5561    case XPATH_RANGE:
5562    case XPATH_LOCATIONSET:
5563	TODO;
5564	ret = xmlXPathNAN;
5565	break;
5566    }
5567    return(ret);
5568}
5569
5570/**
5571 * xmlXPathConvertNumber:
5572 * @val:  an XPath object
5573 *
5574 * Converts an existing object to its number() equivalent
5575 *
5576 * Returns the new object, the old one is freed (or the operation
5577 *         is done directly on @val)
5578 */
5579xmlXPathObjectPtr
5580xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5581    xmlXPathObjectPtr ret;
5582
5583    if (val == NULL)
5584	return(xmlXPathNewFloat(0.0));
5585    if (val->type == XPATH_NUMBER)
5586	return(val);
5587    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5588    xmlXPathFreeObject(val);
5589    return(ret);
5590}
5591
5592/**
5593 * xmlXPathCastNumberToBoolean:
5594 * @val:  a number
5595 *
5596 * Converts a number to its boolean value
5597 *
5598 * Returns the boolean value
5599 */
5600int
5601xmlXPathCastNumberToBoolean (double val) {
5602     if (xmlXPathIsNaN(val) || (val == 0.0))
5603	 return(0);
5604     return(1);
5605}
5606
5607/**
5608 * xmlXPathCastStringToBoolean:
5609 * @val:  a string
5610 *
5611 * Converts a string to its boolean value
5612 *
5613 * Returns the boolean value
5614 */
5615int
5616xmlXPathCastStringToBoolean (const xmlChar *val) {
5617    if ((val == NULL) || (xmlStrlen(val) == 0))
5618	return(0);
5619    return(1);
5620}
5621
5622/**
5623 * xmlXPathCastNodeSetToBoolean:
5624 * @ns:  a node-set
5625 *
5626 * Converts a node-set to its boolean value
5627 *
5628 * Returns the boolean value
5629 */
5630int
5631xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5632    if ((ns == NULL) || (ns->nodeNr == 0))
5633	return(0);
5634    return(1);
5635}
5636
5637/**
5638 * xmlXPathCastToBoolean:
5639 * @val:  an XPath object
5640 *
5641 * Converts an XPath object to its boolean value
5642 *
5643 * Returns the boolean value
5644 */
5645int
5646xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5647    int ret = 0;
5648
5649    if (val == NULL)
5650	return(0);
5651    switch (val->type) {
5652    case XPATH_UNDEFINED:
5653#ifdef DEBUG_EXPR
5654	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5655#endif
5656	ret = 0;
5657	break;
5658    case XPATH_NODESET:
5659    case XPATH_XSLT_TREE:
5660	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5661	break;
5662    case XPATH_STRING:
5663	ret = xmlXPathCastStringToBoolean(val->stringval);
5664	break;
5665    case XPATH_NUMBER:
5666	ret = xmlXPathCastNumberToBoolean(val->floatval);
5667	break;
5668    case XPATH_BOOLEAN:
5669	ret = val->boolval;
5670	break;
5671    case XPATH_USERS:
5672    case XPATH_POINT:
5673    case XPATH_RANGE:
5674    case XPATH_LOCATIONSET:
5675	TODO;
5676	ret = 0;
5677	break;
5678    }
5679    return(ret);
5680}
5681
5682
5683/**
5684 * xmlXPathConvertBoolean:
5685 * @val:  an XPath object
5686 *
5687 * Converts an existing object to its boolean() equivalent
5688 *
5689 * Returns the new object, the old one is freed (or the operation
5690 *         is done directly on @val)
5691 */
5692xmlXPathObjectPtr
5693xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5694    xmlXPathObjectPtr ret;
5695
5696    if (val == NULL)
5697	return(xmlXPathNewBoolean(0));
5698    if (val->type == XPATH_BOOLEAN)
5699	return(val);
5700    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5701    xmlXPathFreeObject(val);
5702    return(ret);
5703}
5704
5705/************************************************************************
5706 *									*
5707 *		Routines to handle XPath contexts			*
5708 *									*
5709 ************************************************************************/
5710
5711/**
5712 * xmlXPathNewContext:
5713 * @doc:  the XML document
5714 *
5715 * Create a new xmlXPathContext
5716 *
5717 * Returns the xmlXPathContext just allocated. The caller will need to free it.
5718 */
5719xmlXPathContextPtr
5720xmlXPathNewContext(xmlDocPtr doc) {
5721    xmlXPathContextPtr ret;
5722
5723    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5724    if (ret == NULL) {
5725        xmlXPathErrMemory(NULL, "creating context\n");
5726	return(NULL);
5727    }
5728    memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5729    ret->doc = doc;
5730    ret->node = NULL;
5731
5732    ret->varHash = NULL;
5733
5734    ret->nb_types = 0;
5735    ret->max_types = 0;
5736    ret->types = NULL;
5737
5738    ret->funcHash = xmlHashCreate(0);
5739
5740    ret->nb_axis = 0;
5741    ret->max_axis = 0;
5742    ret->axis = NULL;
5743
5744    ret->nsHash = NULL;
5745    ret->user = NULL;
5746
5747    ret->contextSize = -1;
5748    ret->proximityPosition = -1;
5749
5750#ifdef XP_DEFAULT_CACHE_ON
5751    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
5752	xmlXPathFreeContext(ret);
5753	return(NULL);
5754    }
5755#endif
5756
5757    xmlXPathRegisterAllFunctions(ret);
5758
5759    return(ret);
5760}
5761
5762/**
5763 * xmlXPathFreeContext:
5764 * @ctxt:  the context to free
5765 *
5766 * Free up an xmlXPathContext
5767 */
5768void
5769xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
5770    if (ctxt == NULL) return;
5771
5772    if (ctxt->cache != NULL)
5773	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
5774    xmlXPathRegisteredNsCleanup(ctxt);
5775    xmlXPathRegisteredFuncsCleanup(ctxt);
5776    xmlXPathRegisteredVariablesCleanup(ctxt);
5777    xmlResetError(&ctxt->lastError);
5778    xmlFree(ctxt);
5779}
5780
5781/************************************************************************
5782 *									*
5783 *		Routines to handle XPath parser contexts		*
5784 *									*
5785 ************************************************************************/
5786
5787#define CHECK_CTXT(ctxt)						\
5788    if (ctxt == NULL) { 						\
5789	__xmlRaiseError(NULL, NULL, NULL,				\
5790		NULL, NULL, XML_FROM_XPATH,				\
5791		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
5792		__FILE__, __LINE__,					\
5793		NULL, NULL, NULL, 0, 0,					\
5794		"NULL context pointer\n");				\
5795	return(NULL);							\
5796    }									\
5797
5798
5799#define CHECK_CONTEXT(ctxt)						\
5800    if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
5801        (ctxt->doc->children == NULL)) { 				\
5802	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
5803	return(NULL);							\
5804    }
5805
5806
5807/**
5808 * xmlXPathNewParserContext:
5809 * @str:  the XPath expression
5810 * @ctxt:  the XPath context
5811 *
5812 * Create a new xmlXPathParserContext
5813 *
5814 * Returns the xmlXPathParserContext just allocated.
5815 */
5816xmlXPathParserContextPtr
5817xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5818    xmlXPathParserContextPtr ret;
5819
5820    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5821    if (ret == NULL) {
5822        xmlXPathErrMemory(ctxt, "creating parser context\n");
5823	return(NULL);
5824    }
5825    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
5826    ret->cur = ret->base = str;
5827    ret->context = ctxt;
5828
5829    ret->comp = xmlXPathNewCompExpr();
5830    if (ret->comp == NULL) {
5831	xmlFree(ret->valueTab);
5832	xmlFree(ret);
5833	return(NULL);
5834    }
5835    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5836        ret->comp->dict = ctxt->dict;
5837	xmlDictReference(ret->comp->dict);
5838    }
5839
5840    return(ret);
5841}
5842
5843/**
5844 * xmlXPathCompParserContext:
5845 * @comp:  the XPath compiled expression
5846 * @ctxt:  the XPath context
5847 *
5848 * Create a new xmlXPathParserContext when processing a compiled expression
5849 *
5850 * Returns the xmlXPathParserContext just allocated.
5851 */
5852static xmlXPathParserContextPtr
5853xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5854    xmlXPathParserContextPtr ret;
5855
5856    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5857    if (ret == NULL) {
5858        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
5859	return(NULL);
5860    }
5861    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
5862
5863    /* Allocate the value stack */
5864    ret->valueTab = (xmlXPathObjectPtr *)
5865                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
5866    if (ret->valueTab == NULL) {
5867	xmlFree(ret);
5868	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
5869	return(NULL);
5870    }
5871    ret->valueNr = 0;
5872    ret->valueMax = 10;
5873    ret->value = NULL;
5874
5875    ret->context = ctxt;
5876    ret->comp = comp;
5877
5878    return(ret);
5879}
5880
5881/**
5882 * xmlXPathFreeParserContext:
5883 * @ctxt:  the context to free
5884 *
5885 * Free up an xmlXPathParserContext
5886 */
5887void
5888xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5889    if (ctxt->valueTab != NULL) {
5890        xmlFree(ctxt->valueTab);
5891    }
5892    if (ctxt->comp != NULL) {
5893#ifdef XPATH_STREAMING
5894	if (ctxt->comp->stream != NULL) {
5895	    xmlFreePatternList(ctxt->comp->stream);
5896	    ctxt->comp->stream = NULL;
5897	}
5898#endif
5899	xmlXPathFreeCompExpr(ctxt->comp);
5900    }
5901    xmlFree(ctxt);
5902}
5903
5904/************************************************************************
5905 *									*
5906 *		The implicit core function library			*
5907 *									*
5908 ************************************************************************/
5909
5910/**
5911 * xmlXPathNodeValHash:
5912 * @node:  a node pointer
5913 *
5914 * Function computing the beginning of the string value of the node,
5915 * used to speed up comparisons
5916 *
5917 * Returns an int usable as a hash
5918 */
5919static unsigned int
5920xmlXPathNodeValHash(xmlNodePtr node) {
5921    int len = 2;
5922    const xmlChar * string = NULL;
5923    xmlNodePtr tmp = NULL;
5924    unsigned int ret = 0;
5925
5926    if (node == NULL)
5927	return(0);
5928
5929    if (node->type == XML_DOCUMENT_NODE) {
5930	tmp = xmlDocGetRootElement((xmlDocPtr) node);
5931	if (tmp == NULL)
5932	    node = node->children;
5933	else
5934	    node = tmp;
5935
5936	if (node == NULL)
5937	    return(0);
5938    }
5939
5940    switch (node->type) {
5941	case XML_COMMENT_NODE:
5942	case XML_PI_NODE:
5943	case XML_CDATA_SECTION_NODE:
5944	case XML_TEXT_NODE:
5945	    string = node->content;
5946	    if (string == NULL)
5947		return(0);
5948	    if (string[0] == 0)
5949		return(0);
5950	    return(((unsigned int) string[0]) +
5951		   (((unsigned int) string[1]) << 8));
5952	case XML_NAMESPACE_DECL:
5953	    string = ((xmlNsPtr)node)->href;
5954	    if (string == NULL)
5955		return(0);
5956	    if (string[0] == 0)
5957		return(0);
5958	    return(((unsigned int) string[0]) +
5959		   (((unsigned int) string[1]) << 8));
5960	case XML_ATTRIBUTE_NODE:
5961	    tmp = ((xmlAttrPtr) node)->children;
5962	    break;
5963	case XML_ELEMENT_NODE:
5964	    tmp = node->children;
5965	    break;
5966	default:
5967	    return(0);
5968    }
5969    while (tmp != NULL) {
5970	switch (tmp->type) {
5971	    case XML_COMMENT_NODE:
5972	    case XML_PI_NODE:
5973	    case XML_CDATA_SECTION_NODE:
5974	    case XML_TEXT_NODE:
5975		string = tmp->content;
5976		break;
5977	    case XML_NAMESPACE_DECL:
5978		string = ((xmlNsPtr)tmp)->href;
5979		break;
5980	    default:
5981		break;
5982	}
5983	if ((string != NULL) && (string[0] != 0)) {
5984	    if (len == 1) {
5985		return(ret + (((unsigned int) string[0]) << 8));
5986	    }
5987	    if (string[1] == 0) {
5988		len = 1;
5989		ret = (unsigned int) string[0];
5990	    } else {
5991		return(((unsigned int) string[0]) +
5992		       (((unsigned int) string[1]) << 8));
5993	    }
5994	}
5995	/*
5996	 * Skip to next node
5997	 */
5998	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
5999	    if (tmp->children->type != XML_ENTITY_DECL) {
6000		tmp = tmp->children;
6001		continue;
6002	    }
6003	}
6004	if (tmp == node)
6005	    break;
6006
6007	if (tmp->next != NULL) {
6008	    tmp = tmp->next;
6009	    continue;
6010	}
6011
6012	do {
6013	    tmp = tmp->parent;
6014	    if (tmp == NULL)
6015		break;
6016	    if (tmp == node) {
6017		tmp = NULL;
6018		break;
6019	    }
6020	    if (tmp->next != NULL) {
6021		tmp = tmp->next;
6022		break;
6023	    }
6024	} while (tmp != NULL);
6025    }
6026    return(ret);
6027}
6028
6029/**
6030 * xmlXPathStringHash:
6031 * @string:  a string
6032 *
6033 * Function computing the beginning of the string value of the node,
6034 * used to speed up comparisons
6035 *
6036 * Returns an int usable as a hash
6037 */
6038static unsigned int
6039xmlXPathStringHash(const xmlChar * string) {
6040    if (string == NULL)
6041	return((unsigned int) 0);
6042    if (string[0] == 0)
6043	return(0);
6044    return(((unsigned int) string[0]) +
6045	   (((unsigned int) string[1]) << 8));
6046}
6047
6048/**
6049 * xmlXPathCompareNodeSetFloat:
6050 * @ctxt:  the XPath Parser context
6051 * @inf:  less than (1) or greater than (0)
6052 * @strict:  is the comparison strict
6053 * @arg:  the node set
6054 * @f:  the value
6055 *
6056 * Implement the compare operation between a nodeset and a number
6057 *     @ns < @val    (1, 1, ...
6058 *     @ns <= @val   (1, 0, ...
6059 *     @ns > @val    (0, 1, ...
6060 *     @ns >= @val   (0, 0, ...
6061 *
6062 * If one object to be compared is a node-set and the other is a number,
6063 * then the comparison will be true if and only if there is a node in the
6064 * node-set such that the result of performing the comparison on the number
6065 * to be compared and on the result of converting the string-value of that
6066 * node to a number using the number function is true.
6067 *
6068 * Returns 0 or 1 depending on the results of the test.
6069 */
6070static int
6071xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6072	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6073    int i, ret = 0;
6074    xmlNodeSetPtr ns;
6075    xmlChar *str2;
6076
6077    if ((f == NULL) || (arg == NULL) ||
6078	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6079	xmlXPathReleaseObject(ctxt->context, arg);
6080	xmlXPathReleaseObject(ctxt->context, f);
6081        return(0);
6082    }
6083    ns = arg->nodesetval;
6084    if (ns != NULL) {
6085	for (i = 0;i < ns->nodeNr;i++) {
6086	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6087	     if (str2 != NULL) {
6088		 valuePush(ctxt,
6089			   xmlXPathCacheNewString(ctxt->context, str2));
6090		 xmlFree(str2);
6091		 xmlXPathNumberFunction(ctxt, 1);
6092		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6093		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6094		 if (ret)
6095		     break;
6096	     }
6097	}
6098    }
6099    xmlXPathReleaseObject(ctxt->context, arg);
6100    xmlXPathReleaseObject(ctxt->context, f);
6101    return(ret);
6102}
6103
6104/**
6105 * xmlXPathCompareNodeSetString:
6106 * @ctxt:  the XPath Parser context
6107 * @inf:  less than (1) or greater than (0)
6108 * @strict:  is the comparison strict
6109 * @arg:  the node set
6110 * @s:  the value
6111 *
6112 * Implement the compare operation between a nodeset and a string
6113 *     @ns < @val    (1, 1, ...
6114 *     @ns <= @val   (1, 0, ...
6115 *     @ns > @val    (0, 1, ...
6116 *     @ns >= @val   (0, 0, ...
6117 *
6118 * If one object to be compared is a node-set and the other is a string,
6119 * then the comparison will be true if and only if there is a node in
6120 * the node-set such that the result of performing the comparison on the
6121 * string-value of the node and the other string is true.
6122 *
6123 * Returns 0 or 1 depending on the results of the test.
6124 */
6125static int
6126xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6127	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6128    int i, ret = 0;
6129    xmlNodeSetPtr ns;
6130    xmlChar *str2;
6131
6132    if ((s == NULL) || (arg == NULL) ||
6133	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6134	xmlXPathReleaseObject(ctxt->context, arg);
6135	xmlXPathReleaseObject(ctxt->context, s);
6136        return(0);
6137    }
6138    ns = arg->nodesetval;
6139    if (ns != NULL) {
6140	for (i = 0;i < ns->nodeNr;i++) {
6141	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6142	     if (str2 != NULL) {
6143		 valuePush(ctxt,
6144			   xmlXPathCacheNewString(ctxt->context, str2));
6145		 xmlFree(str2);
6146		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6147		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6148		 if (ret)
6149		     break;
6150	     }
6151	}
6152    }
6153    xmlXPathReleaseObject(ctxt->context, arg);
6154    xmlXPathReleaseObject(ctxt->context, s);
6155    return(ret);
6156}
6157
6158/**
6159 * xmlXPathCompareNodeSets:
6160 * @inf:  less than (1) or greater than (0)
6161 * @strict:  is the comparison strict
6162 * @arg1:  the first node set object
6163 * @arg2:  the second node set object
6164 *
6165 * Implement the compare operation on nodesets:
6166 *
6167 * If both objects to be compared are node-sets, then the comparison
6168 * will be true if and only if there is a node in the first node-set
6169 * and a node in the second node-set such that the result of performing
6170 * the comparison on the string-values of the two nodes is true.
6171 * ....
6172 * When neither object to be compared is a node-set and the operator
6173 * is <=, <, >= or >, then the objects are compared by converting both
6174 * objects to numbers and comparing the numbers according to IEEE 754.
6175 * ....
6176 * The number function converts its argument to a number as follows:
6177 *  - a string that consists of optional whitespace followed by an
6178 *    optional minus sign followed by a Number followed by whitespace
6179 *    is converted to the IEEE 754 number that is nearest (according
6180 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6181 *    represented by the string; any other string is converted to NaN
6182 *
6183 * Conclusion all nodes need to be converted first to their string value
6184 * and then the comparison must be done when possible
6185 */
6186static int
6187xmlXPathCompareNodeSets(int inf, int strict,
6188	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6189    int i, j, init = 0;
6190    double val1;
6191    double *values2;
6192    int ret = 0;
6193    xmlNodeSetPtr ns1;
6194    xmlNodeSetPtr ns2;
6195
6196    if ((arg1 == NULL) ||
6197	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6198	xmlXPathFreeObject(arg2);
6199        return(0);
6200    }
6201    if ((arg2 == NULL) ||
6202	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6203	xmlXPathFreeObject(arg1);
6204	xmlXPathFreeObject(arg2);
6205        return(0);
6206    }
6207
6208    ns1 = arg1->nodesetval;
6209    ns2 = arg2->nodesetval;
6210
6211    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6212	xmlXPathFreeObject(arg1);
6213	xmlXPathFreeObject(arg2);
6214	return(0);
6215    }
6216    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6217	xmlXPathFreeObject(arg1);
6218	xmlXPathFreeObject(arg2);
6219	return(0);
6220    }
6221
6222    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6223    if (values2 == NULL) {
6224        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6225	xmlXPathFreeObject(arg1);
6226	xmlXPathFreeObject(arg2);
6227	return(0);
6228    }
6229    for (i = 0;i < ns1->nodeNr;i++) {
6230	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6231	if (xmlXPathIsNaN(val1))
6232	    continue;
6233	for (j = 0;j < ns2->nodeNr;j++) {
6234	    if (init == 0) {
6235		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6236	    }
6237	    if (xmlXPathIsNaN(values2[j]))
6238		continue;
6239	    if (inf && strict)
6240		ret = (val1 < values2[j]);
6241	    else if (inf && !strict)
6242		ret = (val1 <= values2[j]);
6243	    else if (!inf && strict)
6244		ret = (val1 > values2[j]);
6245	    else if (!inf && !strict)
6246		ret = (val1 >= values2[j]);
6247	    if (ret)
6248		break;
6249	}
6250	if (ret)
6251	    break;
6252	init = 1;
6253    }
6254    xmlFree(values2);
6255    xmlXPathFreeObject(arg1);
6256    xmlXPathFreeObject(arg2);
6257    return(ret);
6258}
6259
6260/**
6261 * xmlXPathCompareNodeSetValue:
6262 * @ctxt:  the XPath Parser context
6263 * @inf:  less than (1) or greater than (0)
6264 * @strict:  is the comparison strict
6265 * @arg:  the node set
6266 * @val:  the value
6267 *
6268 * Implement the compare operation between a nodeset and a value
6269 *     @ns < @val    (1, 1, ...
6270 *     @ns <= @val   (1, 0, ...
6271 *     @ns > @val    (0, 1, ...
6272 *     @ns >= @val   (0, 0, ...
6273 *
6274 * If one object to be compared is a node-set and the other is a boolean,
6275 * then the comparison will be true if and only if the result of performing
6276 * the comparison on the boolean and on the result of converting
6277 * the node-set to a boolean using the boolean function is true.
6278 *
6279 * Returns 0 or 1 depending on the results of the test.
6280 */
6281static int
6282xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6283	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6284    if ((val == NULL) || (arg == NULL) ||
6285	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6286        return(0);
6287
6288    switch(val->type) {
6289        case XPATH_NUMBER:
6290	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6291        case XPATH_NODESET:
6292        case XPATH_XSLT_TREE:
6293	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6294        case XPATH_STRING:
6295	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6296        case XPATH_BOOLEAN:
6297	    valuePush(ctxt, arg);
6298	    xmlXPathBooleanFunction(ctxt, 1);
6299	    valuePush(ctxt, val);
6300	    return(xmlXPathCompareValues(ctxt, inf, strict));
6301	default:
6302	    TODO
6303    }
6304    return(0);
6305}
6306
6307/**
6308 * xmlXPathEqualNodeSetString:
6309 * @arg:  the nodeset object argument
6310 * @str:  the string to compare to.
6311 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6312 *
6313 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6314 * If one object to be compared is a node-set and the other is a string,
6315 * then the comparison will be true if and only if there is a node in
6316 * the node-set such that the result of performing the comparison on the
6317 * string-value of the node and the other string is true.
6318 *
6319 * Returns 0 or 1 depending on the results of the test.
6320 */
6321static int
6322xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6323{
6324    int i;
6325    xmlNodeSetPtr ns;
6326    xmlChar *str2;
6327    unsigned int hash;
6328
6329    if ((str == NULL) || (arg == NULL) ||
6330        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6331        return (0);
6332    ns = arg->nodesetval;
6333    /*
6334     * A NULL nodeset compared with a string is always false
6335     * (since there is no node equal, and no node not equal)
6336     */
6337    if ((ns == NULL) || (ns->nodeNr <= 0) )
6338        return (0);
6339    hash = xmlXPathStringHash(str);
6340    for (i = 0; i < ns->nodeNr; i++) {
6341        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6342            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6343            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6344                xmlFree(str2);
6345		if (neq)
6346		    continue;
6347                return (1);
6348	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6349		if (neq)
6350		    continue;
6351                return (1);
6352            } else if (neq) {
6353		if (str2 != NULL)
6354		    xmlFree(str2);
6355		return (1);
6356	    }
6357            if (str2 != NULL)
6358                xmlFree(str2);
6359        } else if (neq)
6360	    return (1);
6361    }
6362    return (0);
6363}
6364
6365/**
6366 * xmlXPathEqualNodeSetFloat:
6367 * @arg:  the nodeset object argument
6368 * @f:  the float to compare to
6369 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6370 *
6371 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6372 * If one object to be compared is a node-set and the other is a number,
6373 * then the comparison will be true if and only if there is a node in
6374 * the node-set such that the result of performing the comparison on the
6375 * number to be compared and on the result of converting the string-value
6376 * of that node to a number using the number function is true.
6377 *
6378 * Returns 0 or 1 depending on the results of the test.
6379 */
6380static int
6381xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6382    xmlXPathObjectPtr arg, double f, int neq) {
6383  int i, ret=0;
6384  xmlNodeSetPtr ns;
6385  xmlChar *str2;
6386  xmlXPathObjectPtr val;
6387  double v;
6388
6389    if ((arg == NULL) ||
6390	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6391        return(0);
6392
6393    ns = arg->nodesetval;
6394    if (ns != NULL) {
6395	for (i=0;i<ns->nodeNr;i++) {
6396	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6397	    if (str2 != NULL) {
6398		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6399		xmlFree(str2);
6400		xmlXPathNumberFunction(ctxt, 1);
6401		val = valuePop(ctxt);
6402		v = val->floatval;
6403		xmlXPathReleaseObject(ctxt->context, val);
6404		if (!xmlXPathIsNaN(v)) {
6405		    if ((!neq) && (v==f)) {
6406			ret = 1;
6407			break;
6408		    } else if ((neq) && (v!=f)) {
6409			ret = 1;
6410			break;
6411		    }
6412		} else {	/* NaN is unequal to any value */
6413		    if (neq)
6414			ret = 1;
6415		}
6416	    }
6417	}
6418    }
6419
6420    return(ret);
6421}
6422
6423
6424/**
6425 * xmlXPathEqualNodeSets:
6426 * @arg1:  first nodeset object argument
6427 * @arg2:  second nodeset object argument
6428 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6429 *
6430 * Implement the equal / not equal operation on XPath nodesets:
6431 * @arg1 == @arg2  or  @arg1 != @arg2
6432 * If both objects to be compared are node-sets, then the comparison
6433 * will be true if and only if there is a node in the first node-set and
6434 * a node in the second node-set such that the result of performing the
6435 * comparison on the string-values of the two nodes is true.
6436 *
6437 * (needless to say, this is a costly operation)
6438 *
6439 * Returns 0 or 1 depending on the results of the test.
6440 */
6441static int
6442xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6443    int i, j;
6444    unsigned int *hashs1;
6445    unsigned int *hashs2;
6446    xmlChar **values1;
6447    xmlChar **values2;
6448    int ret = 0;
6449    xmlNodeSetPtr ns1;
6450    xmlNodeSetPtr ns2;
6451
6452    if ((arg1 == NULL) ||
6453	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6454        return(0);
6455    if ((arg2 == NULL) ||
6456	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6457        return(0);
6458
6459    ns1 = arg1->nodesetval;
6460    ns2 = arg2->nodesetval;
6461
6462    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6463	return(0);
6464    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6465	return(0);
6466
6467    /*
6468     * for equal, check if there is a node pertaining to both sets
6469     */
6470    if (neq == 0)
6471	for (i = 0;i < ns1->nodeNr;i++)
6472	    for (j = 0;j < ns2->nodeNr;j++)
6473		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6474		    return(1);
6475
6476    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6477    if (values1 == NULL) {
6478        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6479	return(0);
6480    }
6481    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6482    if (hashs1 == NULL) {
6483        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6484	xmlFree(values1);
6485	return(0);
6486    }
6487    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6488    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6489    if (values2 == NULL) {
6490        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6491	xmlFree(hashs1);
6492	xmlFree(values1);
6493	return(0);
6494    }
6495    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6496    if (hashs2 == NULL) {
6497        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6498	xmlFree(hashs1);
6499	xmlFree(values1);
6500	xmlFree(values2);
6501	return(0);
6502    }
6503    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6504    for (i = 0;i < ns1->nodeNr;i++) {
6505	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6506	for (j = 0;j < ns2->nodeNr;j++) {
6507	    if (i == 0)
6508		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6509	    if (hashs1[i] != hashs2[j]) {
6510		if (neq) {
6511		    ret = 1;
6512		    break;
6513		}
6514	    }
6515	    else {
6516		if (values1[i] == NULL)
6517		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6518		if (values2[j] == NULL)
6519		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6520		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6521		if (ret)
6522		    break;
6523	    }
6524	}
6525	if (ret)
6526	    break;
6527    }
6528    for (i = 0;i < ns1->nodeNr;i++)
6529	if (values1[i] != NULL)
6530	    xmlFree(values1[i]);
6531    for (j = 0;j < ns2->nodeNr;j++)
6532	if (values2[j] != NULL)
6533	    xmlFree(values2[j]);
6534    xmlFree(values1);
6535    xmlFree(values2);
6536    xmlFree(hashs1);
6537    xmlFree(hashs2);
6538    return(ret);
6539}
6540
6541static int
6542xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6543  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6544    int ret = 0;
6545    /*
6546     *At this point we are assured neither arg1 nor arg2
6547     *is a nodeset, so we can just pick the appropriate routine.
6548     */
6549    switch (arg1->type) {
6550        case XPATH_UNDEFINED:
6551#ifdef DEBUG_EXPR
6552	    xmlGenericError(xmlGenericErrorContext,
6553		    "Equal: undefined\n");
6554#endif
6555	    break;
6556        case XPATH_BOOLEAN:
6557	    switch (arg2->type) {
6558	        case XPATH_UNDEFINED:
6559#ifdef DEBUG_EXPR
6560		    xmlGenericError(xmlGenericErrorContext,
6561			    "Equal: undefined\n");
6562#endif
6563		    break;
6564		case XPATH_BOOLEAN:
6565#ifdef DEBUG_EXPR
6566		    xmlGenericError(xmlGenericErrorContext,
6567			    "Equal: %d boolean %d \n",
6568			    arg1->boolval, arg2->boolval);
6569#endif
6570		    ret = (arg1->boolval == arg2->boolval);
6571		    break;
6572		case XPATH_NUMBER:
6573		    ret = (arg1->boolval ==
6574			   xmlXPathCastNumberToBoolean(arg2->floatval));
6575		    break;
6576		case XPATH_STRING:
6577		    if ((arg2->stringval == NULL) ||
6578			(arg2->stringval[0] == 0)) ret = 0;
6579		    else
6580			ret = 1;
6581		    ret = (arg1->boolval == ret);
6582		    break;
6583		case XPATH_USERS:
6584		case XPATH_POINT:
6585		case XPATH_RANGE:
6586		case XPATH_LOCATIONSET:
6587		    TODO
6588		    break;
6589		case XPATH_NODESET:
6590		case XPATH_XSLT_TREE:
6591		    break;
6592	    }
6593	    break;
6594        case XPATH_NUMBER:
6595	    switch (arg2->type) {
6596	        case XPATH_UNDEFINED:
6597#ifdef DEBUG_EXPR
6598		    xmlGenericError(xmlGenericErrorContext,
6599			    "Equal: undefined\n");
6600#endif
6601		    break;
6602		case XPATH_BOOLEAN:
6603		    ret = (arg2->boolval==
6604			   xmlXPathCastNumberToBoolean(arg1->floatval));
6605		    break;
6606		case XPATH_STRING:
6607		    valuePush(ctxt, arg2);
6608		    xmlXPathNumberFunction(ctxt, 1);
6609		    arg2 = valuePop(ctxt);
6610		    /* no break on purpose */
6611		case XPATH_NUMBER:
6612		    /* Hand check NaN and Infinity equalities */
6613		    if (xmlXPathIsNaN(arg1->floatval) ||
6614		    	    xmlXPathIsNaN(arg2->floatval)) {
6615		        ret = 0;
6616		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6617		        if (xmlXPathIsInf(arg2->floatval) == 1)
6618			    ret = 1;
6619			else
6620			    ret = 0;
6621		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6622			if (xmlXPathIsInf(arg2->floatval) == -1)
6623			    ret = 1;
6624			else
6625			    ret = 0;
6626		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6627			if (xmlXPathIsInf(arg1->floatval) == 1)
6628			    ret = 1;
6629			else
6630			    ret = 0;
6631		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6632			if (xmlXPathIsInf(arg1->floatval) == -1)
6633			    ret = 1;
6634			else
6635			    ret = 0;
6636		    } else {
6637		        ret = (arg1->floatval == arg2->floatval);
6638		    }
6639		    break;
6640		case XPATH_USERS:
6641		case XPATH_POINT:
6642		case XPATH_RANGE:
6643		case XPATH_LOCATIONSET:
6644		    TODO
6645		    break;
6646		case XPATH_NODESET:
6647		case XPATH_XSLT_TREE:
6648		    break;
6649	    }
6650	    break;
6651        case XPATH_STRING:
6652	    switch (arg2->type) {
6653	        case XPATH_UNDEFINED:
6654#ifdef DEBUG_EXPR
6655		    xmlGenericError(xmlGenericErrorContext,
6656			    "Equal: undefined\n");
6657#endif
6658		    break;
6659		case XPATH_BOOLEAN:
6660		    if ((arg1->stringval == NULL) ||
6661			(arg1->stringval[0] == 0)) ret = 0;
6662		    else
6663			ret = 1;
6664		    ret = (arg2->boolval == ret);
6665		    break;
6666		case XPATH_STRING:
6667		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6668		    break;
6669		case XPATH_NUMBER:
6670		    valuePush(ctxt, arg1);
6671		    xmlXPathNumberFunction(ctxt, 1);
6672		    arg1 = valuePop(ctxt);
6673		    /* Hand check NaN and Infinity equalities */
6674		    if (xmlXPathIsNaN(arg1->floatval) ||
6675		    	    xmlXPathIsNaN(arg2->floatval)) {
6676		        ret = 0;
6677		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6678			if (xmlXPathIsInf(arg2->floatval) == 1)
6679			    ret = 1;
6680			else
6681			    ret = 0;
6682		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6683			if (xmlXPathIsInf(arg2->floatval) == -1)
6684			    ret = 1;
6685			else
6686			    ret = 0;
6687		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6688			if (xmlXPathIsInf(arg1->floatval) == 1)
6689			    ret = 1;
6690			else
6691			    ret = 0;
6692		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6693			if (xmlXPathIsInf(arg1->floatval) == -1)
6694			    ret = 1;
6695			else
6696			    ret = 0;
6697		    } else {
6698		        ret = (arg1->floatval == arg2->floatval);
6699		    }
6700		    break;
6701		case XPATH_USERS:
6702		case XPATH_POINT:
6703		case XPATH_RANGE:
6704		case XPATH_LOCATIONSET:
6705		    TODO
6706		    break;
6707		case XPATH_NODESET:
6708		case XPATH_XSLT_TREE:
6709		    break;
6710	    }
6711	    break;
6712        case XPATH_USERS:
6713	case XPATH_POINT:
6714	case XPATH_RANGE:
6715	case XPATH_LOCATIONSET:
6716	    TODO
6717	    break;
6718	case XPATH_NODESET:
6719	case XPATH_XSLT_TREE:
6720	    break;
6721    }
6722    xmlXPathReleaseObject(ctxt->context, arg1);
6723    xmlXPathReleaseObject(ctxt->context, arg2);
6724    return(ret);
6725}
6726
6727/**
6728 * xmlXPathEqualValues:
6729 * @ctxt:  the XPath Parser context
6730 *
6731 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6732 *
6733 * Returns 0 or 1 depending on the results of the test.
6734 */
6735int
6736xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6737    xmlXPathObjectPtr arg1, arg2, argtmp;
6738    int ret = 0;
6739
6740    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6741    arg2 = valuePop(ctxt);
6742    arg1 = valuePop(ctxt);
6743    if ((arg1 == NULL) || (arg2 == NULL)) {
6744	if (arg1 != NULL)
6745	    xmlXPathReleaseObject(ctxt->context, arg1);
6746	else
6747	    xmlXPathReleaseObject(ctxt->context, arg2);
6748	XP_ERROR0(XPATH_INVALID_OPERAND);
6749    }
6750
6751    if (arg1 == arg2) {
6752#ifdef DEBUG_EXPR
6753        xmlGenericError(xmlGenericErrorContext,
6754		"Equal: by pointer\n");
6755#endif
6756	xmlXPathFreeObject(arg1);
6757        return(1);
6758    }
6759
6760    /*
6761     *If either argument is a nodeset, it's a 'special case'
6762     */
6763    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6764      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6765	/*
6766	 *Hack it to assure arg1 is the nodeset
6767	 */
6768	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6769		argtmp = arg2;
6770		arg2 = arg1;
6771		arg1 = argtmp;
6772	}
6773	switch (arg2->type) {
6774	    case XPATH_UNDEFINED:
6775#ifdef DEBUG_EXPR
6776		xmlGenericError(xmlGenericErrorContext,
6777			"Equal: undefined\n");
6778#endif
6779		break;
6780	    case XPATH_NODESET:
6781	    case XPATH_XSLT_TREE:
6782		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
6783		break;
6784	    case XPATH_BOOLEAN:
6785		if ((arg1->nodesetval == NULL) ||
6786		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
6787		else
6788		    ret = 1;
6789		ret = (ret == arg2->boolval);
6790		break;
6791	    case XPATH_NUMBER:
6792		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
6793		break;
6794	    case XPATH_STRING:
6795		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
6796		break;
6797	    case XPATH_USERS:
6798	    case XPATH_POINT:
6799	    case XPATH_RANGE:
6800	    case XPATH_LOCATIONSET:
6801		TODO
6802		break;
6803	}
6804	xmlXPathReleaseObject(ctxt->context, arg1);
6805	xmlXPathReleaseObject(ctxt->context, arg2);
6806	return(ret);
6807    }
6808
6809    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6810}
6811
6812/**
6813 * xmlXPathNotEqualValues:
6814 * @ctxt:  the XPath Parser context
6815 *
6816 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6817 *
6818 * Returns 0 or 1 depending on the results of the test.
6819 */
6820int
6821xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
6822    xmlXPathObjectPtr arg1, arg2, argtmp;
6823    int ret = 0;
6824
6825    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6826    arg2 = valuePop(ctxt);
6827    arg1 = valuePop(ctxt);
6828    if ((arg1 == NULL) || (arg2 == NULL)) {
6829	if (arg1 != NULL)
6830	    xmlXPathReleaseObject(ctxt->context, arg1);
6831	else
6832	    xmlXPathReleaseObject(ctxt->context, arg2);
6833	XP_ERROR0(XPATH_INVALID_OPERAND);
6834    }
6835
6836    if (arg1 == arg2) {
6837#ifdef DEBUG_EXPR
6838        xmlGenericError(xmlGenericErrorContext,
6839		"NotEqual: by pointer\n");
6840#endif
6841	xmlXPathReleaseObject(ctxt->context, arg1);
6842        return(0);
6843    }
6844
6845    /*
6846     *If either argument is a nodeset, it's a 'special case'
6847     */
6848    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6849      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6850	/*
6851	 *Hack it to assure arg1 is the nodeset
6852	 */
6853	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6854		argtmp = arg2;
6855		arg2 = arg1;
6856		arg1 = argtmp;
6857	}
6858	switch (arg2->type) {
6859	    case XPATH_UNDEFINED:
6860#ifdef DEBUG_EXPR
6861		xmlGenericError(xmlGenericErrorContext,
6862			"NotEqual: undefined\n");
6863#endif
6864		break;
6865	    case XPATH_NODESET:
6866	    case XPATH_XSLT_TREE:
6867		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
6868		break;
6869	    case XPATH_BOOLEAN:
6870		if ((arg1->nodesetval == NULL) ||
6871		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
6872		else
6873		    ret = 1;
6874		ret = (ret != arg2->boolval);
6875		break;
6876	    case XPATH_NUMBER:
6877		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6878		break;
6879	    case XPATH_STRING:
6880		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
6881		break;
6882	    case XPATH_USERS:
6883	    case XPATH_POINT:
6884	    case XPATH_RANGE:
6885	    case XPATH_LOCATIONSET:
6886		TODO
6887		break;
6888	}
6889	xmlXPathReleaseObject(ctxt->context, arg1);
6890	xmlXPathReleaseObject(ctxt->context, arg2);
6891	return(ret);
6892    }
6893
6894    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6895}
6896
6897/**
6898 * xmlXPathCompareValues:
6899 * @ctxt:  the XPath Parser context
6900 * @inf:  less than (1) or greater than (0)
6901 * @strict:  is the comparison strict
6902 *
6903 * Implement the compare operation on XPath objects:
6904 *     @arg1 < @arg2    (1, 1, ...
6905 *     @arg1 <= @arg2   (1, 0, ...
6906 *     @arg1 > @arg2    (0, 1, ...
6907 *     @arg1 >= @arg2   (0, 0, ...
6908 *
6909 * When neither object to be compared is a node-set and the operator is
6910 * <=, <, >=, >, then the objects are compared by converted both objects
6911 * to numbers and comparing the numbers according to IEEE 754. The <
6912 * comparison will be true if and only if the first number is less than the
6913 * second number. The <= comparison will be true if and only if the first
6914 * number is less than or equal to the second number. The > comparison
6915 * will be true if and only if the first number is greater than the second
6916 * number. The >= comparison will be true if and only if the first number
6917 * is greater than or equal to the second number.
6918 *
6919 * Returns 1 if the comparison succeeded, 0 if it failed
6920 */
6921int
6922xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
6923    int ret = 0, arg1i = 0, arg2i = 0;
6924    xmlXPathObjectPtr arg1, arg2;
6925
6926    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6927    arg2 = valuePop(ctxt);
6928    arg1 = valuePop(ctxt);
6929    if ((arg1 == NULL) || (arg2 == NULL)) {
6930	if (arg1 != NULL)
6931	    xmlXPathReleaseObject(ctxt->context, arg1);
6932	else
6933	    xmlXPathReleaseObject(ctxt->context, arg2);
6934	XP_ERROR0(XPATH_INVALID_OPERAND);
6935    }
6936
6937    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6938      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6939	/*
6940	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6941	 * are not freed from within this routine; they will be freed from the
6942	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6943	 */
6944	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6945	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
6946	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
6947	} else {
6948	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6949		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6950			                          arg1, arg2);
6951	    } else {
6952		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6953			                          arg2, arg1);
6954	    }
6955	}
6956	return(ret);
6957    }
6958
6959    if (arg1->type != XPATH_NUMBER) {
6960	valuePush(ctxt, arg1);
6961	xmlXPathNumberFunction(ctxt, 1);
6962	arg1 = valuePop(ctxt);
6963    }
6964    if (arg1->type != XPATH_NUMBER) {
6965	xmlXPathFreeObject(arg1);
6966	xmlXPathFreeObject(arg2);
6967	XP_ERROR0(XPATH_INVALID_OPERAND);
6968    }
6969    if (arg2->type != XPATH_NUMBER) {
6970	valuePush(ctxt, arg2);
6971	xmlXPathNumberFunction(ctxt, 1);
6972	arg2 = valuePop(ctxt);
6973    }
6974    if (arg2->type != XPATH_NUMBER) {
6975	xmlXPathReleaseObject(ctxt->context, arg1);
6976	xmlXPathReleaseObject(ctxt->context, arg2);
6977	XP_ERROR0(XPATH_INVALID_OPERAND);
6978    }
6979    /*
6980     * Add tests for infinity and nan
6981     * => feedback on 3.4 for Inf and NaN
6982     */
6983    /* Hand check NaN and Infinity comparisons */
6984    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
6985	ret=0;
6986    } else {
6987	arg1i=xmlXPathIsInf(arg1->floatval);
6988	arg2i=xmlXPathIsInf(arg2->floatval);
6989	if (inf && strict) {
6990	    if ((arg1i == -1 && arg2i != -1) ||
6991		(arg2i == 1 && arg1i != 1)) {
6992		ret = 1;
6993	    } else if (arg1i == 0 && arg2i == 0) {
6994		ret = (arg1->floatval < arg2->floatval);
6995	    } else {
6996		ret = 0;
6997	    }
6998	}
6999	else if (inf && !strict) {
7000	    if (arg1i == -1 || arg2i == 1) {
7001		ret = 1;
7002	    } else if (arg1i == 0 && arg2i == 0) {
7003		ret = (arg1->floatval <= arg2->floatval);
7004	    } else {
7005		ret = 0;
7006	    }
7007	}
7008	else if (!inf && strict) {
7009	    if ((arg1i == 1 && arg2i != 1) ||
7010		(arg2i == -1 && arg1i != -1)) {
7011		ret = 1;
7012	    } else if (arg1i == 0 && arg2i == 0) {
7013		ret = (arg1->floatval > arg2->floatval);
7014	    } else {
7015		ret = 0;
7016	    }
7017	}
7018	else if (!inf && !strict) {
7019	    if (arg1i == 1 || arg2i == -1) {
7020		ret = 1;
7021	    } else if (arg1i == 0 && arg2i == 0) {
7022		ret = (arg1->floatval >= arg2->floatval);
7023	    } else {
7024		ret = 0;
7025	    }
7026	}
7027    }
7028    xmlXPathReleaseObject(ctxt->context, arg1);
7029    xmlXPathReleaseObject(ctxt->context, arg2);
7030    return(ret);
7031}
7032
7033/**
7034 * xmlXPathValueFlipSign:
7035 * @ctxt:  the XPath Parser context
7036 *
7037 * Implement the unary - operation on an XPath object
7038 * The numeric operators convert their operands to numbers as if
7039 * by calling the number function.
7040 */
7041void
7042xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7043    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7044    CAST_TO_NUMBER;
7045    CHECK_TYPE(XPATH_NUMBER);
7046    if (xmlXPathIsNaN(ctxt->value->floatval))
7047        ctxt->value->floatval=xmlXPathNAN;
7048    else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7049        ctxt->value->floatval=xmlXPathNINF;
7050    else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7051        ctxt->value->floatval=xmlXPathPINF;
7052    else if (ctxt->value->floatval == 0) {
7053        if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7054	    ctxt->value->floatval = xmlXPathNZERO;
7055	else
7056	    ctxt->value->floatval = 0;
7057    }
7058    else
7059        ctxt->value->floatval = - ctxt->value->floatval;
7060}
7061
7062/**
7063 * xmlXPathAddValues:
7064 * @ctxt:  the XPath Parser context
7065 *
7066 * Implement the add operation on XPath objects:
7067 * The numeric operators convert their operands to numbers as if
7068 * by calling the number function.
7069 */
7070void
7071xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7072    xmlXPathObjectPtr arg;
7073    double val;
7074
7075    arg = valuePop(ctxt);
7076    if (arg == NULL)
7077	XP_ERROR(XPATH_INVALID_OPERAND);
7078    val = xmlXPathCastToNumber(arg);
7079    xmlXPathReleaseObject(ctxt->context, arg);
7080    CAST_TO_NUMBER;
7081    CHECK_TYPE(XPATH_NUMBER);
7082    ctxt->value->floatval += val;
7083}
7084
7085/**
7086 * xmlXPathSubValues:
7087 * @ctxt:  the XPath Parser context
7088 *
7089 * Implement the subtraction operation on XPath objects:
7090 * The numeric operators convert their operands to numbers as if
7091 * by calling the number function.
7092 */
7093void
7094xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7095    xmlXPathObjectPtr arg;
7096    double val;
7097
7098    arg = valuePop(ctxt);
7099    if (arg == NULL)
7100	XP_ERROR(XPATH_INVALID_OPERAND);
7101    val = xmlXPathCastToNumber(arg);
7102    xmlXPathReleaseObject(ctxt->context, arg);
7103    CAST_TO_NUMBER;
7104    CHECK_TYPE(XPATH_NUMBER);
7105    ctxt->value->floatval -= val;
7106}
7107
7108/**
7109 * xmlXPathMultValues:
7110 * @ctxt:  the XPath Parser context
7111 *
7112 * Implement the multiply operation on XPath objects:
7113 * The numeric operators convert their operands to numbers as if
7114 * by calling the number function.
7115 */
7116void
7117xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7118    xmlXPathObjectPtr arg;
7119    double val;
7120
7121    arg = valuePop(ctxt);
7122    if (arg == NULL)
7123	XP_ERROR(XPATH_INVALID_OPERAND);
7124    val = xmlXPathCastToNumber(arg);
7125    xmlXPathReleaseObject(ctxt->context, arg);
7126    CAST_TO_NUMBER;
7127    CHECK_TYPE(XPATH_NUMBER);
7128    ctxt->value->floatval *= val;
7129}
7130
7131/**
7132 * xmlXPathDivValues:
7133 * @ctxt:  the XPath Parser context
7134 *
7135 * Implement the div operation on XPath objects @arg1 / @arg2:
7136 * The numeric operators convert their operands to numbers as if
7137 * by calling the number function.
7138 */
7139void
7140xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7141    xmlXPathObjectPtr arg;
7142    double val;
7143
7144    arg = valuePop(ctxt);
7145    if (arg == NULL)
7146	XP_ERROR(XPATH_INVALID_OPERAND);
7147    val = xmlXPathCastToNumber(arg);
7148    xmlXPathReleaseObject(ctxt->context, arg);
7149    CAST_TO_NUMBER;
7150    CHECK_TYPE(XPATH_NUMBER);
7151    if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7152	ctxt->value->floatval = xmlXPathNAN;
7153    else if (val == 0 && xmlXPathGetSign(val) != 0) {
7154	if (ctxt->value->floatval == 0)
7155	    ctxt->value->floatval = xmlXPathNAN;
7156	else if (ctxt->value->floatval > 0)
7157	    ctxt->value->floatval = xmlXPathNINF;
7158	else if (ctxt->value->floatval < 0)
7159	    ctxt->value->floatval = xmlXPathPINF;
7160    }
7161    else if (val == 0) {
7162	if (ctxt->value->floatval == 0)
7163	    ctxt->value->floatval = xmlXPathNAN;
7164	else if (ctxt->value->floatval > 0)
7165	    ctxt->value->floatval = xmlXPathPINF;
7166	else if (ctxt->value->floatval < 0)
7167	    ctxt->value->floatval = xmlXPathNINF;
7168    } else
7169	ctxt->value->floatval /= val;
7170}
7171
7172/**
7173 * xmlXPathModValues:
7174 * @ctxt:  the XPath Parser context
7175 *
7176 * Implement the mod operation on XPath objects: @arg1 / @arg2
7177 * The numeric operators convert their operands to numbers as if
7178 * by calling the number function.
7179 */
7180void
7181xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7182    xmlXPathObjectPtr arg;
7183    double arg1, arg2;
7184
7185    arg = valuePop(ctxt);
7186    if (arg == NULL)
7187	XP_ERROR(XPATH_INVALID_OPERAND);
7188    arg2 = xmlXPathCastToNumber(arg);
7189    xmlXPathReleaseObject(ctxt->context, arg);
7190    CAST_TO_NUMBER;
7191    CHECK_TYPE(XPATH_NUMBER);
7192    arg1 = ctxt->value->floatval;
7193    if (arg2 == 0)
7194	ctxt->value->floatval = xmlXPathNAN;
7195    else {
7196	ctxt->value->floatval = fmod(arg1, arg2);
7197    }
7198}
7199
7200/************************************************************************
7201 *									*
7202 *		The traversal functions					*
7203 *									*
7204 ************************************************************************/
7205
7206/*
7207 * A traversal function enumerates nodes along an axis.
7208 * Initially it must be called with NULL, and it indicates
7209 * termination on the axis by returning NULL.
7210 */
7211typedef xmlNodePtr (*xmlXPathTraversalFunction)
7212                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7213
7214/*
7215 * xmlXPathTraversalFunctionExt:
7216 * A traversal function enumerates nodes along an axis.
7217 * Initially it must be called with NULL, and it indicates
7218 * termination on the axis by returning NULL.
7219 * The context node of the traversal is specified via @contextNode.
7220 */
7221typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7222                    (xmlNodePtr cur, xmlNodePtr contextNode);
7223
7224
7225/**
7226 * xmlXPathNextSelf:
7227 * @ctxt:  the XPath Parser context
7228 * @cur:  the current node in the traversal
7229 *
7230 * Traversal function for the "self" direction
7231 * The self axis contains just the context node itself
7232 *
7233 * Returns the next element following that axis
7234 */
7235xmlNodePtr
7236xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7237    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7238    if (cur == NULL)
7239        return(ctxt->context->node);
7240    return(NULL);
7241}
7242
7243/**
7244 * xmlXPathNextChild:
7245 * @ctxt:  the XPath Parser context
7246 * @cur:  the current node in the traversal
7247 *
7248 * Traversal function for the "child" direction
7249 * The child axis contains the children of the context node in document order.
7250 *
7251 * Returns the next element following that axis
7252 */
7253xmlNodePtr
7254xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7255    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7256    if (cur == NULL) {
7257	if (ctxt->context->node == NULL) return(NULL);
7258	switch (ctxt->context->node->type) {
7259            case XML_ELEMENT_NODE:
7260            case XML_TEXT_NODE:
7261            case XML_CDATA_SECTION_NODE:
7262            case XML_ENTITY_REF_NODE:
7263            case XML_ENTITY_NODE:
7264            case XML_PI_NODE:
7265            case XML_COMMENT_NODE:
7266            case XML_NOTATION_NODE:
7267            case XML_DTD_NODE:
7268		return(ctxt->context->node->children);
7269            case XML_DOCUMENT_NODE:
7270            case XML_DOCUMENT_TYPE_NODE:
7271            case XML_DOCUMENT_FRAG_NODE:
7272            case XML_HTML_DOCUMENT_NODE:
7273#ifdef LIBXML_DOCB_ENABLED
7274	    case XML_DOCB_DOCUMENT_NODE:
7275#endif
7276		return(((xmlDocPtr) ctxt->context->node)->children);
7277	    case XML_ELEMENT_DECL:
7278	    case XML_ATTRIBUTE_DECL:
7279	    case XML_ENTITY_DECL:
7280            case XML_ATTRIBUTE_NODE:
7281	    case XML_NAMESPACE_DECL:
7282	    case XML_XINCLUDE_START:
7283	    case XML_XINCLUDE_END:
7284		return(NULL);
7285	}
7286	return(NULL);
7287    }
7288    if ((cur->type == XML_DOCUMENT_NODE) ||
7289        (cur->type == XML_HTML_DOCUMENT_NODE))
7290	return(NULL);
7291    return(cur->next);
7292}
7293
7294/**
7295 * xmlXPathNextChildElement:
7296 * @ctxt:  the XPath Parser context
7297 * @cur:  the current node in the traversal
7298 *
7299 * Traversal function for the "child" direction and nodes of type element.
7300 * The child axis contains the children of the context node in document order.
7301 *
7302 * Returns the next element following that axis
7303 */
7304static xmlNodePtr
7305xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7306    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7307    if (cur == NULL) {
7308	cur = ctxt->context->node;
7309	if (cur == NULL) return(NULL);
7310	/*
7311	* Get the first element child.
7312	*/
7313	switch (cur->type) {
7314            case XML_ELEMENT_NODE:
7315	    case XML_DOCUMENT_FRAG_NODE:
7316	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7317            case XML_ENTITY_NODE:
7318		cur = cur->children;
7319		if (cur != NULL) {
7320		    if (cur->type == XML_ELEMENT_NODE)
7321			return(cur);
7322		    do {
7323			cur = cur->next;
7324		    } while ((cur != NULL) &&
7325			(cur->type != XML_ELEMENT_NODE));
7326		    return(cur);
7327		}
7328		return(NULL);
7329            case XML_DOCUMENT_NODE:
7330            case XML_HTML_DOCUMENT_NODE:
7331#ifdef LIBXML_DOCB_ENABLED
7332	    case XML_DOCB_DOCUMENT_NODE:
7333#endif
7334		return(xmlDocGetRootElement((xmlDocPtr) cur));
7335	    default:
7336		return(NULL);
7337	}
7338	return(NULL);
7339    }
7340    /*
7341    * Get the next sibling element node.
7342    */
7343    switch (cur->type) {
7344	case XML_ELEMENT_NODE:
7345	case XML_TEXT_NODE:
7346	case XML_ENTITY_REF_NODE:
7347	case XML_ENTITY_NODE:
7348	case XML_CDATA_SECTION_NODE:
7349	case XML_PI_NODE:
7350	case XML_COMMENT_NODE:
7351	case XML_XINCLUDE_END:
7352	    break;
7353	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7354	default:
7355	    return(NULL);
7356    }
7357    if (cur->next != NULL) {
7358	if (cur->next->type == XML_ELEMENT_NODE)
7359	    return(cur->next);
7360	cur = cur->next;
7361	do {
7362	    cur = cur->next;
7363	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7364	return(cur);
7365    }
7366    return(NULL);
7367}
7368
7369/**
7370 * xmlXPathNextDescendantOrSelfElemParent:
7371 * @ctxt:  the XPath Parser context
7372 * @cur:  the current node in the traversal
7373 *
7374 * Traversal function for the "descendant-or-self" axis.
7375 * Additionally it returns only nodes which can be parents of
7376 * element nodes.
7377 *
7378 *
7379 * Returns the next element following that axis
7380 */
7381static xmlNodePtr
7382xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7383				       xmlNodePtr contextNode)
7384{
7385    if (cur == NULL) {
7386	if (contextNode == NULL)
7387	    return(NULL);
7388	switch (contextNode->type) {
7389	    case XML_ELEMENT_NODE:
7390	    case XML_XINCLUDE_START:
7391	    case XML_DOCUMENT_FRAG_NODE:
7392	    case XML_DOCUMENT_NODE:
7393#ifdef LIBXML_DOCB_ENABLED
7394	    case XML_DOCB_DOCUMENT_NODE:
7395#endif
7396	    case XML_HTML_DOCUMENT_NODE:
7397		return(contextNode);
7398	    default:
7399		return(NULL);
7400	}
7401	return(NULL);
7402    } else {
7403	xmlNodePtr start = cur;
7404
7405	while (cur != NULL) {
7406	    switch (cur->type) {
7407		case XML_ELEMENT_NODE:
7408		/* TODO: OK to have XInclude here? */
7409		case XML_XINCLUDE_START:
7410		case XML_DOCUMENT_FRAG_NODE:
7411		    if (cur != start)
7412			return(cur);
7413		    if (cur->children != NULL) {
7414			cur = cur->children;
7415			continue;
7416		    }
7417		    break;
7418#ifdef LIBXML_DOCB_ENABLED
7419		/* Not sure if we need those here. */
7420		case XML_DOCUMENT_NODE:
7421		case XML_DOCB_DOCUMENT_NODE:
7422#endif
7423		case XML_HTML_DOCUMENT_NODE:
7424		    if (cur != start)
7425			return(cur);
7426		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7427		default:
7428		    break;
7429	    }
7430
7431next_sibling:
7432	    if ((cur == NULL) || (cur == contextNode))
7433		return(NULL);
7434	    if (cur->next != NULL) {
7435		cur = cur->next;
7436	    } else {
7437		cur = cur->parent;
7438		goto next_sibling;
7439	    }
7440	}
7441    }
7442    return(NULL);
7443}
7444
7445/**
7446 * xmlXPathNextDescendant:
7447 * @ctxt:  the XPath Parser context
7448 * @cur:  the current node in the traversal
7449 *
7450 * Traversal function for the "descendant" direction
7451 * the descendant axis contains the descendants of the context node in document
7452 * order; a descendant is a child or a child of a child and so on.
7453 *
7454 * Returns the next element following that axis
7455 */
7456xmlNodePtr
7457xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7458    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7459    if (cur == NULL) {
7460	if (ctxt->context->node == NULL)
7461	    return(NULL);
7462	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7463	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7464	    return(NULL);
7465
7466        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7467	    return(ctxt->context->doc->children);
7468        return(ctxt->context->node->children);
7469    }
7470
7471    if (cur->children != NULL) {
7472	/*
7473	 * Do not descend on entities declarations
7474	 */
7475    	if (cur->children->type != XML_ENTITY_DECL) {
7476	    cur = cur->children;
7477	    /*
7478	     * Skip DTDs
7479	     */
7480	    if (cur->type != XML_DTD_NODE)
7481		return(cur);
7482	}
7483    }
7484
7485    if (cur == ctxt->context->node) return(NULL);
7486
7487    while (cur->next != NULL) {
7488	cur = cur->next;
7489	if ((cur->type != XML_ENTITY_DECL) &&
7490	    (cur->type != XML_DTD_NODE))
7491	    return(cur);
7492    }
7493
7494    do {
7495        cur = cur->parent;
7496	if (cur == NULL) break;
7497	if (cur == ctxt->context->node) return(NULL);
7498	if (cur->next != NULL) {
7499	    cur = cur->next;
7500	    return(cur);
7501	}
7502    } while (cur != NULL);
7503    return(cur);
7504}
7505
7506/**
7507 * xmlXPathNextDescendantOrSelf:
7508 * @ctxt:  the XPath Parser context
7509 * @cur:  the current node in the traversal
7510 *
7511 * Traversal function for the "descendant-or-self" direction
7512 * the descendant-or-self axis contains the context node and the descendants
7513 * of the context node in document order; thus the context node is the first
7514 * node on the axis, and the first child of the context node is the second node
7515 * on the axis
7516 *
7517 * Returns the next element following that axis
7518 */
7519xmlNodePtr
7520xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7521    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7522    if (cur == NULL) {
7523	if (ctxt->context->node == NULL)
7524	    return(NULL);
7525	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7526	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7527	    return(NULL);
7528        return(ctxt->context->node);
7529    }
7530
7531    return(xmlXPathNextDescendant(ctxt, cur));
7532}
7533
7534/**
7535 * xmlXPathNextParent:
7536 * @ctxt:  the XPath Parser context
7537 * @cur:  the current node in the traversal
7538 *
7539 * Traversal function for the "parent" direction
7540 * The parent axis contains the parent of the context node, if there is one.
7541 *
7542 * Returns the next element following that axis
7543 */
7544xmlNodePtr
7545xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7546    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7547    /*
7548     * the parent of an attribute or namespace node is the element
7549     * to which the attribute or namespace node is attached
7550     * Namespace handling !!!
7551     */
7552    if (cur == NULL) {
7553	if (ctxt->context->node == NULL) return(NULL);
7554	switch (ctxt->context->node->type) {
7555            case XML_ELEMENT_NODE:
7556            case XML_TEXT_NODE:
7557            case XML_CDATA_SECTION_NODE:
7558            case XML_ENTITY_REF_NODE:
7559            case XML_ENTITY_NODE:
7560            case XML_PI_NODE:
7561            case XML_COMMENT_NODE:
7562            case XML_NOTATION_NODE:
7563            case XML_DTD_NODE:
7564	    case XML_ELEMENT_DECL:
7565	    case XML_ATTRIBUTE_DECL:
7566	    case XML_XINCLUDE_START:
7567	    case XML_XINCLUDE_END:
7568	    case XML_ENTITY_DECL:
7569		if (ctxt->context->node->parent == NULL)
7570		    return((xmlNodePtr) ctxt->context->doc);
7571		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7572		    ((ctxt->context->node->parent->name[0] == ' ') ||
7573		     (xmlStrEqual(ctxt->context->node->parent->name,
7574				 BAD_CAST "fake node libxslt"))))
7575		    return(NULL);
7576		return(ctxt->context->node->parent);
7577            case XML_ATTRIBUTE_NODE: {
7578		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7579
7580		return(att->parent);
7581	    }
7582            case XML_DOCUMENT_NODE:
7583            case XML_DOCUMENT_TYPE_NODE:
7584            case XML_DOCUMENT_FRAG_NODE:
7585            case XML_HTML_DOCUMENT_NODE:
7586#ifdef LIBXML_DOCB_ENABLED
7587	    case XML_DOCB_DOCUMENT_NODE:
7588#endif
7589                return(NULL);
7590	    case XML_NAMESPACE_DECL: {
7591		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7592
7593		if ((ns->next != NULL) &&
7594		    (ns->next->type != XML_NAMESPACE_DECL))
7595		    return((xmlNodePtr) ns->next);
7596                return(NULL);
7597	    }
7598	}
7599    }
7600    return(NULL);
7601}
7602
7603/**
7604 * xmlXPathNextAncestor:
7605 * @ctxt:  the XPath Parser context
7606 * @cur:  the current node in the traversal
7607 *
7608 * Traversal function for the "ancestor" direction
7609 * the ancestor axis contains the ancestors of the context node; the ancestors
7610 * of the context node consist of the parent of context node and the parent's
7611 * parent and so on; the nodes are ordered in reverse document order; thus the
7612 * parent is the first node on the axis, and the parent's parent is the second
7613 * node on the axis
7614 *
7615 * Returns the next element following that axis
7616 */
7617xmlNodePtr
7618xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7619    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7620    /*
7621     * the parent of an attribute or namespace node is the element
7622     * to which the attribute or namespace node is attached
7623     * !!!!!!!!!!!!!
7624     */
7625    if (cur == NULL) {
7626	if (ctxt->context->node == NULL) return(NULL);
7627	switch (ctxt->context->node->type) {
7628            case XML_ELEMENT_NODE:
7629            case XML_TEXT_NODE:
7630            case XML_CDATA_SECTION_NODE:
7631            case XML_ENTITY_REF_NODE:
7632            case XML_ENTITY_NODE:
7633            case XML_PI_NODE:
7634            case XML_COMMENT_NODE:
7635	    case XML_DTD_NODE:
7636	    case XML_ELEMENT_DECL:
7637	    case XML_ATTRIBUTE_DECL:
7638	    case XML_ENTITY_DECL:
7639            case XML_NOTATION_NODE:
7640	    case XML_XINCLUDE_START:
7641	    case XML_XINCLUDE_END:
7642		if (ctxt->context->node->parent == NULL)
7643		    return((xmlNodePtr) ctxt->context->doc);
7644		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7645		    ((ctxt->context->node->parent->name[0] == ' ') ||
7646		     (xmlStrEqual(ctxt->context->node->parent->name,
7647				 BAD_CAST "fake node libxslt"))))
7648		    return(NULL);
7649		return(ctxt->context->node->parent);
7650            case XML_ATTRIBUTE_NODE: {
7651		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7652
7653		return(tmp->parent);
7654	    }
7655            case XML_DOCUMENT_NODE:
7656            case XML_DOCUMENT_TYPE_NODE:
7657            case XML_DOCUMENT_FRAG_NODE:
7658            case XML_HTML_DOCUMENT_NODE:
7659#ifdef LIBXML_DOCB_ENABLED
7660	    case XML_DOCB_DOCUMENT_NODE:
7661#endif
7662                return(NULL);
7663	    case XML_NAMESPACE_DECL: {
7664		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7665
7666		if ((ns->next != NULL) &&
7667		    (ns->next->type != XML_NAMESPACE_DECL))
7668		    return((xmlNodePtr) ns->next);
7669		/* Bad, how did that namespace end up here ? */
7670                return(NULL);
7671	    }
7672	}
7673	return(NULL);
7674    }
7675    if (cur == ctxt->context->doc->children)
7676	return((xmlNodePtr) ctxt->context->doc);
7677    if (cur == (xmlNodePtr) ctxt->context->doc)
7678	return(NULL);
7679    switch (cur->type) {
7680	case XML_ELEMENT_NODE:
7681	case XML_TEXT_NODE:
7682	case XML_CDATA_SECTION_NODE:
7683	case XML_ENTITY_REF_NODE:
7684	case XML_ENTITY_NODE:
7685	case XML_PI_NODE:
7686	case XML_COMMENT_NODE:
7687	case XML_NOTATION_NODE:
7688	case XML_DTD_NODE:
7689        case XML_ELEMENT_DECL:
7690        case XML_ATTRIBUTE_DECL:
7691        case XML_ENTITY_DECL:
7692	case XML_XINCLUDE_START:
7693	case XML_XINCLUDE_END:
7694	    if (cur->parent == NULL)
7695		return(NULL);
7696	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
7697		((cur->parent->name[0] == ' ') ||
7698		 (xmlStrEqual(cur->parent->name,
7699			      BAD_CAST "fake node libxslt"))))
7700		return(NULL);
7701	    return(cur->parent);
7702	case XML_ATTRIBUTE_NODE: {
7703	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7704
7705	    return(att->parent);
7706	}
7707	case XML_NAMESPACE_DECL: {
7708	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7709
7710	    if ((ns->next != NULL) &&
7711	        (ns->next->type != XML_NAMESPACE_DECL))
7712	        return((xmlNodePtr) ns->next);
7713	    /* Bad, how did that namespace end up here ? */
7714            return(NULL);
7715	}
7716	case XML_DOCUMENT_NODE:
7717	case XML_DOCUMENT_TYPE_NODE:
7718	case XML_DOCUMENT_FRAG_NODE:
7719	case XML_HTML_DOCUMENT_NODE:
7720#ifdef LIBXML_DOCB_ENABLED
7721	case XML_DOCB_DOCUMENT_NODE:
7722#endif
7723	    return(NULL);
7724    }
7725    return(NULL);
7726}
7727
7728/**
7729 * xmlXPathNextAncestorOrSelf:
7730 * @ctxt:  the XPath Parser context
7731 * @cur:  the current node in the traversal
7732 *
7733 * Traversal function for the "ancestor-or-self" direction
7734 * he ancestor-or-self axis contains the context node and ancestors of
7735 * the context node in reverse document order; thus the context node is
7736 * the first node on the axis, and the context node's parent the second;
7737 * parent here is defined the same as with the parent axis.
7738 *
7739 * Returns the next element following that axis
7740 */
7741xmlNodePtr
7742xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7743    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7744    if (cur == NULL)
7745        return(ctxt->context->node);
7746    return(xmlXPathNextAncestor(ctxt, cur));
7747}
7748
7749/**
7750 * xmlXPathNextFollowingSibling:
7751 * @ctxt:  the XPath Parser context
7752 * @cur:  the current node in the traversal
7753 *
7754 * Traversal function for the "following-sibling" direction
7755 * The following-sibling axis contains the following siblings of the context
7756 * node in document order.
7757 *
7758 * Returns the next element following that axis
7759 */
7760xmlNodePtr
7761xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7762    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7763    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7764	(ctxt->context->node->type == XML_NAMESPACE_DECL))
7765	return(NULL);
7766    if (cur == (xmlNodePtr) ctxt->context->doc)
7767        return(NULL);
7768    if (cur == NULL)
7769        return(ctxt->context->node->next);
7770    return(cur->next);
7771}
7772
7773/**
7774 * xmlXPathNextPrecedingSibling:
7775 * @ctxt:  the XPath Parser context
7776 * @cur:  the current node in the traversal
7777 *
7778 * Traversal function for the "preceding-sibling" direction
7779 * The preceding-sibling axis contains the preceding siblings of the context
7780 * node in reverse document order; the first preceding sibling is first on the
7781 * axis; the sibling preceding that node is the second on the axis and so on.
7782 *
7783 * Returns the next element following that axis
7784 */
7785xmlNodePtr
7786xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7787    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7788    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7789	(ctxt->context->node->type == XML_NAMESPACE_DECL))
7790	return(NULL);
7791    if (cur == (xmlNodePtr) ctxt->context->doc)
7792        return(NULL);
7793    if (cur == NULL)
7794        return(ctxt->context->node->prev);
7795    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
7796	cur = cur->prev;
7797	if (cur == NULL)
7798	    return(ctxt->context->node->prev);
7799    }
7800    return(cur->prev);
7801}
7802
7803/**
7804 * xmlXPathNextFollowing:
7805 * @ctxt:  the XPath Parser context
7806 * @cur:  the current node in the traversal
7807 *
7808 * Traversal function for the "following" direction
7809 * The following axis contains all nodes in the same document as the context
7810 * node that are after the context node in document order, excluding any
7811 * descendants and excluding attribute nodes and namespace nodes; the nodes
7812 * are ordered in document order
7813 *
7814 * Returns the next element following that axis
7815 */
7816xmlNodePtr
7817xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7818    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7819    if (cur != NULL && cur->children != NULL)
7820        return cur->children ;
7821    if (cur == NULL) cur = ctxt->context->node;
7822    if (cur == NULL) return(NULL) ; /* ERROR */
7823    if (cur->next != NULL) return(cur->next) ;
7824    do {
7825        cur = cur->parent;
7826        if (cur == NULL) break;
7827        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
7828        if (cur->next != NULL) return(cur->next);
7829    } while (cur != NULL);
7830    return(cur);
7831}
7832
7833/*
7834 * xmlXPathIsAncestor:
7835 * @ancestor:  the ancestor node
7836 * @node:  the current node
7837 *
7838 * Check that @ancestor is a @node's ancestor
7839 *
7840 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
7841 */
7842static int
7843xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
7844    if ((ancestor == NULL) || (node == NULL)) return(0);
7845    /* nodes need to be in the same document */
7846    if (ancestor->doc != node->doc) return(0);
7847    /* avoid searching if ancestor or node is the root node */
7848    if (ancestor == (xmlNodePtr) node->doc) return(1);
7849    if (node == (xmlNodePtr) ancestor->doc) return(0);
7850    while (node->parent != NULL) {
7851        if (node->parent == ancestor)
7852            return(1);
7853	node = node->parent;
7854    }
7855    return(0);
7856}
7857
7858/**
7859 * xmlXPathNextPreceding:
7860 * @ctxt:  the XPath Parser context
7861 * @cur:  the current node in the traversal
7862 *
7863 * Traversal function for the "preceding" direction
7864 * the preceding axis contains all nodes in the same document as the context
7865 * node that are before the context node in document order, excluding any
7866 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7867 * ordered in reverse document order
7868 *
7869 * Returns the next element following that axis
7870 */
7871xmlNodePtr
7872xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
7873{
7874    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7875    if (cur == NULL)
7876        cur = ctxt->context->node;
7877    if (cur == NULL)
7878	return (NULL);
7879    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7880	cur = cur->prev;
7881    do {
7882        if (cur->prev != NULL) {
7883            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
7884            return (cur);
7885        }
7886
7887        cur = cur->parent;
7888        if (cur == NULL)
7889            return (NULL);
7890        if (cur == ctxt->context->doc->children)
7891            return (NULL);
7892    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
7893    return (cur);
7894}
7895
7896/**
7897 * xmlXPathNextPrecedingInternal:
7898 * @ctxt:  the XPath Parser context
7899 * @cur:  the current node in the traversal
7900 *
7901 * Traversal function for the "preceding" direction
7902 * the preceding axis contains all nodes in the same document as the context
7903 * node that are before the context node in document order, excluding any
7904 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7905 * ordered in reverse document order
7906 * This is a faster implementation but internal only since it requires a
7907 * state kept in the parser context: ctxt->ancestor.
7908 *
7909 * Returns the next element following that axis
7910 */
7911static xmlNodePtr
7912xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
7913                              xmlNodePtr cur)
7914{
7915    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7916    if (cur == NULL) {
7917        cur = ctxt->context->node;
7918        if (cur == NULL)
7919            return (NULL);
7920	if (cur->type == XML_NAMESPACE_DECL)
7921	    cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
7922        ctxt->ancestor = cur->parent;
7923    }
7924    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7925	cur = cur->prev;
7926    while (cur->prev == NULL) {
7927        cur = cur->parent;
7928        if (cur == NULL)
7929            return (NULL);
7930        if (cur == ctxt->context->doc->children)
7931            return (NULL);
7932        if (cur != ctxt->ancestor)
7933            return (cur);
7934        ctxt->ancestor = cur->parent;
7935    }
7936    cur = cur->prev;
7937    while (cur->last != NULL)
7938        cur = cur->last;
7939    return (cur);
7940}
7941
7942/**
7943 * xmlXPathNextNamespace:
7944 * @ctxt:  the XPath Parser context
7945 * @cur:  the current attribute in the traversal
7946 *
7947 * Traversal function for the "namespace" direction
7948 * the namespace axis contains the namespace nodes of the context node;
7949 * the order of nodes on this axis is implementation-defined; the axis will
7950 * be empty unless the context node is an element
7951 *
7952 * We keep the XML namespace node at the end of the list.
7953 *
7954 * Returns the next element following that axis
7955 */
7956xmlNodePtr
7957xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7958    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7959    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
7960    if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
7961        if (ctxt->context->tmpNsList != NULL)
7962	    xmlFree(ctxt->context->tmpNsList);
7963	ctxt->context->tmpNsList =
7964	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
7965	ctxt->context->tmpNsNr = 0;
7966	if (ctxt->context->tmpNsList != NULL) {
7967	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7968		ctxt->context->tmpNsNr++;
7969	    }
7970	}
7971	return((xmlNodePtr) xmlXPathXMLNamespace);
7972    }
7973    if (ctxt->context->tmpNsNr > 0) {
7974	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7975    } else {
7976	if (ctxt->context->tmpNsList != NULL)
7977	    xmlFree(ctxt->context->tmpNsList);
7978	ctxt->context->tmpNsList = NULL;
7979	return(NULL);
7980    }
7981}
7982
7983/**
7984 * xmlXPathNextAttribute:
7985 * @ctxt:  the XPath Parser context
7986 * @cur:  the current attribute in the traversal
7987 *
7988 * Traversal function for the "attribute" direction
7989 * TODO: support DTD inherited default attributes
7990 *
7991 * Returns the next element following that axis
7992 */
7993xmlNodePtr
7994xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7995    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7996    if (ctxt->context->node == NULL)
7997	return(NULL);
7998    if (ctxt->context->node->type != XML_ELEMENT_NODE)
7999	return(NULL);
8000    if (cur == NULL) {
8001        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8002	    return(NULL);
8003        return((xmlNodePtr)ctxt->context->node->properties);
8004    }
8005    return((xmlNodePtr)cur->next);
8006}
8007
8008/************************************************************************
8009 *									*
8010 *		NodeTest Functions					*
8011 *									*
8012 ************************************************************************/
8013
8014#define IS_FUNCTION			200
8015
8016
8017/************************************************************************
8018 *									*
8019 *		Implicit tree core function library			*
8020 *									*
8021 ************************************************************************/
8022
8023/**
8024 * xmlXPathRoot:
8025 * @ctxt:  the XPath Parser context
8026 *
8027 * Initialize the context to the root of the document
8028 */
8029void
8030xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8031    if ((ctxt == NULL) || (ctxt->context == NULL))
8032	return;
8033    ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8034    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8035	ctxt->context->node));
8036}
8037
8038/************************************************************************
8039 *									*
8040 *		The explicit core function library			*
8041 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8042 *									*
8043 ************************************************************************/
8044
8045
8046/**
8047 * xmlXPathLastFunction:
8048 * @ctxt:  the XPath Parser context
8049 * @nargs:  the number of arguments
8050 *
8051 * Implement the last() XPath function
8052 *    number last()
8053 * The last function returns the number of nodes in the context node list.
8054 */
8055void
8056xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8057    CHECK_ARITY(0);
8058    if (ctxt->context->contextSize >= 0) {
8059	valuePush(ctxt,
8060	    xmlXPathCacheNewFloat(ctxt->context,
8061		(double) ctxt->context->contextSize));
8062#ifdef DEBUG_EXPR
8063	xmlGenericError(xmlGenericErrorContext,
8064		"last() : %d\n", ctxt->context->contextSize);
8065#endif
8066    } else {
8067	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8068    }
8069}
8070
8071/**
8072 * xmlXPathPositionFunction:
8073 * @ctxt:  the XPath Parser context
8074 * @nargs:  the number of arguments
8075 *
8076 * Implement the position() XPath function
8077 *    number position()
8078 * The position function returns the position of the context node in the
8079 * context node list. The first position is 1, and so the last position
8080 * will be equal to last().
8081 */
8082void
8083xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8084    CHECK_ARITY(0);
8085    if (ctxt->context->proximityPosition >= 0) {
8086	valuePush(ctxt,
8087	      xmlXPathCacheNewFloat(ctxt->context,
8088		(double) ctxt->context->proximityPosition));
8089#ifdef DEBUG_EXPR
8090	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8091		ctxt->context->proximityPosition);
8092#endif
8093    } else {
8094	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8095    }
8096}
8097
8098/**
8099 * xmlXPathCountFunction:
8100 * @ctxt:  the XPath Parser context
8101 * @nargs:  the number of arguments
8102 *
8103 * Implement the count() XPath function
8104 *    number count(node-set)
8105 */
8106void
8107xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8108    xmlXPathObjectPtr cur;
8109
8110    CHECK_ARITY(1);
8111    if ((ctxt->value == NULL) ||
8112	((ctxt->value->type != XPATH_NODESET) &&
8113	 (ctxt->value->type != XPATH_XSLT_TREE)))
8114	XP_ERROR(XPATH_INVALID_TYPE);
8115    cur = valuePop(ctxt);
8116
8117    if ((cur == NULL) || (cur->nodesetval == NULL))
8118	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8119    else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8120	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8121	    (double) cur->nodesetval->nodeNr));
8122    } else {
8123	if ((cur->nodesetval->nodeNr != 1) ||
8124	    (cur->nodesetval->nodeTab == NULL)) {
8125	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8126	} else {
8127	    xmlNodePtr tmp;
8128	    int i = 0;
8129
8130	    tmp = cur->nodesetval->nodeTab[0];
8131	    if (tmp != NULL) {
8132		tmp = tmp->children;
8133		while (tmp != NULL) {
8134		    tmp = tmp->next;
8135		    i++;
8136		}
8137	    }
8138	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8139	}
8140    }
8141    xmlXPathReleaseObject(ctxt->context, cur);
8142}
8143
8144/**
8145 * xmlXPathGetElementsByIds:
8146 * @doc:  the document
8147 * @ids:  a whitespace separated list of IDs
8148 *
8149 * Selects elements by their unique ID.
8150 *
8151 * Returns a node-set of selected elements.
8152 */
8153static xmlNodeSetPtr
8154xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8155    xmlNodeSetPtr ret;
8156    const xmlChar *cur = ids;
8157    xmlChar *ID;
8158    xmlAttrPtr attr;
8159    xmlNodePtr elem = NULL;
8160
8161    if (ids == NULL) return(NULL);
8162
8163    ret = xmlXPathNodeSetCreate(NULL);
8164
8165    while (IS_BLANK_CH(*cur)) cur++;
8166    while (*cur != 0) {
8167	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8168	    cur++;
8169
8170        ID = xmlStrndup(ids, cur - ids);
8171	if (ID != NULL) {
8172	    /*
8173	     * We used to check the fact that the value passed
8174	     * was an NCName, but this generated much troubles for
8175	     * me and Aleksey Sanin, people blatantly violated that
8176	     * constaint, like Visa3D spec.
8177	     * if (xmlValidateNCName(ID, 1) == 0)
8178	     */
8179	    attr = xmlGetID(doc, ID);
8180	    if (attr != NULL) {
8181		if (attr->type == XML_ATTRIBUTE_NODE)
8182		    elem = attr->parent;
8183		else if (attr->type == XML_ELEMENT_NODE)
8184		    elem = (xmlNodePtr) attr;
8185		else
8186		    elem = NULL;
8187		if (elem != NULL)
8188		    xmlXPathNodeSetAdd(ret, elem);
8189	    }
8190	    xmlFree(ID);
8191	}
8192
8193	while (IS_BLANK_CH(*cur)) cur++;
8194	ids = cur;
8195    }
8196    return(ret);
8197}
8198
8199/**
8200 * xmlXPathIdFunction:
8201 * @ctxt:  the XPath Parser context
8202 * @nargs:  the number of arguments
8203 *
8204 * Implement the id() XPath function
8205 *    node-set id(object)
8206 * The id function selects elements by their unique ID
8207 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8208 * then the result is the union of the result of applying id to the
8209 * string value of each of the nodes in the argument node-set. When the
8210 * argument to id is of any other type, the argument is converted to a
8211 * string as if by a call to the string function; the string is split
8212 * into a whitespace-separated list of tokens (whitespace is any sequence
8213 * of characters matching the production S); the result is a node-set
8214 * containing the elements in the same document as the context node that
8215 * have a unique ID equal to any of the tokens in the list.
8216 */
8217void
8218xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8219    xmlChar *tokens;
8220    xmlNodeSetPtr ret;
8221    xmlXPathObjectPtr obj;
8222
8223    CHECK_ARITY(1);
8224    obj = valuePop(ctxt);
8225    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8226    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8227	xmlNodeSetPtr ns;
8228	int i;
8229
8230	ret = xmlXPathNodeSetCreate(NULL);
8231
8232	if (obj->nodesetval != NULL) {
8233	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8234		tokens =
8235		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8236		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8237		ret = xmlXPathNodeSetMerge(ret, ns);
8238		xmlXPathFreeNodeSet(ns);
8239		if (tokens != NULL)
8240		    xmlFree(tokens);
8241	    }
8242	}
8243	xmlXPathReleaseObject(ctxt->context, obj);
8244	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8245	return;
8246    }
8247    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8248    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8249    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8250    xmlXPathReleaseObject(ctxt->context, obj);
8251    return;
8252}
8253
8254/**
8255 * xmlXPathLocalNameFunction:
8256 * @ctxt:  the XPath Parser context
8257 * @nargs:  the number of arguments
8258 *
8259 * Implement the local-name() XPath function
8260 *    string local-name(node-set?)
8261 * The local-name function returns a string containing the local part
8262 * of the name of the node in the argument node-set that is first in
8263 * document order. If the node-set is empty or the first node has no
8264 * name, an empty string is returned. If the argument is omitted it
8265 * defaults to the context node.
8266 */
8267void
8268xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8269    xmlXPathObjectPtr cur;
8270
8271    if (ctxt == NULL) return;
8272
8273    if (nargs == 0) {
8274	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8275	    ctxt->context->node));
8276	nargs = 1;
8277    }
8278
8279    CHECK_ARITY(1);
8280    if ((ctxt->value == NULL) ||
8281	((ctxt->value->type != XPATH_NODESET) &&
8282	 (ctxt->value->type != XPATH_XSLT_TREE)))
8283	XP_ERROR(XPATH_INVALID_TYPE);
8284    cur = valuePop(ctxt);
8285
8286    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8287	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8288    } else {
8289	int i = 0; /* Should be first in document order !!!!! */
8290	switch (cur->nodesetval->nodeTab[i]->type) {
8291	case XML_ELEMENT_NODE:
8292	case XML_ATTRIBUTE_NODE:
8293	case XML_PI_NODE:
8294	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8295		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8296	    else
8297		valuePush(ctxt,
8298		      xmlXPathCacheNewString(ctxt->context,
8299			cur->nodesetval->nodeTab[i]->name));
8300	    break;
8301	case XML_NAMESPACE_DECL:
8302	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8303			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8304	    break;
8305	default:
8306	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8307	}
8308    }
8309    xmlXPathReleaseObject(ctxt->context, cur);
8310}
8311
8312/**
8313 * xmlXPathNamespaceURIFunction:
8314 * @ctxt:  the XPath Parser context
8315 * @nargs:  the number of arguments
8316 *
8317 * Implement the namespace-uri() XPath function
8318 *    string namespace-uri(node-set?)
8319 * The namespace-uri function returns a string containing the
8320 * namespace URI of the expanded name of the node in the argument
8321 * node-set that is first in document order. If the node-set is empty,
8322 * the first node has no name, or the expanded name has no namespace
8323 * URI, an empty string is returned. If the argument is omitted it
8324 * defaults to the context node.
8325 */
8326void
8327xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8328    xmlXPathObjectPtr cur;
8329
8330    if (ctxt == NULL) return;
8331
8332    if (nargs == 0) {
8333	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8334	    ctxt->context->node));
8335	nargs = 1;
8336    }
8337    CHECK_ARITY(1);
8338    if ((ctxt->value == NULL) ||
8339	((ctxt->value->type != XPATH_NODESET) &&
8340	 (ctxt->value->type != XPATH_XSLT_TREE)))
8341	XP_ERROR(XPATH_INVALID_TYPE);
8342    cur = valuePop(ctxt);
8343
8344    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8345	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8346    } else {
8347	int i = 0; /* Should be first in document order !!!!! */
8348	switch (cur->nodesetval->nodeTab[i]->type) {
8349	case XML_ELEMENT_NODE:
8350	case XML_ATTRIBUTE_NODE:
8351	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8352		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8353	    else
8354		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8355			  cur->nodesetval->nodeTab[i]->ns->href));
8356	    break;
8357	default:
8358	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8359	}
8360    }
8361    xmlXPathReleaseObject(ctxt->context, cur);
8362}
8363
8364/**
8365 * xmlXPathNameFunction:
8366 * @ctxt:  the XPath Parser context
8367 * @nargs:  the number of arguments
8368 *
8369 * Implement the name() XPath function
8370 *    string name(node-set?)
8371 * The name function returns a string containing a QName representing
8372 * the name of the node in the argument node-set that is first in document
8373 * order. The QName must represent the name with respect to the namespace
8374 * declarations in effect on the node whose name is being represented.
8375 * Typically, this will be the form in which the name occurred in the XML
8376 * source. This need not be the case if there are namespace declarations
8377 * in effect on the node that associate multiple prefixes with the same
8378 * namespace. However, an implementation may include information about
8379 * the original prefix in its representation of nodes; in this case, an
8380 * implementation can ensure that the returned string is always the same
8381 * as the QName used in the XML source. If the argument it omitted it
8382 * defaults to the context node.
8383 * Libxml keep the original prefix so the "real qualified name" used is
8384 * returned.
8385 */
8386static void
8387xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8388{
8389    xmlXPathObjectPtr cur;
8390
8391    if (nargs == 0) {
8392	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8393	    ctxt->context->node));
8394        nargs = 1;
8395    }
8396
8397    CHECK_ARITY(1);
8398    if ((ctxt->value == NULL) ||
8399        ((ctxt->value->type != XPATH_NODESET) &&
8400         (ctxt->value->type != XPATH_XSLT_TREE)))
8401        XP_ERROR(XPATH_INVALID_TYPE);
8402    cur = valuePop(ctxt);
8403
8404    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8405        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8406    } else {
8407        int i = 0;              /* Should be first in document order !!!!! */
8408
8409        switch (cur->nodesetval->nodeTab[i]->type) {
8410            case XML_ELEMENT_NODE:
8411            case XML_ATTRIBUTE_NODE:
8412		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8413		    valuePush(ctxt,
8414			xmlXPathCacheNewCString(ctxt->context, ""));
8415		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8416                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8417		    valuePush(ctxt,
8418		        xmlXPathCacheNewString(ctxt->context,
8419			    cur->nodesetval->nodeTab[i]->name));
8420		} else {
8421		    xmlChar *fullname;
8422
8423		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8424				     cur->nodesetval->nodeTab[i]->ns->prefix,
8425				     NULL, 0);
8426		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8427			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8428		    if (fullname == NULL) {
8429			XP_ERROR(XPATH_MEMORY_ERROR);
8430		    }
8431		    valuePush(ctxt, xmlXPathCacheWrapString(
8432			ctxt->context, fullname));
8433                }
8434                break;
8435            default:
8436		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8437		    cur->nodesetval->nodeTab[i]));
8438                xmlXPathLocalNameFunction(ctxt, 1);
8439        }
8440    }
8441    xmlXPathReleaseObject(ctxt->context, cur);
8442}
8443
8444
8445/**
8446 * xmlXPathStringFunction:
8447 * @ctxt:  the XPath Parser context
8448 * @nargs:  the number of arguments
8449 *
8450 * Implement the string() XPath function
8451 *    string string(object?)
8452 * The string function converts an object to a string as follows:
8453 *    - A node-set is converted to a string by returning the value of
8454 *      the node in the node-set that is first in document order.
8455 *      If the node-set is empty, an empty string is returned.
8456 *    - A number is converted to a string as follows
8457 *      + NaN is converted to the string NaN
8458 *      + positive zero is converted to the string 0
8459 *      + negative zero is converted to the string 0
8460 *      + positive infinity is converted to the string Infinity
8461 *      + negative infinity is converted to the string -Infinity
8462 *      + if the number is an integer, the number is represented in
8463 *        decimal form as a Number with no decimal point and no leading
8464 *        zeros, preceded by a minus sign (-) if the number is negative
8465 *      + otherwise, the number is represented in decimal form as a
8466 *        Number including a decimal point with at least one digit
8467 *        before the decimal point and at least one digit after the
8468 *        decimal point, preceded by a minus sign (-) if the number
8469 *        is negative; there must be no leading zeros before the decimal
8470 *        point apart possibly from the one required digit immediately
8471 *        before the decimal point; beyond the one required digit
8472 *        after the decimal point there must be as many, but only as
8473 *        many, more digits as are needed to uniquely distinguish the
8474 *        number from all other IEEE 754 numeric values.
8475 *    - The boolean false value is converted to the string false.
8476 *      The boolean true value is converted to the string true.
8477 *
8478 * If the argument is omitted, it defaults to a node-set with the
8479 * context node as its only member.
8480 */
8481void
8482xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8483    xmlXPathObjectPtr cur;
8484
8485    if (ctxt == NULL) return;
8486    if (nargs == 0) {
8487    valuePush(ctxt,
8488	xmlXPathCacheWrapString(ctxt->context,
8489	    xmlXPathCastNodeToString(ctxt->context->node)));
8490	return;
8491    }
8492
8493    CHECK_ARITY(1);
8494    cur = valuePop(ctxt);
8495    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8496    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8497}
8498
8499/**
8500 * xmlXPathStringLengthFunction:
8501 * @ctxt:  the XPath Parser context
8502 * @nargs:  the number of arguments
8503 *
8504 * Implement the string-length() XPath function
8505 *    number string-length(string?)
8506 * The string-length returns the number of characters in the string
8507 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8508 * the context node converted to a string, in other words the value
8509 * of the context node.
8510 */
8511void
8512xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8513    xmlXPathObjectPtr cur;
8514
8515    if (nargs == 0) {
8516        if ((ctxt == NULL) || (ctxt->context == NULL))
8517	    return;
8518	if (ctxt->context->node == NULL) {
8519	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8520	} else {
8521	    xmlChar *content;
8522
8523	    content = xmlXPathCastNodeToString(ctxt->context->node);
8524	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8525		xmlUTF8Strlen(content)));
8526	    xmlFree(content);
8527	}
8528	return;
8529    }
8530    CHECK_ARITY(1);
8531    CAST_TO_STRING;
8532    CHECK_TYPE(XPATH_STRING);
8533    cur = valuePop(ctxt);
8534    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8535	xmlUTF8Strlen(cur->stringval)));
8536    xmlXPathReleaseObject(ctxt->context, cur);
8537}
8538
8539/**
8540 * xmlXPathConcatFunction:
8541 * @ctxt:  the XPath Parser context
8542 * @nargs:  the number of arguments
8543 *
8544 * Implement the concat() XPath function
8545 *    string concat(string, string, string*)
8546 * The concat function returns the concatenation of its arguments.
8547 */
8548void
8549xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8550    xmlXPathObjectPtr cur, newobj;
8551    xmlChar *tmp;
8552
8553    if (ctxt == NULL) return;
8554    if (nargs < 2) {
8555	CHECK_ARITY(2);
8556    }
8557
8558    CAST_TO_STRING;
8559    cur = valuePop(ctxt);
8560    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8561	xmlXPathReleaseObject(ctxt->context, cur);
8562	return;
8563    }
8564    nargs--;
8565
8566    while (nargs > 0) {
8567	CAST_TO_STRING;
8568	newobj = valuePop(ctxt);
8569	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8570	    xmlXPathReleaseObject(ctxt->context, newobj);
8571	    xmlXPathReleaseObject(ctxt->context, cur);
8572	    XP_ERROR(XPATH_INVALID_TYPE);
8573	}
8574	tmp = xmlStrcat(newobj->stringval, cur->stringval);
8575	newobj->stringval = cur->stringval;
8576	cur->stringval = tmp;
8577	xmlXPathReleaseObject(ctxt->context, newobj);
8578	nargs--;
8579    }
8580    valuePush(ctxt, cur);
8581}
8582
8583/**
8584 * xmlXPathContainsFunction:
8585 * @ctxt:  the XPath Parser context
8586 * @nargs:  the number of arguments
8587 *
8588 * Implement the contains() XPath function
8589 *    boolean contains(string, string)
8590 * The contains function returns true if the first argument string
8591 * contains the second argument string, and otherwise returns false.
8592 */
8593void
8594xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8595    xmlXPathObjectPtr hay, needle;
8596
8597    CHECK_ARITY(2);
8598    CAST_TO_STRING;
8599    CHECK_TYPE(XPATH_STRING);
8600    needle = valuePop(ctxt);
8601    CAST_TO_STRING;
8602    hay = valuePop(ctxt);
8603
8604    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8605	xmlXPathReleaseObject(ctxt->context, hay);
8606	xmlXPathReleaseObject(ctxt->context, needle);
8607	XP_ERROR(XPATH_INVALID_TYPE);
8608    }
8609    if (xmlStrstr(hay->stringval, needle->stringval))
8610	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8611    else
8612	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8613    xmlXPathReleaseObject(ctxt->context, hay);
8614    xmlXPathReleaseObject(ctxt->context, needle);
8615}
8616
8617/**
8618 * xmlXPathStartsWithFunction:
8619 * @ctxt:  the XPath Parser context
8620 * @nargs:  the number of arguments
8621 *
8622 * Implement the starts-with() XPath function
8623 *    boolean starts-with(string, string)
8624 * The starts-with function returns true if the first argument string
8625 * starts with the second argument string, and otherwise returns false.
8626 */
8627void
8628xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8629    xmlXPathObjectPtr hay, needle;
8630    int n;
8631
8632    CHECK_ARITY(2);
8633    CAST_TO_STRING;
8634    CHECK_TYPE(XPATH_STRING);
8635    needle = valuePop(ctxt);
8636    CAST_TO_STRING;
8637    hay = valuePop(ctxt);
8638
8639    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8640	xmlXPathReleaseObject(ctxt->context, hay);
8641	xmlXPathReleaseObject(ctxt->context, needle);
8642	XP_ERROR(XPATH_INVALID_TYPE);
8643    }
8644    n = xmlStrlen(needle->stringval);
8645    if (xmlStrncmp(hay->stringval, needle->stringval, n))
8646        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8647    else
8648        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8649    xmlXPathReleaseObject(ctxt->context, hay);
8650    xmlXPathReleaseObject(ctxt->context, needle);
8651}
8652
8653/**
8654 * xmlXPathSubstringFunction:
8655 * @ctxt:  the XPath Parser context
8656 * @nargs:  the number of arguments
8657 *
8658 * Implement the substring() XPath function
8659 *    string substring(string, number, number?)
8660 * The substring function returns the substring of the first argument
8661 * starting at the position specified in the second argument with
8662 * length specified in the third argument. For example,
8663 * substring("12345",2,3) returns "234". If the third argument is not
8664 * specified, it returns the substring starting at the position specified
8665 * in the second argument and continuing to the end of the string. For
8666 * example, substring("12345",2) returns "2345".  More precisely, each
8667 * character in the string (see [3.6 Strings]) is considered to have a
8668 * numeric position: the position of the first character is 1, the position
8669 * of the second character is 2 and so on. The returned substring contains
8670 * those characters for which the position of the character is greater than
8671 * or equal to the second argument and, if the third argument is specified,
8672 * less than the sum of the second and third arguments; the comparisons
8673 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8674 *  - substring("12345", 1.5, 2.6) returns "234"
8675 *  - substring("12345", 0, 3) returns "12"
8676 *  - substring("12345", 0 div 0, 3) returns ""
8677 *  - substring("12345", 1, 0 div 0) returns ""
8678 *  - substring("12345", -42, 1 div 0) returns "12345"
8679 *  - substring("12345", -1 div 0, 1 div 0) returns ""
8680 */
8681void
8682xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8683    xmlXPathObjectPtr str, start, len;
8684    double le=0, in;
8685    int i, l, m;
8686    xmlChar *ret;
8687
8688    if (nargs < 2) {
8689	CHECK_ARITY(2);
8690    }
8691    if (nargs > 3) {
8692	CHECK_ARITY(3);
8693    }
8694    /*
8695     * take care of possible last (position) argument
8696    */
8697    if (nargs == 3) {
8698	CAST_TO_NUMBER;
8699	CHECK_TYPE(XPATH_NUMBER);
8700	len = valuePop(ctxt);
8701	le = len->floatval;
8702	xmlXPathReleaseObject(ctxt->context, len);
8703    }
8704
8705    CAST_TO_NUMBER;
8706    CHECK_TYPE(XPATH_NUMBER);
8707    start = valuePop(ctxt);
8708    in = start->floatval;
8709    xmlXPathReleaseObject(ctxt->context, start);
8710    CAST_TO_STRING;
8711    CHECK_TYPE(XPATH_STRING);
8712    str = valuePop(ctxt);
8713    m = xmlUTF8Strlen((const unsigned char *)str->stringval);
8714
8715    /*
8716     * If last pos not present, calculate last position
8717    */
8718    if (nargs != 3) {
8719	le = (double)m;
8720	if (in < 1.0)
8721	    in = 1.0;
8722    }
8723
8724    /* Need to check for the special cases where either
8725     * the index is NaN, the length is NaN, or both
8726     * arguments are infinity (relying on Inf + -Inf = NaN)
8727     */
8728    if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
8729        /*
8730         * To meet the requirements of the spec, the arguments
8731	 * must be converted to integer format before
8732	 * initial index calculations are done
8733         *
8734         * First we go to integer form, rounding up
8735	 * and checking for special cases
8736         */
8737        i = (int) in;
8738        if (((double)i)+0.5 <= in) i++;
8739
8740	if (xmlXPathIsInf(le) == 1) {
8741	    l = m;
8742	    if (i < 1)
8743		i = 1;
8744	}
8745	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
8746	    l = 0;
8747	else {
8748	    l = (int) le;
8749	    if (((double)l)+0.5 <= le) l++;
8750	}
8751
8752	/* Now we normalize inidices */
8753        i -= 1;
8754        l += i;
8755        if (i < 0)
8756            i = 0;
8757        if (l > m)
8758            l = m;
8759
8760        /* number of chars to copy */
8761        l -= i;
8762
8763        ret = xmlUTF8Strsub(str->stringval, i, l);
8764    }
8765    else {
8766        ret = NULL;
8767    }
8768    if (ret == NULL)
8769	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8770    else {
8771	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
8772	xmlFree(ret);
8773    }
8774    xmlXPathReleaseObject(ctxt->context, str);
8775}
8776
8777/**
8778 * xmlXPathSubstringBeforeFunction:
8779 * @ctxt:  the XPath Parser context
8780 * @nargs:  the number of arguments
8781 *
8782 * Implement the substring-before() XPath function
8783 *    string substring-before(string, string)
8784 * The substring-before function returns the substring of the first
8785 * argument string that precedes the first occurrence of the second
8786 * argument string in the first argument string, or the empty string
8787 * if the first argument string does not contain the second argument
8788 * string. For example, substring-before("1999/04/01","/") returns 1999.
8789 */
8790void
8791xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8792  xmlXPathObjectPtr str;
8793  xmlXPathObjectPtr find;
8794  xmlBufferPtr target;
8795  const xmlChar *point;
8796  int offset;
8797
8798  CHECK_ARITY(2);
8799  CAST_TO_STRING;
8800  find = valuePop(ctxt);
8801  CAST_TO_STRING;
8802  str = valuePop(ctxt);
8803
8804  target = xmlBufferCreate();
8805  if (target) {
8806    point = xmlStrstr(str->stringval, find->stringval);
8807    if (point) {
8808      offset = (int)(point - str->stringval);
8809      xmlBufferAdd(target, str->stringval, offset);
8810    }
8811    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8812	xmlBufferContent(target)));
8813    xmlBufferFree(target);
8814  }
8815  xmlXPathReleaseObject(ctxt->context, str);
8816  xmlXPathReleaseObject(ctxt->context, find);
8817}
8818
8819/**
8820 * xmlXPathSubstringAfterFunction:
8821 * @ctxt:  the XPath Parser context
8822 * @nargs:  the number of arguments
8823 *
8824 * Implement the substring-after() XPath function
8825 *    string substring-after(string, string)
8826 * The substring-after function returns the substring of the first
8827 * argument string that follows the first occurrence of the second
8828 * argument string in the first argument string, or the empty stringi
8829 * if the first argument string does not contain the second argument
8830 * string. For example, substring-after("1999/04/01","/") returns 04/01,
8831 * and substring-after("1999/04/01","19") returns 99/04/01.
8832 */
8833void
8834xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8835  xmlXPathObjectPtr str;
8836  xmlXPathObjectPtr find;
8837  xmlBufferPtr target;
8838  const xmlChar *point;
8839  int offset;
8840
8841  CHECK_ARITY(2);
8842  CAST_TO_STRING;
8843  find = valuePop(ctxt);
8844  CAST_TO_STRING;
8845  str = valuePop(ctxt);
8846
8847  target = xmlBufferCreate();
8848  if (target) {
8849    point = xmlStrstr(str->stringval, find->stringval);
8850    if (point) {
8851      offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
8852      xmlBufferAdd(target, &str->stringval[offset],
8853		   xmlStrlen(str->stringval) - offset);
8854    }
8855    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8856	xmlBufferContent(target)));
8857    xmlBufferFree(target);
8858  }
8859  xmlXPathReleaseObject(ctxt->context, str);
8860  xmlXPathReleaseObject(ctxt->context, find);
8861}
8862
8863/**
8864 * xmlXPathNormalizeFunction:
8865 * @ctxt:  the XPath Parser context
8866 * @nargs:  the number of arguments
8867 *
8868 * Implement the normalize-space() XPath function
8869 *    string normalize-space(string?)
8870 * The normalize-space function returns the argument string with white
8871 * space normalized by stripping leading and trailing whitespace
8872 * and replacing sequences of whitespace characters by a single
8873 * space. Whitespace characters are the same allowed by the S production
8874 * in XML. If the argument is omitted, it defaults to the context
8875 * node converted to a string, in other words the value of the context node.
8876 */
8877void
8878xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8879  xmlXPathObjectPtr obj = NULL;
8880  xmlChar *source = NULL;
8881  xmlBufferPtr target;
8882  xmlChar blank;
8883
8884  if (ctxt == NULL) return;
8885  if (nargs == 0) {
8886    /* Use current context node */
8887      valuePush(ctxt,
8888	  xmlXPathCacheWrapString(ctxt->context,
8889	    xmlXPathCastNodeToString(ctxt->context->node)));
8890    nargs = 1;
8891  }
8892
8893  CHECK_ARITY(1);
8894  CAST_TO_STRING;
8895  CHECK_TYPE(XPATH_STRING);
8896  obj = valuePop(ctxt);
8897  source = obj->stringval;
8898
8899  target = xmlBufferCreate();
8900  if (target && source) {
8901
8902    /* Skip leading whitespaces */
8903    while (IS_BLANK_CH(*source))
8904      source++;
8905
8906    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
8907    blank = 0;
8908    while (*source) {
8909      if (IS_BLANK_CH(*source)) {
8910	blank = 0x20;
8911      } else {
8912	if (blank) {
8913	  xmlBufferAdd(target, &blank, 1);
8914	  blank = 0;
8915	}
8916	xmlBufferAdd(target, source, 1);
8917      }
8918      source++;
8919    }
8920    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8921	xmlBufferContent(target)));
8922    xmlBufferFree(target);
8923  }
8924  xmlXPathReleaseObject(ctxt->context, obj);
8925}
8926
8927/**
8928 * xmlXPathTranslateFunction:
8929 * @ctxt:  the XPath Parser context
8930 * @nargs:  the number of arguments
8931 *
8932 * Implement the translate() XPath function
8933 *    string translate(string, string, string)
8934 * The translate function returns the first argument string with
8935 * occurrences of characters in the second argument string replaced
8936 * by the character at the corresponding position in the third argument
8937 * string. For example, translate("bar","abc","ABC") returns the string
8938 * BAr. If there is a character in the second argument string with no
8939 * character at a corresponding position in the third argument string
8940 * (because the second argument string is longer than the third argument
8941 * string), then occurrences of that character in the first argument
8942 * string are removed. For example, translate("--aaa--","abc-","ABC")
8943 * returns "AAA". If a character occurs more than once in second
8944 * argument string, then the first occurrence determines the replacement
8945 * character. If the third argument string is longer than the second
8946 * argument string, then excess characters are ignored.
8947 */
8948void
8949xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8950    xmlXPathObjectPtr str;
8951    xmlXPathObjectPtr from;
8952    xmlXPathObjectPtr to;
8953    xmlBufferPtr target;
8954    int offset, max;
8955    xmlChar ch;
8956    const xmlChar *point;
8957    xmlChar *cptr;
8958
8959    CHECK_ARITY(3);
8960
8961    CAST_TO_STRING;
8962    to = valuePop(ctxt);
8963    CAST_TO_STRING;
8964    from = valuePop(ctxt);
8965    CAST_TO_STRING;
8966    str = valuePop(ctxt);
8967
8968    target = xmlBufferCreate();
8969    if (target) {
8970	max = xmlUTF8Strlen(to->stringval);
8971	for (cptr = str->stringval; (ch=*cptr); ) {
8972	    offset = xmlUTF8Strloc(from->stringval, cptr);
8973	    if (offset >= 0) {
8974		if (offset < max) {
8975		    point = xmlUTF8Strpos(to->stringval, offset);
8976		    if (point)
8977			xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
8978		}
8979	    } else
8980		xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8981
8982	    /* Step to next character in input */
8983	    cptr++;
8984	    if ( ch & 0x80 ) {
8985		/* if not simple ascii, verify proper format */
8986		if ( (ch & 0xc0) != 0xc0 ) {
8987		    xmlGenericError(xmlGenericErrorContext,
8988			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
8989		    break;
8990		}
8991		/* then skip over remaining bytes for this char */
8992		while ( (ch <<= 1) & 0x80 )
8993		    if ( (*cptr++ & 0xc0) != 0x80 ) {
8994			xmlGenericError(xmlGenericErrorContext,
8995			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
8996			break;
8997		    }
8998		if (ch & 0x80) /* must have had error encountered */
8999		    break;
9000	    }
9001	}
9002    }
9003    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9004	xmlBufferContent(target)));
9005    xmlBufferFree(target);
9006    xmlXPathReleaseObject(ctxt->context, str);
9007    xmlXPathReleaseObject(ctxt->context, from);
9008    xmlXPathReleaseObject(ctxt->context, to);
9009}
9010
9011/**
9012 * xmlXPathBooleanFunction:
9013 * @ctxt:  the XPath Parser context
9014 * @nargs:  the number of arguments
9015 *
9016 * Implement the boolean() XPath function
9017 *    boolean boolean(object)
9018 * The boolean function converts its argument to a boolean as follows:
9019 *    - a number is true if and only if it is neither positive or
9020 *      negative zero nor NaN
9021 *    - a node-set is true if and only if it is non-empty
9022 *    - a string is true if and only if its length is non-zero
9023 */
9024void
9025xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9026    xmlXPathObjectPtr cur;
9027
9028    CHECK_ARITY(1);
9029    cur = valuePop(ctxt);
9030    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9031    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9032    valuePush(ctxt, cur);
9033}
9034
9035/**
9036 * xmlXPathNotFunction:
9037 * @ctxt:  the XPath Parser context
9038 * @nargs:  the number of arguments
9039 *
9040 * Implement the not() XPath function
9041 *    boolean not(boolean)
9042 * The not function returns true if its argument is false,
9043 * and false otherwise.
9044 */
9045void
9046xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9047    CHECK_ARITY(1);
9048    CAST_TO_BOOLEAN;
9049    CHECK_TYPE(XPATH_BOOLEAN);
9050    ctxt->value->boolval = ! ctxt->value->boolval;
9051}
9052
9053/**
9054 * xmlXPathTrueFunction:
9055 * @ctxt:  the XPath Parser context
9056 * @nargs:  the number of arguments
9057 *
9058 * Implement the true() XPath function
9059 *    boolean true()
9060 */
9061void
9062xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9063    CHECK_ARITY(0);
9064    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9065}
9066
9067/**
9068 * xmlXPathFalseFunction:
9069 * @ctxt:  the XPath Parser context
9070 * @nargs:  the number of arguments
9071 *
9072 * Implement the false() XPath function
9073 *    boolean false()
9074 */
9075void
9076xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9077    CHECK_ARITY(0);
9078    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9079}
9080
9081/**
9082 * xmlXPathLangFunction:
9083 * @ctxt:  the XPath Parser context
9084 * @nargs:  the number of arguments
9085 *
9086 * Implement the lang() XPath function
9087 *    boolean lang(string)
9088 * The lang function returns true or false depending on whether the
9089 * language of the context node as specified by xml:lang attributes
9090 * is the same as or is a sublanguage of the language specified by
9091 * the argument string. The language of the context node is determined
9092 * by the value of the xml:lang attribute on the context node, or, if
9093 * the context node has no xml:lang attribute, by the value of the
9094 * xml:lang attribute on the nearest ancestor of the context node that
9095 * has an xml:lang attribute. If there is no such attribute, then lang
9096 * returns false. If there is such an attribute, then lang returns
9097 * true if the attribute value is equal to the argument ignoring case,
9098 * or if there is some suffix starting with - such that the attribute
9099 * value is equal to the argument ignoring that suffix of the attribute
9100 * value and ignoring case.
9101 */
9102void
9103xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9104    xmlXPathObjectPtr val = NULL;
9105    const xmlChar *theLang = NULL;
9106    const xmlChar *lang;
9107    int ret = 0;
9108    int i;
9109
9110    CHECK_ARITY(1);
9111    CAST_TO_STRING;
9112    CHECK_TYPE(XPATH_STRING);
9113    val = valuePop(ctxt);
9114    lang = val->stringval;
9115    theLang = xmlNodeGetLang(ctxt->context->node);
9116    if ((theLang != NULL) && (lang != NULL)) {
9117        for (i = 0;lang[i] != 0;i++)
9118	    if (toupper(lang[i]) != toupper(theLang[i]))
9119	        goto not_equal;
9120	if ((theLang[i] == 0) || (theLang[i] == '-'))
9121	    ret = 1;
9122    }
9123not_equal:
9124    if (theLang != NULL)
9125	xmlFree((void *)theLang);
9126
9127    xmlXPathReleaseObject(ctxt->context, val);
9128    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9129}
9130
9131/**
9132 * xmlXPathNumberFunction:
9133 * @ctxt:  the XPath Parser context
9134 * @nargs:  the number of arguments
9135 *
9136 * Implement the number() XPath function
9137 *    number number(object?)
9138 */
9139void
9140xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9141    xmlXPathObjectPtr cur;
9142    double res;
9143
9144    if (ctxt == NULL) return;
9145    if (nargs == 0) {
9146	if (ctxt->context->node == NULL) {
9147	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9148	} else {
9149	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9150
9151	    res = xmlXPathStringEvalNumber(content);
9152	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9153	    xmlFree(content);
9154	}
9155	return;
9156    }
9157
9158    CHECK_ARITY(1);
9159    cur = valuePop(ctxt);
9160    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9161}
9162
9163/**
9164 * xmlXPathSumFunction:
9165 * @ctxt:  the XPath Parser context
9166 * @nargs:  the number of arguments
9167 *
9168 * Implement the sum() XPath function
9169 *    number sum(node-set)
9170 * The sum function returns the sum of the values of the nodes in
9171 * the argument node-set.
9172 */
9173void
9174xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9175    xmlXPathObjectPtr cur;
9176    int i;
9177    double res = 0.0;
9178
9179    CHECK_ARITY(1);
9180    if ((ctxt->value == NULL) ||
9181	((ctxt->value->type != XPATH_NODESET) &&
9182	 (ctxt->value->type != XPATH_XSLT_TREE)))
9183	XP_ERROR(XPATH_INVALID_TYPE);
9184    cur = valuePop(ctxt);
9185
9186    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9187	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9188	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9189	}
9190    }
9191    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9192    xmlXPathReleaseObject(ctxt->context, cur);
9193}
9194
9195/*
9196 * To assure working code on multiple platforms, we want to only depend
9197 * upon the characteristic truncation of converting a floating point value
9198 * to an integer.  Unfortunately, because of the different storage sizes
9199 * of our internal floating point value (double) and integer (int), we
9200 * can't directly convert (see bug 301162).  This macro is a messy
9201 * 'workaround'
9202 */
9203#define XTRUNC(f, v)            \
9204    f = fmod((v), INT_MAX);     \
9205    f = (v) - (f) + (double)((int)(f));
9206
9207/**
9208 * xmlXPathFloorFunction:
9209 * @ctxt:  the XPath Parser context
9210 * @nargs:  the number of arguments
9211 *
9212 * Implement the floor() XPath function
9213 *    number floor(number)
9214 * The floor function returns the largest (closest to positive infinity)
9215 * number that is not greater than the argument and that is an integer.
9216 */
9217void
9218xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9219    double f;
9220
9221    CHECK_ARITY(1);
9222    CAST_TO_NUMBER;
9223    CHECK_TYPE(XPATH_NUMBER);
9224
9225    XTRUNC(f, ctxt->value->floatval);
9226    if (f != ctxt->value->floatval) {
9227	if (ctxt->value->floatval > 0)
9228	    ctxt->value->floatval = f;
9229	else
9230	    ctxt->value->floatval = f - 1;
9231    }
9232}
9233
9234/**
9235 * xmlXPathCeilingFunction:
9236 * @ctxt:  the XPath Parser context
9237 * @nargs:  the number of arguments
9238 *
9239 * Implement the ceiling() XPath function
9240 *    number ceiling(number)
9241 * The ceiling function returns the smallest (closest to negative infinity)
9242 * number that is not less than the argument and that is an integer.
9243 */
9244void
9245xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9246    double f;
9247
9248    CHECK_ARITY(1);
9249    CAST_TO_NUMBER;
9250    CHECK_TYPE(XPATH_NUMBER);
9251
9252#if 0
9253    ctxt->value->floatval = ceil(ctxt->value->floatval);
9254#else
9255    XTRUNC(f, ctxt->value->floatval);
9256    if (f != ctxt->value->floatval) {
9257	if (ctxt->value->floatval > 0)
9258	    ctxt->value->floatval = f + 1;
9259	else {
9260	    if (ctxt->value->floatval < 0 && f == 0)
9261	        ctxt->value->floatval = xmlXPathNZERO;
9262	    else
9263	        ctxt->value->floatval = f;
9264	}
9265
9266    }
9267#endif
9268}
9269
9270/**
9271 * xmlXPathRoundFunction:
9272 * @ctxt:  the XPath Parser context
9273 * @nargs:  the number of arguments
9274 *
9275 * Implement the round() XPath function
9276 *    number round(number)
9277 * The round function returns the number that is closest to the
9278 * argument and that is an integer. If there are two such numbers,
9279 * then the one that is even is returned.
9280 */
9281void
9282xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9283    double f;
9284
9285    CHECK_ARITY(1);
9286    CAST_TO_NUMBER;
9287    CHECK_TYPE(XPATH_NUMBER);
9288
9289    if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9290	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9291	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9292	(ctxt->value->floatval == 0.0))
9293	return;
9294
9295    XTRUNC(f, ctxt->value->floatval);
9296    if (ctxt->value->floatval < 0) {
9297	if (ctxt->value->floatval < f - 0.5)
9298	    ctxt->value->floatval = f - 1;
9299	else
9300	    ctxt->value->floatval = f;
9301	if (ctxt->value->floatval == 0)
9302	    ctxt->value->floatval = xmlXPathNZERO;
9303    } else {
9304	if (ctxt->value->floatval < f + 0.5)
9305	    ctxt->value->floatval = f;
9306	else
9307	    ctxt->value->floatval = f + 1;
9308    }
9309}
9310
9311/************************************************************************
9312 *									*
9313 *			The Parser					*
9314 *									*
9315 ************************************************************************/
9316
9317/*
9318 * a few forward declarations since we use a recursive call based
9319 * implementation.
9320 */
9321static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9322static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9323static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9324static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9325static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9326	                                  int qualified);
9327
9328/**
9329 * xmlXPathCurrentChar:
9330 * @ctxt:  the XPath parser context
9331 * @cur:  pointer to the beginning of the char
9332 * @len:  pointer to the length of the char read
9333 *
9334 * The current char value, if using UTF-8 this may actually span multiple
9335 * bytes in the input buffer.
9336 *
9337 * Returns the current char value and its length
9338 */
9339
9340static int
9341xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9342    unsigned char c;
9343    unsigned int val;
9344    const xmlChar *cur;
9345
9346    if (ctxt == NULL)
9347	return(0);
9348    cur = ctxt->cur;
9349
9350    /*
9351     * We are supposed to handle UTF8, check it's valid
9352     * From rfc2044: encoding of the Unicode values on UTF-8:
9353     *
9354     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9355     * 0000 0000-0000 007F   0xxxxxxx
9356     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9357     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9358     *
9359     * Check for the 0x110000 limit too
9360     */
9361    c = *cur;
9362    if (c & 0x80) {
9363	if ((cur[1] & 0xc0) != 0x80)
9364	    goto encoding_error;
9365	if ((c & 0xe0) == 0xe0) {
9366
9367	    if ((cur[2] & 0xc0) != 0x80)
9368		goto encoding_error;
9369	    if ((c & 0xf0) == 0xf0) {
9370		if (((c & 0xf8) != 0xf0) ||
9371		    ((cur[3] & 0xc0) != 0x80))
9372		    goto encoding_error;
9373		/* 4-byte code */
9374		*len = 4;
9375		val = (cur[0] & 0x7) << 18;
9376		val |= (cur[1] & 0x3f) << 12;
9377		val |= (cur[2] & 0x3f) << 6;
9378		val |= cur[3] & 0x3f;
9379	    } else {
9380	      /* 3-byte code */
9381		*len = 3;
9382		val = (cur[0] & 0xf) << 12;
9383		val |= (cur[1] & 0x3f) << 6;
9384		val |= cur[2] & 0x3f;
9385	    }
9386	} else {
9387	  /* 2-byte code */
9388	    *len = 2;
9389	    val = (cur[0] & 0x1f) << 6;
9390	    val |= cur[1] & 0x3f;
9391	}
9392	if (!IS_CHAR(val)) {
9393	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9394	}
9395	return(val);
9396    } else {
9397	/* 1-byte code */
9398	*len = 1;
9399	return((int) *cur);
9400    }
9401encoding_error:
9402    /*
9403     * If we detect an UTF8 error that probably means that the
9404     * input encoding didn't get properly advertised in the
9405     * declaration header. Report the error and switch the encoding
9406     * to ISO-Latin-1 (if you don't like this policy, just declare the
9407     * encoding !)
9408     */
9409    *len = 0;
9410    XP_ERROR0(XPATH_ENCODING_ERROR);
9411}
9412
9413/**
9414 * xmlXPathParseNCName:
9415 * @ctxt:  the XPath Parser context
9416 *
9417 * parse an XML namespace non qualified name.
9418 *
9419 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9420 *
9421 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9422 *                       CombiningChar | Extender
9423 *
9424 * Returns the namespace name or NULL
9425 */
9426
9427xmlChar *
9428xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9429    const xmlChar *in;
9430    xmlChar *ret;
9431    int count = 0;
9432
9433    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9434    /*
9435     * Accelerator for simple ASCII names
9436     */
9437    in = ctxt->cur;
9438    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9439	((*in >= 0x41) && (*in <= 0x5A)) ||
9440	(*in == '_')) {
9441	in++;
9442	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9443	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9444	       ((*in >= 0x30) && (*in <= 0x39)) ||
9445	       (*in == '_') || (*in == '.') ||
9446	       (*in == '-'))
9447	    in++;
9448	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9449            (*in == '[') || (*in == ']') || (*in == ':') ||
9450            (*in == '@') || (*in == '*')) {
9451	    count = in - ctxt->cur;
9452	    if (count == 0)
9453		return(NULL);
9454	    ret = xmlStrndup(ctxt->cur, count);
9455	    ctxt->cur = in;
9456	    return(ret);
9457	}
9458    }
9459    return(xmlXPathParseNameComplex(ctxt, 0));
9460}
9461
9462
9463/**
9464 * xmlXPathParseQName:
9465 * @ctxt:  the XPath Parser context
9466 * @prefix:  a xmlChar **
9467 *
9468 * parse an XML qualified name
9469 *
9470 * [NS 5] QName ::= (Prefix ':')? LocalPart
9471 *
9472 * [NS 6] Prefix ::= NCName
9473 *
9474 * [NS 7] LocalPart ::= NCName
9475 *
9476 * Returns the function returns the local part, and prefix is updated
9477 *   to get the Prefix if any.
9478 */
9479
9480static xmlChar *
9481xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9482    xmlChar *ret = NULL;
9483
9484    *prefix = NULL;
9485    ret = xmlXPathParseNCName(ctxt);
9486    if (CUR == ':') {
9487        *prefix = ret;
9488	NEXT;
9489	ret = xmlXPathParseNCName(ctxt);
9490    }
9491    return(ret);
9492}
9493
9494/**
9495 * xmlXPathParseName:
9496 * @ctxt:  the XPath Parser context
9497 *
9498 * parse an XML name
9499 *
9500 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9501 *                  CombiningChar | Extender
9502 *
9503 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9504 *
9505 * Returns the namespace name or NULL
9506 */
9507
9508xmlChar *
9509xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9510    const xmlChar *in;
9511    xmlChar *ret;
9512    int count = 0;
9513
9514    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9515    /*
9516     * Accelerator for simple ASCII names
9517     */
9518    in = ctxt->cur;
9519    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9520	((*in >= 0x41) && (*in <= 0x5A)) ||
9521	(*in == '_') || (*in == ':')) {
9522	in++;
9523	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9524	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9525	       ((*in >= 0x30) && (*in <= 0x39)) ||
9526	       (*in == '_') || (*in == '-') ||
9527	       (*in == ':') || (*in == '.'))
9528	    in++;
9529	if ((*in > 0) && (*in < 0x80)) {
9530	    count = in - ctxt->cur;
9531	    ret = xmlStrndup(ctxt->cur, count);
9532	    ctxt->cur = in;
9533	    return(ret);
9534	}
9535    }
9536    return(xmlXPathParseNameComplex(ctxt, 1));
9537}
9538
9539static xmlChar *
9540xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9541    xmlChar buf[XML_MAX_NAMELEN + 5];
9542    int len = 0, l;
9543    int c;
9544
9545    /*
9546     * Handler for more complex cases
9547     */
9548    c = CUR_CHAR(l);
9549    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9550        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9551        (c == '*') || /* accelerators */
9552	(!IS_LETTER(c) && (c != '_') &&
9553         ((qualified) && (c != ':')))) {
9554	return(NULL);
9555    }
9556
9557    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9558	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9559            (c == '.') || (c == '-') ||
9560	    (c == '_') || ((qualified) && (c == ':')) ||
9561	    (IS_COMBINING(c)) ||
9562	    (IS_EXTENDER(c)))) {
9563	COPY_BUF(l,buf,len,c);
9564	NEXTL(l);
9565	c = CUR_CHAR(l);
9566	if (len >= XML_MAX_NAMELEN) {
9567	    /*
9568	     * Okay someone managed to make a huge name, so he's ready to pay
9569	     * for the processing speed.
9570	     */
9571	    xmlChar *buffer;
9572	    int max = len * 2;
9573
9574	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9575	    if (buffer == NULL) {
9576		XP_ERRORNULL(XPATH_MEMORY_ERROR);
9577	    }
9578	    memcpy(buffer, buf, len);
9579	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9580		   (c == '.') || (c == '-') ||
9581		   (c == '_') || ((qualified) && (c == ':')) ||
9582		   (IS_COMBINING(c)) ||
9583		   (IS_EXTENDER(c))) {
9584		if (len + 10 > max) {
9585		    max *= 2;
9586		    buffer = (xmlChar *) xmlRealloc(buffer,
9587			                            max * sizeof(xmlChar));
9588		    if (buffer == NULL) {
9589			XP_ERRORNULL(XPATH_MEMORY_ERROR);
9590		    }
9591		}
9592		COPY_BUF(l,buffer,len,c);
9593		NEXTL(l);
9594		c = CUR_CHAR(l);
9595	    }
9596	    buffer[len] = 0;
9597	    return(buffer);
9598	}
9599    }
9600    if (len == 0)
9601	return(NULL);
9602    return(xmlStrndup(buf, len));
9603}
9604
9605#define MAX_FRAC 20
9606
9607/*
9608 * These are used as divisors for the fractional part of a number.
9609 * Since the table includes 1.0 (representing '0' fractional digits),
9610 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9611 */
9612static double my_pow10[MAX_FRAC+1] = {
9613    1.0, 10.0, 100.0, 1000.0, 10000.0,
9614    100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9615    10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9616    100000000000000.0,
9617    1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9618    1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9619};
9620
9621/**
9622 * xmlXPathStringEvalNumber:
9623 * @str:  A string to scan
9624 *
9625 *  [30a]  Float  ::= Number ('e' Digits?)?
9626 *
9627 *  [30]   Number ::=   Digits ('.' Digits?)?
9628 *                    | '.' Digits
9629 *  [31]   Digits ::=   [0-9]+
9630 *
9631 * Compile a Number in the string
9632 * In complement of the Number expression, this function also handles
9633 * negative values : '-' Number.
9634 *
9635 * Returns the double value.
9636 */
9637double
9638xmlXPathStringEvalNumber(const xmlChar *str) {
9639    const xmlChar *cur = str;
9640    double ret;
9641    int ok = 0;
9642    int isneg = 0;
9643    int exponent = 0;
9644    int is_exponent_negative = 0;
9645#ifdef __GNUC__
9646    unsigned long tmp = 0;
9647    double temp;
9648#endif
9649    if (cur == NULL) return(0);
9650    while (IS_BLANK_CH(*cur)) cur++;
9651    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9652        return(xmlXPathNAN);
9653    }
9654    if (*cur == '-') {
9655	isneg = 1;
9656	cur++;
9657    }
9658
9659#ifdef __GNUC__
9660    /*
9661     * tmp/temp is a workaround against a gcc compiler bug
9662     * http://veillard.com/gcc.bug
9663     */
9664    ret = 0;
9665    while ((*cur >= '0') && (*cur <= '9')) {
9666	ret = ret * 10;
9667	tmp = (*cur - '0');
9668	ok = 1;
9669	cur++;
9670	temp = (double) tmp;
9671	ret = ret + temp;
9672    }
9673#else
9674    ret = 0;
9675    while ((*cur >= '0') && (*cur <= '9')) {
9676	ret = ret * 10 + (*cur - '0');
9677	ok = 1;
9678	cur++;
9679    }
9680#endif
9681
9682    if (*cur == '.') {
9683	int v, frac = 0;
9684	double fraction = 0;
9685
9686        cur++;
9687	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9688	    return(xmlXPathNAN);
9689	}
9690	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9691	    v = (*cur - '0');
9692	    fraction = fraction * 10 + v;
9693	    frac = frac + 1;
9694	    cur++;
9695	}
9696	fraction /= my_pow10[frac];
9697	ret = ret + fraction;
9698	while ((*cur >= '0') && (*cur <= '9'))
9699	    cur++;
9700    }
9701    if ((*cur == 'e') || (*cur == 'E')) {
9702      cur++;
9703      if (*cur == '-') {
9704	is_exponent_negative = 1;
9705	cur++;
9706      } else if (*cur == '+') {
9707        cur++;
9708      }
9709      while ((*cur >= '0') && (*cur <= '9')) {
9710	exponent = exponent * 10 + (*cur - '0');
9711	cur++;
9712      }
9713    }
9714    while (IS_BLANK_CH(*cur)) cur++;
9715    if (*cur != 0) return(xmlXPathNAN);
9716    if (isneg) ret = -ret;
9717    if (is_exponent_negative) exponent = -exponent;
9718    ret *= pow(10.0, (double)exponent);
9719    return(ret);
9720}
9721
9722/**
9723 * xmlXPathCompNumber:
9724 * @ctxt:  the XPath Parser context
9725 *
9726 *  [30]   Number ::=   Digits ('.' Digits?)?
9727 *                    | '.' Digits
9728 *  [31]   Digits ::=   [0-9]+
9729 *
9730 * Compile a Number, then push it on the stack
9731 *
9732 */
9733static void
9734xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9735{
9736    double ret = 0.0;
9737    double mult = 1;
9738    int ok = 0;
9739    int exponent = 0;
9740    int is_exponent_negative = 0;
9741#ifdef __GNUC__
9742    unsigned long tmp = 0;
9743    double temp;
9744#endif
9745
9746    CHECK_ERROR;
9747    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
9748        XP_ERROR(XPATH_NUMBER_ERROR);
9749    }
9750#ifdef __GNUC__
9751    /*
9752     * tmp/temp is a workaround against a gcc compiler bug
9753     * http://veillard.com/gcc.bug
9754     */
9755    ret = 0;
9756    while ((CUR >= '0') && (CUR <= '9')) {
9757	ret = ret * 10;
9758	tmp = (CUR - '0');
9759        ok = 1;
9760        NEXT;
9761	temp = (double) tmp;
9762	ret = ret + temp;
9763    }
9764#else
9765    ret = 0;
9766    while ((CUR >= '0') && (CUR <= '9')) {
9767	ret = ret * 10 + (CUR - '0');
9768	ok = 1;
9769	NEXT;
9770    }
9771#endif
9772    if (CUR == '.') {
9773        NEXT;
9774        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
9775            XP_ERROR(XPATH_NUMBER_ERROR);
9776        }
9777        while ((CUR >= '0') && (CUR <= '9')) {
9778            mult /= 10;
9779            ret = ret + (CUR - '0') * mult;
9780            NEXT;
9781        }
9782    }
9783    if ((CUR == 'e') || (CUR == 'E')) {
9784        NEXT;
9785        if (CUR == '-') {
9786            is_exponent_negative = 1;
9787            NEXT;
9788        } else if (CUR == '+') {
9789	    NEXT;
9790	}
9791        while ((CUR >= '0') && (CUR <= '9')) {
9792            exponent = exponent * 10 + (CUR - '0');
9793            NEXT;
9794        }
9795        if (is_exponent_negative)
9796            exponent = -exponent;
9797        ret *= pow(10.0, (double) exponent);
9798    }
9799    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
9800                   xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
9801}
9802
9803/**
9804 * xmlXPathParseLiteral:
9805 * @ctxt:  the XPath Parser context
9806 *
9807 * Parse a Literal
9808 *
9809 *  [29]   Literal ::=   '"' [^"]* '"'
9810 *                    | "'" [^']* "'"
9811 *
9812 * Returns the value found or NULL in case of error
9813 */
9814static xmlChar *
9815xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
9816    const xmlChar *q;
9817    xmlChar *ret = NULL;
9818
9819    if (CUR == '"') {
9820        NEXT;
9821	q = CUR_PTR;
9822	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
9823	    NEXT;
9824	if (!IS_CHAR_CH(CUR)) {
9825	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
9826	} else {
9827	    ret = xmlStrndup(q, CUR_PTR - q);
9828	    NEXT;
9829        }
9830    } else if (CUR == '\'') {
9831        NEXT;
9832	q = CUR_PTR;
9833	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
9834	    NEXT;
9835	if (!IS_CHAR_CH(CUR)) {
9836	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
9837	} else {
9838	    ret = xmlStrndup(q, CUR_PTR - q);
9839	    NEXT;
9840        }
9841    } else {
9842	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
9843    }
9844    return(ret);
9845}
9846
9847/**
9848 * xmlXPathCompLiteral:
9849 * @ctxt:  the XPath Parser context
9850 *
9851 * Parse a Literal and push it on the stack.
9852 *
9853 *  [29]   Literal ::=   '"' [^"]* '"'
9854 *                    | "'" [^']* "'"
9855 *
9856 * TODO: xmlXPathCompLiteral memory allocation could be improved.
9857 */
9858static void
9859xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
9860    const xmlChar *q;
9861    xmlChar *ret = NULL;
9862
9863    if (CUR == '"') {
9864        NEXT;
9865	q = CUR_PTR;
9866	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
9867	    NEXT;
9868	if (!IS_CHAR_CH(CUR)) {
9869	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9870	} else {
9871	    ret = xmlStrndup(q, CUR_PTR - q);
9872	    NEXT;
9873        }
9874    } else if (CUR == '\'') {
9875        NEXT;
9876	q = CUR_PTR;
9877	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
9878	    NEXT;
9879	if (!IS_CHAR_CH(CUR)) {
9880	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9881	} else {
9882	    ret = xmlStrndup(q, CUR_PTR - q);
9883	    NEXT;
9884        }
9885    } else {
9886	XP_ERROR(XPATH_START_LITERAL_ERROR);
9887    }
9888    if (ret == NULL) return;
9889    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
9890	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
9891    xmlFree(ret);
9892}
9893
9894/**
9895 * xmlXPathCompVariableReference:
9896 * @ctxt:  the XPath Parser context
9897 *
9898 * Parse a VariableReference, evaluate it and push it on the stack.
9899 *
9900 * The variable bindings consist of a mapping from variable names
9901 * to variable values. The value of a variable is an object, which can be
9902 * of any of the types that are possible for the value of an expression,
9903 * and may also be of additional types not specified here.
9904 *
9905 * Early evaluation is possible since:
9906 * The variable bindings [...] used to evaluate a subexpression are
9907 * always the same as those used to evaluate the containing expression.
9908 *
9909 *  [36]   VariableReference ::=   '$' QName
9910 */
9911static void
9912xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
9913    xmlChar *name;
9914    xmlChar *prefix;
9915
9916    SKIP_BLANKS;
9917    if (CUR != '$') {
9918	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9919    }
9920    NEXT;
9921    name = xmlXPathParseQName(ctxt, &prefix);
9922    if (name == NULL) {
9923	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9924    }
9925    ctxt->comp->last = -1;
9926    PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
9927	           name, prefix);
9928    SKIP_BLANKS;
9929    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9930	XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
9931    }
9932}
9933
9934/**
9935 * xmlXPathIsNodeType:
9936 * @name:  a name string
9937 *
9938 * Is the name given a NodeType one.
9939 *
9940 *  [38]   NodeType ::=   'comment'
9941 *                    | 'text'
9942 *                    | 'processing-instruction'
9943 *                    | 'node'
9944 *
9945 * Returns 1 if true 0 otherwise
9946 */
9947int
9948xmlXPathIsNodeType(const xmlChar *name) {
9949    if (name == NULL)
9950	return(0);
9951
9952    if (xmlStrEqual(name, BAD_CAST "node"))
9953	return(1);
9954    if (xmlStrEqual(name, BAD_CAST "text"))
9955	return(1);
9956    if (xmlStrEqual(name, BAD_CAST "comment"))
9957	return(1);
9958    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9959	return(1);
9960    return(0);
9961}
9962
9963/**
9964 * xmlXPathCompFunctionCall:
9965 * @ctxt:  the XPath Parser context
9966 *
9967 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9968 *  [17]   Argument ::=   Expr
9969 *
9970 * Compile a function call, the evaluation of all arguments are
9971 * pushed on the stack
9972 */
9973static void
9974xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
9975    xmlChar *name;
9976    xmlChar *prefix;
9977    int nbargs = 0;
9978    int sort = 1;
9979
9980    name = xmlXPathParseQName(ctxt, &prefix);
9981    if (name == NULL) {
9982	XP_ERROR(XPATH_EXPR_ERROR);
9983    }
9984    SKIP_BLANKS;
9985#ifdef DEBUG_EXPR
9986    if (prefix == NULL)
9987	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
9988			name);
9989    else
9990	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
9991			prefix, name);
9992#endif
9993
9994    if (CUR != '(') {
9995	XP_ERROR(XPATH_EXPR_ERROR);
9996    }
9997    NEXT;
9998    SKIP_BLANKS;
9999
10000    /*
10001    * Optimization for count(): we don't need the node-set to be sorted.
10002    */
10003    if ((prefix == NULL) && (name[0] == 'c') &&
10004	xmlStrEqual(name, BAD_CAST "count"))
10005    {
10006	sort = 0;
10007    }
10008    ctxt->comp->last = -1;
10009    if (CUR != ')') {
10010	while (CUR != 0) {
10011	    int op1 = ctxt->comp->last;
10012	    ctxt->comp->last = -1;
10013	    xmlXPathCompileExpr(ctxt, sort);
10014	    CHECK_ERROR;
10015	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10016	    nbargs++;
10017	    if (CUR == ')') break;
10018	    if (CUR != ',') {
10019		XP_ERROR(XPATH_EXPR_ERROR);
10020	    }
10021	    NEXT;
10022	    SKIP_BLANKS;
10023	}
10024    }
10025    PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10026	           name, prefix);
10027    NEXT;
10028    SKIP_BLANKS;
10029}
10030
10031/**
10032 * xmlXPathCompPrimaryExpr:
10033 * @ctxt:  the XPath Parser context
10034 *
10035 *  [15]   PrimaryExpr ::=   VariableReference
10036 *                | '(' Expr ')'
10037 *                | Literal
10038 *                | Number
10039 *                | FunctionCall
10040 *
10041 * Compile a primary expression.
10042 */
10043static void
10044xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10045    SKIP_BLANKS;
10046    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10047    else if (CUR == '(') {
10048	NEXT;
10049	SKIP_BLANKS;
10050	xmlXPathCompileExpr(ctxt, 1);
10051	CHECK_ERROR;
10052	if (CUR != ')') {
10053	    XP_ERROR(XPATH_EXPR_ERROR);
10054	}
10055	NEXT;
10056	SKIP_BLANKS;
10057    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10058	xmlXPathCompNumber(ctxt);
10059    } else if ((CUR == '\'') || (CUR == '"')) {
10060	xmlXPathCompLiteral(ctxt);
10061    } else {
10062	xmlXPathCompFunctionCall(ctxt);
10063    }
10064    SKIP_BLANKS;
10065}
10066
10067/**
10068 * xmlXPathCompFilterExpr:
10069 * @ctxt:  the XPath Parser context
10070 *
10071 *  [20]   FilterExpr ::=   PrimaryExpr
10072 *               | FilterExpr Predicate
10073 *
10074 * Compile a filter expression.
10075 * Square brackets are used to filter expressions in the same way that
10076 * they are used in location paths. It is an error if the expression to
10077 * be filtered does not evaluate to a node-set. The context node list
10078 * used for evaluating the expression in square brackets is the node-set
10079 * to be filtered listed in document order.
10080 */
10081
10082static void
10083xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10084    xmlXPathCompPrimaryExpr(ctxt);
10085    CHECK_ERROR;
10086    SKIP_BLANKS;
10087
10088    while (CUR == '[') {
10089	xmlXPathCompPredicate(ctxt, 1);
10090	SKIP_BLANKS;
10091    }
10092
10093
10094}
10095
10096/**
10097 * xmlXPathScanName:
10098 * @ctxt:  the XPath Parser context
10099 *
10100 * Trickery: parse an XML name but without consuming the input flow
10101 * Needed to avoid insanity in the parser state.
10102 *
10103 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10104 *                  CombiningChar | Extender
10105 *
10106 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10107 *
10108 * [6] Names ::= Name (S Name)*
10109 *
10110 * Returns the Name parsed or NULL
10111 */
10112
10113static xmlChar *
10114xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10115    int len = 0, l;
10116    int c;
10117    const xmlChar *cur;
10118    xmlChar *ret;
10119
10120    cur = ctxt->cur;
10121
10122    c = CUR_CHAR(l);
10123    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10124	(!IS_LETTER(c) && (c != '_') &&
10125         (c != ':'))) {
10126	return(NULL);
10127    }
10128
10129    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10130	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10131            (c == '.') || (c == '-') ||
10132	    (c == '_') || (c == ':') ||
10133	    (IS_COMBINING(c)) ||
10134	    (IS_EXTENDER(c)))) {
10135	len += l;
10136	NEXTL(l);
10137	c = CUR_CHAR(l);
10138    }
10139    ret = xmlStrndup(cur, ctxt->cur - cur);
10140    ctxt->cur = cur;
10141    return(ret);
10142}
10143
10144/**
10145 * xmlXPathCompPathExpr:
10146 * @ctxt:  the XPath Parser context
10147 *
10148 *  [19]   PathExpr ::=   LocationPath
10149 *               | FilterExpr
10150 *               | FilterExpr '/' RelativeLocationPath
10151 *               | FilterExpr '//' RelativeLocationPath
10152 *
10153 * Compile a path expression.
10154 * The / operator and // operators combine an arbitrary expression
10155 * and a relative location path. It is an error if the expression
10156 * does not evaluate to a node-set.
10157 * The / operator does composition in the same way as when / is
10158 * used in a location path. As in location paths, // is short for
10159 * /descendant-or-self::node()/.
10160 */
10161
10162static void
10163xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10164    int lc = 1;           /* Should we branch to LocationPath ?         */
10165    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10166
10167    SKIP_BLANKS;
10168    if ((CUR == '$') || (CUR == '(') ||
10169    	(IS_ASCII_DIGIT(CUR)) ||
10170        (CUR == '\'') || (CUR == '"') ||
10171	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10172	lc = 0;
10173    } else if (CUR == '*') {
10174	/* relative or absolute location path */
10175	lc = 1;
10176    } else if (CUR == '/') {
10177	/* relative or absolute location path */
10178	lc = 1;
10179    } else if (CUR == '@') {
10180	/* relative abbreviated attribute location path */
10181	lc = 1;
10182    } else if (CUR == '.') {
10183	/* relative abbreviated attribute location path */
10184	lc = 1;
10185    } else {
10186	/*
10187	 * Problem is finding if we have a name here whether it's:
10188	 *   - a nodetype
10189	 *   - a function call in which case it's followed by '('
10190	 *   - an axis in which case it's followed by ':'
10191	 *   - a element name
10192	 * We do an a priori analysis here rather than having to
10193	 * maintain parsed token content through the recursive function
10194	 * calls. This looks uglier but makes the code easier to
10195	 * read/write/debug.
10196	 */
10197	SKIP_BLANKS;
10198	name = xmlXPathScanName(ctxt);
10199	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10200#ifdef DEBUG_STEP
10201	    xmlGenericError(xmlGenericErrorContext,
10202		    "PathExpr: Axis\n");
10203#endif
10204	    lc = 1;
10205	    xmlFree(name);
10206	} else if (name != NULL) {
10207	    int len =xmlStrlen(name);
10208
10209
10210	    while (NXT(len) != 0) {
10211		if (NXT(len) == '/') {
10212		    /* element name */
10213#ifdef DEBUG_STEP
10214		    xmlGenericError(xmlGenericErrorContext,
10215			    "PathExpr: AbbrRelLocation\n");
10216#endif
10217		    lc = 1;
10218		    break;
10219		} else if (IS_BLANK_CH(NXT(len))) {
10220		    /* ignore blanks */
10221		    ;
10222		} else if (NXT(len) == ':') {
10223#ifdef DEBUG_STEP
10224		    xmlGenericError(xmlGenericErrorContext,
10225			    "PathExpr: AbbrRelLocation\n");
10226#endif
10227		    lc = 1;
10228		    break;
10229		} else if ((NXT(len) == '(')) {
10230		    /* Note Type or Function */
10231		    if (xmlXPathIsNodeType(name)) {
10232#ifdef DEBUG_STEP
10233		        xmlGenericError(xmlGenericErrorContext,
10234				"PathExpr: Type search\n");
10235#endif
10236			lc = 1;
10237		    } else {
10238#ifdef DEBUG_STEP
10239		        xmlGenericError(xmlGenericErrorContext,
10240				"PathExpr: function call\n");
10241#endif
10242			lc = 0;
10243		    }
10244                    break;
10245		} else if ((NXT(len) == '[')) {
10246		    /* element name */
10247#ifdef DEBUG_STEP
10248		    xmlGenericError(xmlGenericErrorContext,
10249			    "PathExpr: AbbrRelLocation\n");
10250#endif
10251		    lc = 1;
10252		    break;
10253		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10254			   (NXT(len) == '=')) {
10255		    lc = 1;
10256		    break;
10257		} else {
10258		    lc = 1;
10259		    break;
10260		}
10261		len++;
10262	    }
10263	    if (NXT(len) == 0) {
10264#ifdef DEBUG_STEP
10265		xmlGenericError(xmlGenericErrorContext,
10266			"PathExpr: AbbrRelLocation\n");
10267#endif
10268		/* element name */
10269		lc = 1;
10270	    }
10271	    xmlFree(name);
10272	} else {
10273	    /* make sure all cases are covered explicitly */
10274	    XP_ERROR(XPATH_EXPR_ERROR);
10275	}
10276    }
10277
10278    if (lc) {
10279	if (CUR == '/') {
10280	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10281	} else {
10282	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10283	}
10284	xmlXPathCompLocationPath(ctxt);
10285    } else {
10286	xmlXPathCompFilterExpr(ctxt);
10287	CHECK_ERROR;
10288	if ((CUR == '/') && (NXT(1) == '/')) {
10289	    SKIP(2);
10290	    SKIP_BLANKS;
10291
10292	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10293		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10294	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10295
10296	    xmlXPathCompRelativeLocationPath(ctxt);
10297	} else if (CUR == '/') {
10298	    xmlXPathCompRelativeLocationPath(ctxt);
10299	}
10300    }
10301    SKIP_BLANKS;
10302}
10303
10304/**
10305 * xmlXPathCompUnionExpr:
10306 * @ctxt:  the XPath Parser context
10307 *
10308 *  [18]   UnionExpr ::=   PathExpr
10309 *               | UnionExpr '|' PathExpr
10310 *
10311 * Compile an union expression.
10312 */
10313
10314static void
10315xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10316    xmlXPathCompPathExpr(ctxt);
10317    CHECK_ERROR;
10318    SKIP_BLANKS;
10319    while (CUR == '|') {
10320	int op1 = ctxt->comp->last;
10321	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10322
10323	NEXT;
10324	SKIP_BLANKS;
10325	xmlXPathCompPathExpr(ctxt);
10326
10327	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10328
10329	SKIP_BLANKS;
10330    }
10331}
10332
10333/**
10334 * xmlXPathCompUnaryExpr:
10335 * @ctxt:  the XPath Parser context
10336 *
10337 *  [27]   UnaryExpr ::=   UnionExpr
10338 *                   | '-' UnaryExpr
10339 *
10340 * Compile an unary expression.
10341 */
10342
10343static void
10344xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10345    int minus = 0;
10346    int found = 0;
10347
10348    SKIP_BLANKS;
10349    while (CUR == '-') {
10350        minus = 1 - minus;
10351	found = 1;
10352	NEXT;
10353	SKIP_BLANKS;
10354    }
10355
10356    xmlXPathCompUnionExpr(ctxt);
10357    CHECK_ERROR;
10358    if (found) {
10359	if (minus)
10360	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10361	else
10362	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10363    }
10364}
10365
10366/**
10367 * xmlXPathCompMultiplicativeExpr:
10368 * @ctxt:  the XPath Parser context
10369 *
10370 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10371 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10372 *                   | MultiplicativeExpr 'div' UnaryExpr
10373 *                   | MultiplicativeExpr 'mod' UnaryExpr
10374 *  [34]   MultiplyOperator ::=   '*'
10375 *
10376 * Compile an Additive expression.
10377 */
10378
10379static void
10380xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10381    xmlXPathCompUnaryExpr(ctxt);
10382    CHECK_ERROR;
10383    SKIP_BLANKS;
10384    while ((CUR == '*') ||
10385           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10386           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10387	int op = -1;
10388	int op1 = ctxt->comp->last;
10389
10390        if (CUR == '*') {
10391	    op = 0;
10392	    NEXT;
10393	} else if (CUR == 'd') {
10394	    op = 1;
10395	    SKIP(3);
10396	} else if (CUR == 'm') {
10397	    op = 2;
10398	    SKIP(3);
10399	}
10400	SKIP_BLANKS;
10401        xmlXPathCompUnaryExpr(ctxt);
10402	CHECK_ERROR;
10403	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10404	SKIP_BLANKS;
10405    }
10406}
10407
10408/**
10409 * xmlXPathCompAdditiveExpr:
10410 * @ctxt:  the XPath Parser context
10411 *
10412 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10413 *                   | AdditiveExpr '+' MultiplicativeExpr
10414 *                   | AdditiveExpr '-' MultiplicativeExpr
10415 *
10416 * Compile an Additive expression.
10417 */
10418
10419static void
10420xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10421
10422    xmlXPathCompMultiplicativeExpr(ctxt);
10423    CHECK_ERROR;
10424    SKIP_BLANKS;
10425    while ((CUR == '+') || (CUR == '-')) {
10426	int plus;
10427	int op1 = ctxt->comp->last;
10428
10429        if (CUR == '+') plus = 1;
10430	else plus = 0;
10431	NEXT;
10432	SKIP_BLANKS;
10433        xmlXPathCompMultiplicativeExpr(ctxt);
10434	CHECK_ERROR;
10435	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10436	SKIP_BLANKS;
10437    }
10438}
10439
10440/**
10441 * xmlXPathCompRelationalExpr:
10442 * @ctxt:  the XPath Parser context
10443 *
10444 *  [24]   RelationalExpr ::=   AdditiveExpr
10445 *                 | RelationalExpr '<' AdditiveExpr
10446 *                 | RelationalExpr '>' AdditiveExpr
10447 *                 | RelationalExpr '<=' AdditiveExpr
10448 *                 | RelationalExpr '>=' AdditiveExpr
10449 *
10450 *  A <= B > C is allowed ? Answer from James, yes with
10451 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10452 *  which is basically what got implemented.
10453 *
10454 * Compile a Relational expression, then push the result
10455 * on the stack
10456 */
10457
10458static void
10459xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10460    xmlXPathCompAdditiveExpr(ctxt);
10461    CHECK_ERROR;
10462    SKIP_BLANKS;
10463    while ((CUR == '<') ||
10464           (CUR == '>') ||
10465           ((CUR == '<') && (NXT(1) == '=')) ||
10466           ((CUR == '>') && (NXT(1) == '='))) {
10467	int inf, strict;
10468	int op1 = ctxt->comp->last;
10469
10470        if (CUR == '<') inf = 1;
10471	else inf = 0;
10472	if (NXT(1) == '=') strict = 0;
10473	else strict = 1;
10474	NEXT;
10475	if (!strict) NEXT;
10476	SKIP_BLANKS;
10477        xmlXPathCompAdditiveExpr(ctxt);
10478	CHECK_ERROR;
10479	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10480	SKIP_BLANKS;
10481    }
10482}
10483
10484/**
10485 * xmlXPathCompEqualityExpr:
10486 * @ctxt:  the XPath Parser context
10487 *
10488 *  [23]   EqualityExpr ::=   RelationalExpr
10489 *                 | EqualityExpr '=' RelationalExpr
10490 *                 | EqualityExpr '!=' RelationalExpr
10491 *
10492 *  A != B != C is allowed ? Answer from James, yes with
10493 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10494 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10495 *  which is basically what got implemented.
10496 *
10497 * Compile an Equality expression.
10498 *
10499 */
10500static void
10501xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10502    xmlXPathCompRelationalExpr(ctxt);
10503    CHECK_ERROR;
10504    SKIP_BLANKS;
10505    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10506	int eq;
10507	int op1 = ctxt->comp->last;
10508
10509        if (CUR == '=') eq = 1;
10510	else eq = 0;
10511	NEXT;
10512	if (!eq) NEXT;
10513	SKIP_BLANKS;
10514        xmlXPathCompRelationalExpr(ctxt);
10515	CHECK_ERROR;
10516	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10517	SKIP_BLANKS;
10518    }
10519}
10520
10521/**
10522 * xmlXPathCompAndExpr:
10523 * @ctxt:  the XPath Parser context
10524 *
10525 *  [22]   AndExpr ::=   EqualityExpr
10526 *                 | AndExpr 'and' EqualityExpr
10527 *
10528 * Compile an AND expression.
10529 *
10530 */
10531static void
10532xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10533    xmlXPathCompEqualityExpr(ctxt);
10534    CHECK_ERROR;
10535    SKIP_BLANKS;
10536    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10537	int op1 = ctxt->comp->last;
10538        SKIP(3);
10539	SKIP_BLANKS;
10540        xmlXPathCompEqualityExpr(ctxt);
10541	CHECK_ERROR;
10542	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10543	SKIP_BLANKS;
10544    }
10545}
10546
10547/**
10548 * xmlXPathCompileExpr:
10549 * @ctxt:  the XPath Parser context
10550 *
10551 *  [14]   Expr ::=   OrExpr
10552 *  [21]   OrExpr ::=   AndExpr
10553 *                 | OrExpr 'or' AndExpr
10554 *
10555 * Parse and compile an expression
10556 */
10557static void
10558xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10559    xmlXPathCompAndExpr(ctxt);
10560    CHECK_ERROR;
10561    SKIP_BLANKS;
10562    while ((CUR == 'o') && (NXT(1) == 'r')) {
10563	int op1 = ctxt->comp->last;
10564        SKIP(2);
10565	SKIP_BLANKS;
10566        xmlXPathCompAndExpr(ctxt);
10567	CHECK_ERROR;
10568	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10569	op1 = ctxt->comp->nbStep;
10570	SKIP_BLANKS;
10571    }
10572    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10573	/* more ops could be optimized too */
10574	/*
10575	* This is the main place to eliminate sorting for
10576	* operations which don't require a sorted node-set.
10577	* E.g. count().
10578	*/
10579	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10580    }
10581}
10582
10583/**
10584 * xmlXPathCompPredicate:
10585 * @ctxt:  the XPath Parser context
10586 * @filter:  act as a filter
10587 *
10588 *  [8]   Predicate ::=   '[' PredicateExpr ']'
10589 *  [9]   PredicateExpr ::=   Expr
10590 *
10591 * Compile a predicate expression
10592 */
10593static void
10594xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10595    int op1 = ctxt->comp->last;
10596
10597    SKIP_BLANKS;
10598    if (CUR != '[') {
10599	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10600    }
10601    NEXT;
10602    SKIP_BLANKS;
10603
10604    ctxt->comp->last = -1;
10605    xmlXPathCompileExpr(ctxt, 1);
10606    CHECK_ERROR;
10607
10608    if (CUR != ']') {
10609	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10610    }
10611
10612    if (filter)
10613	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10614    else
10615	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10616
10617    NEXT;
10618    SKIP_BLANKS;
10619}
10620
10621/**
10622 * xmlXPathCompNodeTest:
10623 * @ctxt:  the XPath Parser context
10624 * @test:  pointer to a xmlXPathTestVal
10625 * @type:  pointer to a xmlXPathTypeVal
10626 * @prefix:  placeholder for a possible name prefix
10627 *
10628 * [7] NodeTest ::=   NameTest
10629 *		    | NodeType '(' ')'
10630 *		    | 'processing-instruction' '(' Literal ')'
10631 *
10632 * [37] NameTest ::=  '*'
10633 *		    | NCName ':' '*'
10634 *		    | QName
10635 * [38] NodeType ::= 'comment'
10636 *		   | 'text'
10637 *		   | 'processing-instruction'
10638 *		   | 'node'
10639 *
10640 * Returns the name found and updates @test, @type and @prefix appropriately
10641 */
10642static xmlChar *
10643xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10644	             xmlXPathTypeVal *type, const xmlChar **prefix,
10645		     xmlChar *name) {
10646    int blanks;
10647
10648    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10649	STRANGE;
10650	return(NULL);
10651    }
10652    *type = (xmlXPathTypeVal) 0;
10653    *test = (xmlXPathTestVal) 0;
10654    *prefix = NULL;
10655    SKIP_BLANKS;
10656
10657    if ((name == NULL) && (CUR == '*')) {
10658	/*
10659	 * All elements
10660	 */
10661	NEXT;
10662	*test = NODE_TEST_ALL;
10663	return(NULL);
10664    }
10665
10666    if (name == NULL)
10667	name = xmlXPathParseNCName(ctxt);
10668    if (name == NULL) {
10669	XP_ERRORNULL(XPATH_EXPR_ERROR);
10670    }
10671
10672    blanks = IS_BLANK_CH(CUR);
10673    SKIP_BLANKS;
10674    if (CUR == '(') {
10675	NEXT;
10676	/*
10677	 * NodeType or PI search
10678	 */
10679	if (xmlStrEqual(name, BAD_CAST "comment"))
10680	    *type = NODE_TYPE_COMMENT;
10681	else if (xmlStrEqual(name, BAD_CAST "node"))
10682	    *type = NODE_TYPE_NODE;
10683	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10684	    *type = NODE_TYPE_PI;
10685	else if (xmlStrEqual(name, BAD_CAST "text"))
10686	    *type = NODE_TYPE_TEXT;
10687	else {
10688	    if (name != NULL)
10689		xmlFree(name);
10690	    XP_ERRORNULL(XPATH_EXPR_ERROR);
10691	}
10692
10693	*test = NODE_TEST_TYPE;
10694
10695	SKIP_BLANKS;
10696	if (*type == NODE_TYPE_PI) {
10697	    /*
10698	     * Specific case: search a PI by name.
10699	     */
10700	    if (name != NULL)
10701		xmlFree(name);
10702	    name = NULL;
10703	    if (CUR != ')') {
10704		name = xmlXPathParseLiteral(ctxt);
10705		CHECK_ERROR NULL;
10706		*test = NODE_TEST_PI;
10707		SKIP_BLANKS;
10708	    }
10709	}
10710	if (CUR != ')') {
10711	    if (name != NULL)
10712		xmlFree(name);
10713	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
10714	}
10715	NEXT;
10716	return(name);
10717    }
10718    *test = NODE_TEST_NAME;
10719    if ((!blanks) && (CUR == ':')) {
10720	NEXT;
10721
10722	/*
10723	 * Since currently the parser context don't have a
10724	 * namespace list associated:
10725	 * The namespace name for this prefix can be computed
10726	 * only at evaluation time. The compilation is done
10727	 * outside of any context.
10728	 */
10729#if 0
10730	*prefix = xmlXPathNsLookup(ctxt->context, name);
10731	if (name != NULL)
10732	    xmlFree(name);
10733	if (*prefix == NULL) {
10734	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10735	}
10736#else
10737	*prefix = name;
10738#endif
10739
10740	if (CUR == '*') {
10741	    /*
10742	     * All elements
10743	     */
10744	    NEXT;
10745	    *test = NODE_TEST_ALL;
10746	    return(NULL);
10747	}
10748
10749	name = xmlXPathParseNCName(ctxt);
10750	if (name == NULL) {
10751	    XP_ERRORNULL(XPATH_EXPR_ERROR);
10752	}
10753    }
10754    return(name);
10755}
10756
10757/**
10758 * xmlXPathIsAxisName:
10759 * @name:  a preparsed name token
10760 *
10761 * [6] AxisName ::=   'ancestor'
10762 *                  | 'ancestor-or-self'
10763 *                  | 'attribute'
10764 *                  | 'child'
10765 *                  | 'descendant'
10766 *                  | 'descendant-or-self'
10767 *                  | 'following'
10768 *                  | 'following-sibling'
10769 *                  | 'namespace'
10770 *                  | 'parent'
10771 *                  | 'preceding'
10772 *                  | 'preceding-sibling'
10773 *                  | 'self'
10774 *
10775 * Returns the axis or 0
10776 */
10777static xmlXPathAxisVal
10778xmlXPathIsAxisName(const xmlChar *name) {
10779    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
10780    switch (name[0]) {
10781	case 'a':
10782	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
10783		ret = AXIS_ANCESTOR;
10784	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
10785		ret = AXIS_ANCESTOR_OR_SELF;
10786	    if (xmlStrEqual(name, BAD_CAST "attribute"))
10787		ret = AXIS_ATTRIBUTE;
10788	    break;
10789	case 'c':
10790	    if (xmlStrEqual(name, BAD_CAST "child"))
10791		ret = AXIS_CHILD;
10792	    break;
10793	case 'd':
10794	    if (xmlStrEqual(name, BAD_CAST "descendant"))
10795		ret = AXIS_DESCENDANT;
10796	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
10797		ret = AXIS_DESCENDANT_OR_SELF;
10798	    break;
10799	case 'f':
10800	    if (xmlStrEqual(name, BAD_CAST "following"))
10801		ret = AXIS_FOLLOWING;
10802	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
10803		ret = AXIS_FOLLOWING_SIBLING;
10804	    break;
10805	case 'n':
10806	    if (xmlStrEqual(name, BAD_CAST "namespace"))
10807		ret = AXIS_NAMESPACE;
10808	    break;
10809	case 'p':
10810	    if (xmlStrEqual(name, BAD_CAST "parent"))
10811		ret = AXIS_PARENT;
10812	    if (xmlStrEqual(name, BAD_CAST "preceding"))
10813		ret = AXIS_PRECEDING;
10814	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
10815		ret = AXIS_PRECEDING_SIBLING;
10816	    break;
10817	case 's':
10818	    if (xmlStrEqual(name, BAD_CAST "self"))
10819		ret = AXIS_SELF;
10820	    break;
10821    }
10822    return(ret);
10823}
10824
10825/**
10826 * xmlXPathCompStep:
10827 * @ctxt:  the XPath Parser context
10828 *
10829 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
10830 *                  | AbbreviatedStep
10831 *
10832 * [12] AbbreviatedStep ::=   '.' | '..'
10833 *
10834 * [5] AxisSpecifier ::= AxisName '::'
10835 *                  | AbbreviatedAxisSpecifier
10836 *
10837 * [13] AbbreviatedAxisSpecifier ::= '@'?
10838 *
10839 * Modified for XPtr range support as:
10840 *
10841 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
10842 *                     | AbbreviatedStep
10843 *                     | 'range-to' '(' Expr ')' Predicate*
10844 *
10845 * Compile one step in a Location Path
10846 * A location step of . is short for self::node(). This is
10847 * particularly useful in conjunction with //. For example, the
10848 * location path .//para is short for
10849 * self::node()/descendant-or-self::node()/child::para
10850 * and so will select all para descendant elements of the context
10851 * node.
10852 * Similarly, a location step of .. is short for parent::node().
10853 * For example, ../title is short for parent::node()/child::title
10854 * and so will select the title children of the parent of the context
10855 * node.
10856 */
10857static void
10858xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
10859#ifdef LIBXML_XPTR_ENABLED
10860    int rangeto = 0;
10861    int op2 = -1;
10862#endif
10863
10864    SKIP_BLANKS;
10865    if ((CUR == '.') && (NXT(1) == '.')) {
10866	SKIP(2);
10867	SKIP_BLANKS;
10868	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
10869		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10870    } else if (CUR == '.') {
10871	NEXT;
10872	SKIP_BLANKS;
10873    } else {
10874	xmlChar *name = NULL;
10875	const xmlChar *prefix = NULL;
10876	xmlXPathTestVal test = (xmlXPathTestVal) 0;
10877	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
10878	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
10879	int op1;
10880
10881	/*
10882	 * The modification needed for XPointer change to the production
10883	 */
10884#ifdef LIBXML_XPTR_ENABLED
10885	if (ctxt->xptr) {
10886	    name = xmlXPathParseNCName(ctxt);
10887	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
10888                op2 = ctxt->comp->last;
10889		xmlFree(name);
10890		SKIP_BLANKS;
10891		if (CUR != '(') {
10892		    XP_ERROR(XPATH_EXPR_ERROR);
10893		}
10894		NEXT;
10895		SKIP_BLANKS;
10896
10897		xmlXPathCompileExpr(ctxt, 1);
10898		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
10899		CHECK_ERROR;
10900
10901		SKIP_BLANKS;
10902		if (CUR != ')') {
10903		    XP_ERROR(XPATH_EXPR_ERROR);
10904		}
10905		NEXT;
10906		rangeto = 1;
10907		goto eval_predicates;
10908	    }
10909	}
10910#endif
10911	if (CUR == '*') {
10912	    axis = AXIS_CHILD;
10913	} else {
10914	    if (name == NULL)
10915		name = xmlXPathParseNCName(ctxt);
10916	    if (name != NULL) {
10917		axis = xmlXPathIsAxisName(name);
10918		if (axis != 0) {
10919		    SKIP_BLANKS;
10920		    if ((CUR == ':') && (NXT(1) == ':')) {
10921			SKIP(2);
10922			xmlFree(name);
10923			name = NULL;
10924		    } else {
10925			/* an element name can conflict with an axis one :-\ */
10926			axis = AXIS_CHILD;
10927		    }
10928		} else {
10929		    axis = AXIS_CHILD;
10930		}
10931	    } else if (CUR == '@') {
10932		NEXT;
10933		axis = AXIS_ATTRIBUTE;
10934	    } else {
10935		axis = AXIS_CHILD;
10936	    }
10937	}
10938
10939	CHECK_ERROR;
10940
10941	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
10942	if (test == 0)
10943	    return;
10944
10945        if ((prefix != NULL) && (ctxt->context != NULL) &&
10946	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
10947	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
10948		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
10949	    }
10950	}
10951#ifdef DEBUG_STEP
10952	xmlGenericError(xmlGenericErrorContext,
10953		"Basis : computing new set\n");
10954#endif
10955
10956#ifdef DEBUG_STEP
10957	xmlGenericError(xmlGenericErrorContext, "Basis : ");
10958	if (ctxt->value == NULL)
10959	    xmlGenericError(xmlGenericErrorContext, "no value\n");
10960	else if (ctxt->value->nodesetval == NULL)
10961	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
10962	else
10963	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
10964#endif
10965
10966#ifdef LIBXML_XPTR_ENABLED
10967eval_predicates:
10968#endif
10969	op1 = ctxt->comp->last;
10970	ctxt->comp->last = -1;
10971
10972	SKIP_BLANKS;
10973	while (CUR == '[') {
10974	    xmlXPathCompPredicate(ctxt, 0);
10975	}
10976
10977#ifdef LIBXML_XPTR_ENABLED
10978	if (rangeto) {
10979	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
10980	} else
10981#endif
10982	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
10983			   test, type, (void *)prefix, (void *)name);
10984
10985    }
10986#ifdef DEBUG_STEP
10987    xmlGenericError(xmlGenericErrorContext, "Step : ");
10988    if (ctxt->value == NULL)
10989	xmlGenericError(xmlGenericErrorContext, "no value\n");
10990    else if (ctxt->value->nodesetval == NULL)
10991	xmlGenericError(xmlGenericErrorContext, "Empty\n");
10992    else
10993	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
10994		ctxt->value->nodesetval);
10995#endif
10996}
10997
10998/**
10999 * xmlXPathCompRelativeLocationPath:
11000 * @ctxt:  the XPath Parser context
11001 *
11002 *  [3]   RelativeLocationPath ::=   Step
11003 *                     | RelativeLocationPath '/' Step
11004 *                     | AbbreviatedRelativeLocationPath
11005 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11006 *
11007 * Compile a relative location path.
11008 */
11009static void
11010xmlXPathCompRelativeLocationPath
11011(xmlXPathParserContextPtr ctxt) {
11012    SKIP_BLANKS;
11013    if ((CUR == '/') && (NXT(1) == '/')) {
11014	SKIP(2);
11015	SKIP_BLANKS;
11016	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11017		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11018    } else if (CUR == '/') {
11019	    NEXT;
11020	SKIP_BLANKS;
11021    }
11022    xmlXPathCompStep(ctxt);
11023    SKIP_BLANKS;
11024    while (CUR == '/') {
11025	if ((CUR == '/') && (NXT(1) == '/')) {
11026	    SKIP(2);
11027	    SKIP_BLANKS;
11028	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11029			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11030	    xmlXPathCompStep(ctxt);
11031	} else if (CUR == '/') {
11032	    NEXT;
11033	    SKIP_BLANKS;
11034	    xmlXPathCompStep(ctxt);
11035	}
11036	SKIP_BLANKS;
11037    }
11038}
11039
11040/**
11041 * xmlXPathCompLocationPath:
11042 * @ctxt:  the XPath Parser context
11043 *
11044 *  [1]   LocationPath ::=   RelativeLocationPath
11045 *                     | AbsoluteLocationPath
11046 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11047 *                     | AbbreviatedAbsoluteLocationPath
11048 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11049 *                           '//' RelativeLocationPath
11050 *
11051 * Compile a location path
11052 *
11053 * // is short for /descendant-or-self::node()/. For example,
11054 * //para is short for /descendant-or-self::node()/child::para and
11055 * so will select any para element in the document (even a para element
11056 * that is a document element will be selected by //para since the
11057 * document element node is a child of the root node); div//para is
11058 * short for div/descendant-or-self::node()/child::para and so will
11059 * select all para descendants of div children.
11060 */
11061static void
11062xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11063    SKIP_BLANKS;
11064    if (CUR != '/') {
11065        xmlXPathCompRelativeLocationPath(ctxt);
11066    } else {
11067	while (CUR == '/') {
11068	    if ((CUR == '/') && (NXT(1) == '/')) {
11069		SKIP(2);
11070		SKIP_BLANKS;
11071		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11072			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11073		xmlXPathCompRelativeLocationPath(ctxt);
11074	    } else if (CUR == '/') {
11075		NEXT;
11076		SKIP_BLANKS;
11077		if ((CUR != 0 ) &&
11078		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11079		     (CUR == '@') || (CUR == '*')))
11080		    xmlXPathCompRelativeLocationPath(ctxt);
11081	    }
11082	}
11083    }
11084}
11085
11086/************************************************************************
11087 *									*
11088 * 		XPath precompiled expression evaluation			*
11089 *									*
11090 ************************************************************************/
11091
11092static int
11093xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11094
11095/**
11096 * xmlXPathNodeCollectAndTest:
11097 * @ctxt:  the XPath Parser context
11098 * @op:  the XPath precompiled step operation
11099 * @first:  pointer to the first element in document order
11100 * @last:  pointer to the last element in document order
11101 *
11102 * This is the function implementing a step: based on the current list
11103 * of nodes, it builds up a new list, looking at all nodes under that
11104 * axis and selecting them. It also does the predicate filtering
11105 *
11106 * Pushes the new NodeSet resulting from the search.
11107 *
11108 * Returns the number of nodes traversed
11109 */
11110static int
11111xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11112                           xmlXPathStepOpPtr op,
11113			   xmlNodePtr * first, xmlNodePtr * last)
11114{
11115    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11116    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11117    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11118    const xmlChar *prefix = op->value4;
11119    const xmlChar *name = op->value5;
11120    const xmlChar *URI = NULL;
11121
11122#ifdef DEBUG_STEP
11123    int nbMatches = 0;
11124#endif
11125    int inputIdx, total = 0, specialNodeInSet = 0;
11126    xmlNodeSetPtr inputList, resultList, list;
11127    xmlXPathTraversalFunction next = NULL;
11128    xmlXPathTraversalFunctionExt compoundNext = NULL;
11129    void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11130    xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
11131    xmlNodePtr oldContextNode, contextNode, cur, compoundContextNode;
11132    xmlXPathObjectPtr obj;
11133    xmlXPathContextPtr xpctxt = ctxt->context;
11134
11135    CHECK_TYPE0(XPATH_NODESET);
11136    obj = valuePop(ctxt);
11137
11138    /*
11139    * Setup wrt namespaces.
11140    */
11141    if (prefix != NULL) {
11142        URI = xmlXPathNsLookup(xpctxt, prefix);
11143        if (URI == NULL) {
11144	    xmlXPathFreeObject(obj);
11145            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11146	}
11147    }
11148
11149#ifdef DEBUG_STEP
11150    xmlGenericError(xmlGenericErrorContext, "new step : ");
11151#endif
11152
11153    /*
11154    * Setup wrt the axis.
11155    */
11156    addNode = xmlXPathNodeSetAdd;
11157    mergeNodeSet = xmlXPathNodeSetMerge;
11158    switch (axis) {
11159        case AXIS_ANCESTOR:
11160#ifdef DEBUG_STEP
11161            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11162#endif
11163            first = NULL;
11164            next = xmlXPathNextAncestor;
11165            break;
11166        case AXIS_ANCESTOR_OR_SELF:
11167#ifdef DEBUG_STEP
11168            xmlGenericError(xmlGenericErrorContext,
11169                            "axis 'ancestors-or-self' ");
11170#endif
11171            first = NULL;
11172            next = xmlXPathNextAncestorOrSelf;
11173            break;
11174        case AXIS_ATTRIBUTE:
11175#ifdef DEBUG_STEP
11176            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11177#endif
11178            first = NULL;
11179	    last = NULL;
11180            next = xmlXPathNextAttribute;
11181	    mergeNodeSet = xmlXPathNodeSetMergeUnique;
11182            break;
11183        case AXIS_CHILD:
11184#ifdef DEBUG_STEP
11185            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11186#endif
11187	    last = NULL;
11188	    if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11189		/*
11190		* This iterator will give us only nodes which can
11191		* hold element nodes.
11192		*/
11193		compoundNext = xmlXPathNextDescendantOrSelfElemParent;
11194	    }
11195	    if ((test == NODE_TEST_NAME) && (type == NODE_TYPE_NODE)) {
11196		/*
11197		* Optimization if an element node type is 'element'.
11198		*/
11199		next = xmlXPathNextChildElement;
11200	    } else
11201		next = xmlXPathNextChild;
11202	    mergeNodeSet = xmlXPathNodeSetMergeUnique;
11203            break;
11204        case AXIS_DESCENDANT:
11205#ifdef DEBUG_STEP
11206            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11207#endif
11208	    last = NULL;
11209            next = xmlXPathNextDescendant;
11210            break;
11211        case AXIS_DESCENDANT_OR_SELF:
11212#ifdef DEBUG_STEP
11213            xmlGenericError(xmlGenericErrorContext,
11214                            "axis 'descendant-or-self' ");
11215#endif
11216	    last = NULL;
11217            next = xmlXPathNextDescendantOrSelf;
11218            break;
11219        case AXIS_FOLLOWING:
11220#ifdef DEBUG_STEP
11221            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11222#endif
11223	    last = NULL;
11224            next = xmlXPathNextFollowing;
11225            break;
11226        case AXIS_FOLLOWING_SIBLING:
11227#ifdef DEBUG_STEP
11228            xmlGenericError(xmlGenericErrorContext,
11229                            "axis 'following-siblings' ");
11230#endif
11231	    last = NULL;
11232            next = xmlXPathNextFollowingSibling;
11233            break;
11234        case AXIS_NAMESPACE:
11235#ifdef DEBUG_STEP
11236            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11237#endif
11238            first = NULL;
11239	    last = NULL;
11240            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11241	    mergeNodeSet = xmlXPathNodeSetMergeUnique;
11242            break;
11243        case AXIS_PARENT:
11244#ifdef DEBUG_STEP
11245            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11246#endif
11247            first = NULL;
11248            next = xmlXPathNextParent;
11249            break;
11250        case AXIS_PRECEDING:
11251#ifdef DEBUG_STEP
11252            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11253#endif
11254            first = NULL;
11255            next = xmlXPathNextPrecedingInternal;
11256            break;
11257        case AXIS_PRECEDING_SIBLING:
11258#ifdef DEBUG_STEP
11259            xmlGenericError(xmlGenericErrorContext,
11260                            "axis 'preceding-sibling' ");
11261#endif
11262            first = NULL;
11263            next = xmlXPathNextPrecedingSibling;
11264            break;
11265        case AXIS_SELF:
11266#ifdef DEBUG_STEP
11267            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11268#endif
11269            first = NULL;
11270	    last = NULL;
11271            next = xmlXPathNextSelf;
11272	    mergeNodeSet = xmlXPathNodeSetMergeUnique;
11273            break;
11274    }
11275    if (next == NULL) {
11276	xmlXPathReleaseObject(xpctxt, obj);
11277        return(0);
11278    }
11279
11280    inputList = obj->nodesetval;
11281    if ((inputList == NULL) || (inputList->nodeNr <= 0)) {
11282	xmlXPathReleaseObject(xpctxt, obj);
11283        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
11284        return(0);
11285    }
11286
11287#ifdef DEBUG_STEP
11288    xmlGenericError(xmlGenericErrorContext,
11289                    " context contains %d nodes\n", nodelist->nodeNr);
11290    switch (test) {
11291        case NODE_TEST_NONE:
11292            xmlGenericError(xmlGenericErrorContext,
11293                            "           searching for none !!!\n");
11294            break;
11295        case NODE_TEST_TYPE:
11296            xmlGenericError(xmlGenericErrorContext,
11297                            "           searching for type %d\n", type);
11298            break;
11299        case NODE_TEST_PI:
11300            xmlGenericError(xmlGenericErrorContext,
11301                            "           searching for PI !!!\n");
11302            break;
11303        case NODE_TEST_ALL:
11304            xmlGenericError(xmlGenericErrorContext,
11305                            "           searching for *\n");
11306            break;
11307        case NODE_TEST_NS:
11308            xmlGenericError(xmlGenericErrorContext,
11309                            "           searching for namespace %s\n",
11310                            prefix);
11311            break;
11312        case NODE_TEST_NAME:
11313            xmlGenericError(xmlGenericErrorContext,
11314                            "           searching for name %s\n", name);
11315            if (prefix != NULL)
11316                xmlGenericError(xmlGenericErrorContext,
11317                                "           with namespace %s\n", prefix);
11318            break;
11319    }
11320    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11321#endif
11322    /*
11323     * 2.3 Node Tests
11324     *  - For the attribute axis, the principal node type is attribute.
11325     *  - For the namespace axis, the principal node type is namespace.
11326     *  - For other axes, the principal node type is element.
11327     *
11328     * A node test * is true for any node of the
11329     * principal node type. For example, child::* will
11330     * select all element children of the context node
11331     */
11332    oldContextNode = xpctxt->node;
11333    addNode = xmlXPathNodeSetAddUnique;
11334    resultList = NULL;
11335    list = NULL;
11336    compoundContextNode = NULL;
11337    contextNode = NULL;
11338    inputIdx = 0;
11339
11340    while ((inputIdx < inputList->nodeNr) || (contextNode != NULL)) {
11341	if (compoundNext != NULL) {
11342	    /*
11343	    * This is a compound traversal.
11344	    */
11345	    if (contextNode == NULL) {
11346		/*
11347		* Set the context for the initial traversal.
11348		*/
11349		compoundContextNode = inputList->nodeTab[inputIdx++];
11350		contextNode = compoundNext(NULL, compoundContextNode);
11351	    } else
11352		contextNode = compoundNext(contextNode, compoundContextNode);
11353	    if (contextNode == NULL)
11354		continue;
11355	    /*
11356	    * Set the context for the main traversal.
11357	    */
11358	    xpctxt->node = contextNode;
11359	} else
11360	    xpctxt->node = inputList->nodeTab[inputIdx++];
11361
11362	if (list == NULL) {
11363	    list = xmlXPathNodeSetCreate(NULL);
11364	    if (list == NULL) {
11365		total = 0;
11366		goto error;
11367	    }
11368	}
11369	cur = NULL;
11370	specialNodeInSet = 0;
11371        do {
11372            cur = next(ctxt, cur);
11373            if (cur == NULL)
11374                break;
11375
11376            if (first != NULL) {
11377		if (*first == cur)
11378		    break;
11379		if ((*first != NULL) &&
11380		    ((total % 256) == 0) &&
11381#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11382		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
11383#else
11384		    (xmlXPathCmpNodes(*first, cur) >= 0))
11385#endif
11386		{
11387		    break;
11388		}
11389	    }
11390	    if (last != NULL) {
11391		if (*last == cur)
11392		    break;
11393		if ((*last != NULL) &&
11394		    ((total % 256) == 0) &&
11395#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11396		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
11397#else
11398		    (xmlXPathCmpNodes(cur, *last) >= 0))
11399#endif
11400		{
11401		    break;
11402		}
11403	    }
11404
11405            total++;
11406#ifdef DEBUG_STEP
11407            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
11408#endif
11409            switch (test) {
11410                case NODE_TEST_NONE:
11411		    STRANGE
11412		    goto error;
11413                case NODE_TEST_TYPE:
11414                    if ((cur->type == type) ||
11415                        ((type == NODE_TYPE_NODE) &&
11416                         ((cur->type == XML_DOCUMENT_NODE) ||
11417                          (cur->type == XML_HTML_DOCUMENT_NODE) ||
11418                          (cur->type == XML_ELEMENT_NODE) ||
11419                          (cur->type == XML_NAMESPACE_DECL) ||
11420                          (cur->type == XML_ATTRIBUTE_NODE) ||
11421                          (cur->type == XML_PI_NODE) ||
11422                          (cur->type == XML_COMMENT_NODE) ||
11423                          (cur->type == XML_CDATA_SECTION_NODE) ||
11424                          (cur->type == XML_TEXT_NODE))) ||
11425			((type == NODE_TYPE_TEXT) &&
11426			 (cur->type == XML_CDATA_SECTION_NODE)))
11427		    {
11428#ifdef DEBUG_STEP
11429                        nbMatches++;
11430#endif
11431			if (cur->type == XML_NAMESPACE_DECL)
11432			    specialNodeInSet = 1;
11433			/*
11434			* TODO: Don't we need to use xmlXPathNodeSetAddNs()
11435			* for namespace nodes here ?
11436			*/
11437                        addNode(list, cur);
11438                    }
11439                    break;
11440                case NODE_TEST_PI:
11441                    if ((cur->type == XML_PI_NODE) &&
11442                        ((name == NULL) || xmlStrEqual(name, cur->name)))
11443		    {
11444#ifdef DEBUG_STEP
11445                        nbMatches++;
11446#endif
11447                        addNode(list, cur);
11448                    }
11449                    break;
11450                case NODE_TEST_ALL:
11451                    if (axis == AXIS_ATTRIBUTE) {
11452                        if (cur->type == XML_ATTRIBUTE_NODE) {
11453#ifdef DEBUG_STEP
11454                            nbMatches++;
11455#endif
11456                            addNode(list, cur);
11457                        }
11458                    } else if (axis == AXIS_NAMESPACE) {
11459                        if (cur->type == XML_NAMESPACE_DECL) {
11460#ifdef DEBUG_STEP
11461                            nbMatches++;
11462#endif
11463			    specialNodeInSet = 1;
11464                            xmlXPathNodeSetAddNs(list, xpctxt->node,
11465				(xmlNsPtr) cur);
11466                        }
11467                    } else {
11468                        if (cur->type == XML_ELEMENT_NODE) {
11469                            if (prefix == NULL) {
11470#ifdef DEBUG_STEP
11471                                nbMatches++;
11472#endif
11473                                addNode(list, cur);
11474                            } else if ((cur->ns != NULL) &&
11475                                       (xmlStrEqual(URI, cur->ns->href)))
11476			    {
11477#ifdef DEBUG_STEP
11478                                nbMatches++;
11479#endif
11480                                addNode(list, cur);
11481                            }
11482                        }
11483                    }
11484                    break;
11485                case NODE_TEST_NS:{
11486                        TODO;
11487                        break;
11488                    }
11489                case NODE_TEST_NAME:
11490                    switch (cur->type) {
11491                        case XML_ELEMENT_NODE:
11492			    if (xmlStrEqual(name, cur->name)) {
11493                                if (prefix == NULL) {
11494                                    if (cur->ns == NULL) {
11495#ifdef DEBUG_STEP
11496                                        nbMatches++;
11497#endif
11498                                        addNode(list, cur);
11499                                    }
11500                                } else {
11501                                    if ((cur->ns != NULL) &&
11502                                        (xmlStrEqual(URI,
11503                                                     cur->ns->href)))
11504				    {
11505#ifdef DEBUG_STEP
11506                                        nbMatches++;
11507#endif
11508                                        addNode(list, cur);
11509                                    }
11510                                }
11511                            }
11512                            break;
11513                        case XML_ATTRIBUTE_NODE:{
11514                                xmlAttrPtr attr = (xmlAttrPtr) cur;
11515
11516                                if (xmlStrEqual(name, attr->name)) {
11517                                    if (prefix == NULL) {
11518                                        if ((attr->ns == NULL) ||
11519                                            (attr->ns->prefix == NULL)) {
11520#ifdef DEBUG_STEP
11521                                            nbMatches++;
11522#endif
11523                                            addNode(list,
11524                                                    (xmlNodePtr) attr);
11525                                        }
11526                                    } else {
11527                                        if ((attr->ns != NULL) &&
11528                                            (xmlStrEqual(URI,
11529                                                         attr->ns->
11530                                                         href)))
11531					{
11532#ifdef DEBUG_STEP
11533                                            nbMatches++;
11534#endif
11535                                            addNode(list,
11536                                                    (xmlNodePtr) attr);
11537                                        }
11538                                    }
11539                                }
11540                                break;
11541                            }
11542                        case XML_NAMESPACE_DECL:
11543                            if (cur->type == XML_NAMESPACE_DECL) {
11544                                xmlNsPtr ns = (xmlNsPtr) cur;
11545
11546                                if ((ns->prefix != NULL) && (name != NULL)
11547                                    && (xmlStrEqual(ns->prefix, name)))
11548				{
11549#ifdef DEBUG_STEP
11550                                    nbMatches++;
11551#endif
11552				    specialNodeInSet = 1;
11553				    xmlXPathNodeSetAddNs(list,
11554					xpctxt->node, (xmlNsPtr) cur);
11555                                }
11556                            }
11557                            break;
11558                        default:
11559                            break;
11560                    } /* switch (cur->type) */
11561                    break; /*  case NODE_TEST_NAME: */
11562            } /* switch (test) */
11563        } while (cur != NULL);
11564
11565        /*
11566         * If there is some predicate filtering do it now
11567         */
11568        if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
11569            xmlXPathObjectPtr obj2;
11570
11571	    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, list));
11572            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
11573            CHECK_TYPE0(XPATH_NODESET);
11574            obj2 = valuePop(ctxt);
11575            list = obj2->nodesetval;
11576            obj2->nodesetval = NULL;
11577	    xmlXPathReleaseObject(xpctxt, obj2);
11578
11579	    if (ctxt->error != XPATH_EXPRESSION_OK) {
11580		total = 0;
11581		goto error;
11582	    }
11583        }
11584        if (resultList == NULL) {
11585            resultList = list;
11586	    list = NULL;
11587        } else if ((list != NULL) && (list->nodeNr > 0)) {
11588            resultList = mergeNodeSet(resultList, list);
11589	    /*
11590	    * This is the list containing the current matching nodes.
11591	    * Avoid massive creation/freeing and preserve it for the
11592	    * next iterations.
11593	    */
11594	    /* If a namespace node was put it, then we need a more
11595	    * time consuming cleanup.
11596	    */
11597	    if (specialNodeInSet)
11598		xmlXPathNodeSetClear(list);
11599	    else
11600		list->nodeNr = 0;
11601        }
11602    }
11603
11604    xpctxt->node = oldContextNode;
11605    /*
11606    * Cleanup the temporary list of current node-test matches.
11607    */
11608    if ((list != NULL) && (list != resultList)) {
11609	 xmlXPathFreeNodeSet(list);
11610	 list = NULL;
11611    }
11612
11613#ifdef DEBUG_STEP
11614    xmlGenericError(xmlGenericErrorContext,
11615                    "\nExamined %d nodes, found %d nodes at that step\n",
11616                    total, nbMatches);
11617#endif
11618
11619    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, resultList));
11620
11621    if ((obj->boolval) && (obj->user != NULL)) {
11622	/*
11623	* QUESTION TODO: What does this do and why?
11624	*/
11625	ctxt->value->boolval = 1;
11626	ctxt->value->user = obj->user;
11627	obj->user = NULL;
11628	obj->boolval = 0;
11629    }
11630    xmlXPathReleaseObject(xpctxt, obj);
11631    return(total);
11632
11633error:
11634    xpctxt->node = oldContextNode;
11635    xmlXPathReleaseObject(xpctxt, obj);
11636    if ((list != NULL) && (list != resultList)) {
11637	 xmlXPathFreeNodeSet(list);
11638    }
11639    if (resultList != NULL)
11640	xmlXPathFreeNodeSet(resultList);
11641    return(total);
11642}
11643
11644/**
11645 * xmlXPathNodeCollectAndTestNth:
11646 * @ctxt:  the XPath Parser context
11647 * @op:  the XPath precompiled step operation
11648 * @reqpos:  the requested position wrt to the axis
11649 * @first:  pointer to the first element in document order
11650 * @last:  pointer to the last element in document order
11651 *
11652 * This is the function implementing a step: based on the current list
11653 * of nodes, it builds up a new list, looking at all nodes under that
11654 * axis and selecting them. It also does the predicate filtering
11655 *
11656 * Pushes the new NodeSet resulting from the search.
11657 * Returns the number of node traversed
11658 */
11659static int
11660xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
11661                              xmlXPathStepOpPtr op, int reqpos,
11662                              xmlNodePtr * first, xmlNodePtr * last)
11663{
11664    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11665    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11666    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11667    const xmlChar *prefix = op->value4;
11668    const xmlChar *name = op->value5;
11669    const xmlChar *URI = NULL;
11670    int pos; /* The current context position */
11671
11672    int inputIdx, total = 0;
11673    xmlNodeSetPtr inputList, list;
11674    xmlXPathTraversalFunction next = NULL;
11675    xmlXPathTraversalFunctionExt compoundNext = NULL;
11676    void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11677    xmlNodePtr oldContextNode, contextNode, cur, compoundContextNode;
11678    xmlXPathObjectPtr obj;
11679    xmlXPathContextPtr xpctxt = ctxt->context;
11680
11681
11682    CHECK_TYPE0(XPATH_NODESET);
11683    obj = valuePop(ctxt);
11684    addNode = xmlXPathNodeSetAdd;
11685
11686    if (prefix != NULL) {
11687        URI = xmlXPathNsLookup(xpctxt, prefix);
11688        if (URI == NULL) {
11689	    xmlXPathFreeObject(obj);
11690            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11691	}
11692    }
11693
11694#ifdef DEBUG_STEP_NTH
11695    xmlGenericError(xmlGenericErrorContext, "new step : ");
11696    if (first != NULL) {
11697	if (*first != NULL)
11698	    xmlGenericError(xmlGenericErrorContext, "first = %s ",
11699		    (*first)->name);
11700	else
11701	    xmlGenericError(xmlGenericErrorContext, "first = NULL ");
11702    }
11703    if (last != NULL) {
11704	if (*last != NULL)
11705	    xmlGenericError(xmlGenericErrorContext, "last = %s ",
11706		    (*last)->name);
11707	else
11708	    xmlGenericError(xmlGenericErrorContext, "last = NULL ");
11709    }
11710#endif
11711    switch (axis) {
11712        case AXIS_ANCESTOR:
11713#ifdef DEBUG_STEP_NTH
11714            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11715#endif
11716            first = NULL;
11717            next = xmlXPathNextAncestor;
11718            break;
11719        case AXIS_ANCESTOR_OR_SELF:
11720#ifdef DEBUG_STEP_NTH
11721            xmlGenericError(xmlGenericErrorContext,
11722                            "axis 'ancestors-or-self' ");
11723#endif
11724            first = NULL;
11725            next = xmlXPathNextAncestorOrSelf;
11726            break;
11727        case AXIS_ATTRIBUTE:
11728#ifdef DEBUG_STEP_NTH
11729            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11730#endif
11731            first = NULL;
11732	    last = NULL;
11733            next = xmlXPathNextAttribute;
11734            break;
11735        case AXIS_CHILD:
11736#ifdef DEBUG_STEP_NTH
11737            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11738#endif
11739	    last = NULL;
11740	    if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11741		/*
11742		* This iterator will give us only nodes which can
11743		* hold element nodes.
11744		*/
11745		compoundNext = xmlXPathNextDescendantOrSelfElemParent;
11746	    }
11747	    if ((test == NODE_TEST_NAME) && (type == NODE_TYPE_NODE)) {
11748		/*
11749		* Optimization if an element node type is 'element'.
11750		*/
11751		next = xmlXPathNextChildElement;
11752	    } else
11753		next = xmlXPathNextChild;
11754            break;
11755        case AXIS_DESCENDANT:
11756#ifdef DEBUG_STEP_NTH
11757            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11758#endif
11759	    last = NULL;
11760            next = xmlXPathNextDescendant;
11761            break;
11762        case AXIS_DESCENDANT_OR_SELF:
11763#ifdef DEBUG_STEP_NTH
11764            xmlGenericError(xmlGenericErrorContext,
11765                            "axis 'descendant-or-self' ");
11766#endif
11767	    last = NULL;
11768            next = xmlXPathNextDescendantOrSelf;
11769            break;
11770        case AXIS_FOLLOWING:
11771#ifdef DEBUG_STEP_NTH
11772            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11773#endif
11774	    last = NULL;
11775            next = xmlXPathNextFollowing;
11776            break;
11777        case AXIS_FOLLOWING_SIBLING:
11778#ifdef DEBUG_STEP_NTH
11779            xmlGenericError(xmlGenericErrorContext,
11780                            "axis 'following-siblings' ");
11781#endif
11782	    last = NULL;
11783            next = xmlXPathNextFollowingSibling;
11784            break;
11785        case AXIS_NAMESPACE:
11786#ifdef DEBUG_STEP_NTH
11787            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11788#endif
11789	    last = NULL;
11790            first = NULL;
11791            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11792            break;
11793        case AXIS_PARENT:
11794#ifdef DEBUG_STEP_NTH
11795            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11796#endif
11797            first = NULL;
11798            next = xmlXPathNextParent;
11799            break;
11800        case AXIS_PRECEDING:
11801#ifdef DEBUG_STEP_NTH
11802            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11803#endif
11804            first = NULL;
11805            next = xmlXPathNextPrecedingInternal;
11806            break;
11807        case AXIS_PRECEDING_SIBLING:
11808#ifdef DEBUG_STEP_NTH
11809            xmlGenericError(xmlGenericErrorContext,
11810                            "axis 'preceding-sibling' ");
11811#endif
11812            first = NULL;
11813            next = xmlXPathNextPrecedingSibling;
11814            break;
11815        case AXIS_SELF:
11816#ifdef DEBUG_STEP_NTH
11817            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11818#endif
11819            first = NULL;
11820	    last = NULL;
11821            next = xmlXPathNextSelf;
11822            break;
11823    }
11824    if (next == NULL) {
11825	xmlXPathReleaseObject(xpctxt, obj);
11826        return(0);
11827    }
11828
11829    inputList = obj->nodesetval;
11830    if ((inputList == NULL) || (inputList->nodeNr <= 0)) {
11831        xmlXPathReleaseObject(xpctxt, obj);
11832	valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
11833        return(0);
11834    }
11835
11836#ifdef DEBUG_STEP_NTH
11837    xmlGenericError(xmlGenericErrorContext,
11838                    " context contains %d nodes\n", nodelist->nodeNr);
11839    switch (test) {
11840        case NODE_TEST_NONE:
11841            xmlGenericError(xmlGenericErrorContext,
11842                            "           searching for none !!!\n");
11843            break;
11844        case NODE_TEST_TYPE:
11845            xmlGenericError(xmlGenericErrorContext,
11846                            "           searching for type %d\n", type);
11847            break;
11848        case NODE_TEST_PI:
11849            xmlGenericError(xmlGenericErrorContext,
11850                            "           searching for PI !!!\n");
11851            break;
11852        case NODE_TEST_ALL:
11853            xmlGenericError(xmlGenericErrorContext,
11854                            "           searching for *\n");
11855            break;
11856        case NODE_TEST_NS:
11857            xmlGenericError(xmlGenericErrorContext,
11858                            "           searching for namespace %s\n",
11859                            prefix);
11860            break;
11861        case NODE_TEST_NAME:
11862            xmlGenericError(xmlGenericErrorContext,
11863                            "           searching for name %s\n", name);
11864            if (prefix != NULL)
11865                xmlGenericError(xmlGenericErrorContext,
11866                                "           with namespace %s\n", prefix);
11867            break;
11868    }
11869    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11870#endif
11871    /*
11872     * 2.3 Node Tests
11873     *  - For the attribute axis, the principal node type is attribute.
11874     *  - For the namespace axis, the principal node type is namespace.
11875     *  - For other axes, the principal node type is element.
11876     *
11877     * A node test * is true for any node of the
11878     * principal node type. For example, child::* will
11879     * select all element children of the context node
11880     */
11881    oldContextNode = xpctxt->node;
11882    addNode = xmlXPathNodeSetAddUnique;
11883    list = NULL;
11884    compoundContextNode = NULL;
11885    contextNode = NULL;
11886    inputIdx = 0;
11887    list = xmlXPathNodeSetCreate(NULL);
11888
11889    while ((inputIdx < inputList->nodeNr) || (contextNode != NULL)) {
11890	if (compoundNext != NULL) {
11891	    /*
11892	    * This is a compound traversal.
11893	    */
11894	    if (contextNode == NULL) {
11895		/*
11896		* Set the context for the initial traversal.
11897		*/
11898		compoundContextNode = inputList->nodeTab[inputIdx++];
11899		contextNode = compoundNext(NULL, compoundContextNode);
11900	    } else
11901		contextNode = compoundNext(contextNode, compoundContextNode);
11902	    if (contextNode == NULL)
11903		continue;
11904	    /*
11905	    * Set the context for the main traversal.
11906	    */
11907	    xpctxt->node = contextNode;
11908	} else
11909	    xpctxt->node = inputList->nodeTab[inputIdx++];
11910
11911        cur = NULL;
11912        pos = 0;
11913        do {
11914            cur = next(ctxt, cur);
11915            if (cur == NULL)
11916                break;
11917
11918	    if (first != NULL) {
11919		if (*first == cur)
11920		    break;
11921		if ((*first != NULL) &&
11922		    ((total % 256) == 0) &&
11923#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11924		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
11925#else
11926		    (xmlXPathCmpNodes(*first, cur) >= 0))
11927#endif
11928		{
11929		    break;
11930		}
11931	    }
11932	    if (last != NULL) {
11933		if (*last == cur)
11934		    break;
11935		if ((*last != NULL) &&
11936		    ((total % 256) == 0) &&
11937#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11938		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
11939#else
11940		    (xmlXPathCmpNodes(cur, *last) >= 0))
11941#endif
11942		{
11943		    break;
11944		}
11945	    }
11946
11947            total++;
11948            switch (test) {
11949                case NODE_TEST_NONE:
11950		    total = 0;
11951                    STRANGE
11952		    goto error;
11953                case NODE_TEST_TYPE:
11954                    if ((cur->type == type) ||
11955                        ((type == NODE_TYPE_NODE) &&
11956                         ((cur->type == XML_DOCUMENT_NODE) ||
11957                          (cur->type == XML_HTML_DOCUMENT_NODE) ||
11958                          (cur->type == XML_ELEMENT_NODE) ||
11959                          (cur->type == XML_PI_NODE) ||
11960                          (cur->type == XML_COMMENT_NODE) ||
11961                          (cur->type == XML_CDATA_SECTION_NODE) ||
11962                          (cur->type == XML_TEXT_NODE))) ||
11963			((type == NODE_TYPE_TEXT) &&
11964			 (cur->type == XML_CDATA_SECTION_NODE))) {
11965                        pos++;
11966                        if (pos == reqpos)
11967                            addNode(list, cur);
11968                    }
11969                    break;
11970                case NODE_TEST_PI:
11971                    if (cur->type == XML_PI_NODE) {
11972                        if ((name != NULL) &&
11973                            (!xmlStrEqual(name, cur->name)))
11974                            break;
11975                        pos++;
11976                        if (pos == reqpos)
11977                            addNode(list, cur);
11978                    }
11979                    break;
11980                case NODE_TEST_ALL:
11981                    if (axis == AXIS_ATTRIBUTE) {
11982                        if (cur->type == XML_ATTRIBUTE_NODE) {
11983                            pos++;
11984                            if (pos == reqpos)
11985                                addNode(list, cur);
11986                        }
11987                    } else if (axis == AXIS_NAMESPACE) {
11988                        if (cur->type == XML_NAMESPACE_DECL) {
11989                            pos++;
11990                            if (pos == reqpos)
11991				xmlXPathNodeSetAddNs(list, xpctxt->node,
11992						     (xmlNsPtr) cur);
11993                        }
11994                    } else {
11995                        if (cur->type == XML_ELEMENT_NODE) {
11996                            if (prefix == NULL) {
11997                                pos++;
11998                                if (pos == reqpos)
11999                                    addNode(list, cur);
12000                            } else if ((cur->ns != NULL) &&
12001                                       (xmlStrEqual(URI, cur->ns->href))) {
12002                                pos++;
12003                                if (pos == reqpos)
12004                                    addNode(list, cur);
12005                            }
12006                        }
12007                    }
12008                    break;
12009                case NODE_TEST_NS:{
12010                        TODO;
12011                        break;
12012                    }
12013                case NODE_TEST_NAME:
12014                    switch (cur->type) {
12015                        case XML_ELEMENT_NODE:
12016                            if (xmlStrEqual(name, cur->name)) {
12017                                if (prefix == NULL) {
12018                                    if (cur->ns == NULL) {
12019                                        pos++;
12020                                        if (pos == reqpos)
12021                                            addNode(list, cur);
12022                                    }
12023                                } else {
12024                                    if ((cur->ns != NULL) &&
12025                                        (xmlStrEqual(URI,
12026					    cur->ns->href)))
12027				    {
12028                                        pos++;
12029                                        if (pos == reqpos)
12030                                            addNode(list, cur);
12031                                    }
12032                                }
12033                            }
12034                            break;
12035                        case XML_ATTRIBUTE_NODE:{
12036                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12037
12038                                if (xmlStrEqual(name, attr->name)) {
12039                                    if (prefix == NULL) {
12040                                        if ((attr->ns == NULL) ||
12041                                            (attr->ns->prefix == NULL))
12042					{
12043                                            pos++;
12044                                            if (pos == reqpos)
12045                                                addNode(list, cur);
12046                                        }
12047                                    } else {
12048                                        if ((attr->ns != NULL) &&
12049                                            (xmlStrEqual(URI,
12050					      attr->ns->href)))
12051					{
12052                                            pos++;
12053                                            if (pos == reqpos)
12054                                                addNode(list, cur);
12055                                        }
12056                                    }
12057                                }
12058                                break;
12059                            }
12060                        case XML_NAMESPACE_DECL:
12061                            if (cur->type == XML_NAMESPACE_DECL) {
12062                                xmlNsPtr ns = (xmlNsPtr) cur;
12063
12064                                if ((ns->prefix != NULL) && (name != NULL)
12065                                    && (xmlStrEqual(ns->prefix, name))) {
12066                                    pos++;
12067                                    if (pos == reqpos)
12068					xmlXPathNodeSetAddNs(list,
12069					   xpctxt->node, (xmlNsPtr) cur);
12070                                }
12071                            }
12072                            break;
12073                        default:
12074                            break;
12075                    }
12076                    break;
12077            }
12078        } while (pos < reqpos);
12079    }
12080    xpctxt->node = oldContextNode;
12081
12082#ifdef DEBUG_STEP_NTH
12083    xmlGenericError(xmlGenericErrorContext,
12084                    "\nExamined %d nodes, found %d nodes at that step\n",
12085                    total, list->nodeNr);
12086#endif
12087
12088    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, list));
12089
12090    if ((obj->boolval) && (obj->user != NULL)) {
12091	ctxt->value->boolval = 1;
12092	ctxt->value->user = obj->user;
12093	obj->user = NULL;
12094	obj->boolval = 0;
12095    }
12096    xmlXPathReleaseObject(xpctxt, obj);
12097    return(total);
12098
12099error:
12100    xpctxt->node = oldContextNode;
12101    xmlXPathReleaseObject(xpctxt, obj);
12102    if (list != NULL)
12103	 xmlXPathFreeNodeSet(list);
12104    return(total);
12105}
12106
12107static int
12108xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12109			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12110
12111/**
12112 * xmlXPathCompOpEvalFirst:
12113 * @ctxt:  the XPath parser context with the compiled expression
12114 * @op:  an XPath compiled operation
12115 * @first:  the first elem found so far
12116 *
12117 * Evaluate the Precompiled XPath operation searching only the first
12118 * element in document order
12119 *
12120 * Returns the number of examined objects.
12121 */
12122static int
12123xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12124                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12125{
12126    int total = 0, cur;
12127    xmlXPathCompExprPtr comp;
12128    xmlXPathObjectPtr arg1, arg2;
12129
12130    CHECK_ERROR0;
12131    comp = ctxt->comp;
12132    switch (op->op) {
12133        case XPATH_OP_END:
12134            return (0);
12135        case XPATH_OP_UNION:
12136            total =
12137                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12138                                        first);
12139	    CHECK_ERROR0;
12140            if ((ctxt->value != NULL)
12141                && (ctxt->value->type == XPATH_NODESET)
12142                && (ctxt->value->nodesetval != NULL)
12143                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12144                /*
12145                 * limit tree traversing to first node in the result
12146                 */
12147		/*
12148		* OPTIMIZE TODO: This implicitely sorts
12149		*  the result, even if not needed. E.g. if the argument
12150		*  of the count() function, no sorting is needed.
12151		* OPTIMIZE TODO: How do we know if the node-list wasn't
12152		*  aready sorted?
12153		*/
12154		if (ctxt->value->nodesetval->nodeNr > 1)
12155		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12156                *first = ctxt->value->nodesetval->nodeTab[0];
12157            }
12158            cur =
12159                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12160                                        first);
12161	    CHECK_ERROR0;
12162            CHECK_TYPE0(XPATH_NODESET);
12163            arg2 = valuePop(ctxt);
12164
12165            CHECK_TYPE0(XPATH_NODESET);
12166            arg1 = valuePop(ctxt);
12167
12168            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12169                                                    arg2->nodesetval);
12170            valuePush(ctxt, arg1);
12171	    xmlXPathReleaseObject(ctxt->context, arg2);
12172            /* optimizer */
12173	    if (total > cur)
12174		xmlXPathCompSwap(op);
12175            return (total + cur);
12176        case XPATH_OP_ROOT:
12177            xmlXPathRoot(ctxt);
12178            return (0);
12179        case XPATH_OP_NODE:
12180            if (op->ch1 != -1)
12181                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12182	    CHECK_ERROR0;
12183            if (op->ch2 != -1)
12184                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12185	    CHECK_ERROR0;
12186	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12187		ctxt->context->node));
12188            return (total);
12189        case XPATH_OP_RESET:
12190            if (op->ch1 != -1)
12191                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12192	    CHECK_ERROR0;
12193            if (op->ch2 != -1)
12194                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12195	    CHECK_ERROR0;
12196            ctxt->context->node = NULL;
12197            return (total);
12198        case XPATH_OP_COLLECT:{
12199                if (op->ch1 == -1)
12200                    return (total);
12201
12202                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12203		CHECK_ERROR0;
12204
12205                /*
12206                 * Optimization for [n] selection where n is a number
12207                 */
12208                if ((op->ch2 != -1) &&
12209                    (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
12210                    (comp->steps[op->ch2].ch1 == -1) &&
12211                    (comp->steps[op->ch2].ch2 != -1) &&
12212                    (comp->steps[comp->steps[op->ch2].ch2].op ==
12213                     XPATH_OP_VALUE)) {
12214                    xmlXPathObjectPtr val;
12215
12216                    val = comp->steps[comp->steps[op->ch2].ch2].value4;
12217                    if ((val != NULL) && (val->type == XPATH_NUMBER)) {
12218                        int indx = (int) val->floatval;
12219
12220                        if (val->floatval == (float) indx) {
12221                            xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
12222                                                          first, NULL);
12223                            return (total);
12224                        }
12225                    }
12226                }
12227                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
12228                return (total);
12229            }
12230        case XPATH_OP_VALUE:
12231            valuePush(ctxt,
12232                      xmlXPathCacheObjectCopy(ctxt->context,
12233			(xmlXPathObjectPtr) op->value4));
12234            return (0);
12235        case XPATH_OP_SORT:
12236            if (op->ch1 != -1)
12237                total +=
12238                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12239                                            first);
12240	    CHECK_ERROR0;
12241            if ((ctxt->value != NULL)
12242                && (ctxt->value->type == XPATH_NODESET)
12243                && (ctxt->value->nodesetval != NULL)
12244		&& (ctxt->value->nodesetval->nodeNr > 1))
12245                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12246            return (total);
12247#ifdef XP_OPTIMIZED_FILTER_FIRST
12248	case XPATH_OP_FILTER:
12249                total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12250            return (total);
12251#endif
12252        default:
12253            return (xmlXPathCompOpEval(ctxt, op));
12254    }
12255}
12256
12257/**
12258 * xmlXPathCompOpEvalLast:
12259 * @ctxt:  the XPath parser context with the compiled expression
12260 * @op:  an XPath compiled operation
12261 * @last:  the last elem found so far
12262 *
12263 * Evaluate the Precompiled XPath operation searching only the last
12264 * element in document order
12265 *
12266 * Returns the number of nodes traversed
12267 */
12268static int
12269xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12270                       xmlNodePtr * last)
12271{
12272    int total = 0, cur;
12273    xmlXPathCompExprPtr comp;
12274    xmlXPathObjectPtr arg1, arg2;
12275    xmlNodePtr bak;
12276    xmlDocPtr bakd;
12277    int pp;
12278    int cs;
12279
12280    CHECK_ERROR0;
12281    comp = ctxt->comp;
12282    switch (op->op) {
12283        case XPATH_OP_END:
12284            return (0);
12285        case XPATH_OP_UNION:
12286	    bakd = ctxt->context->doc;
12287	    bak = ctxt->context->node;
12288	    pp = ctxt->context->proximityPosition;
12289	    cs = ctxt->context->contextSize;
12290            total =
12291                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12292	    CHECK_ERROR0;
12293            if ((ctxt->value != NULL)
12294                && (ctxt->value->type == XPATH_NODESET)
12295                && (ctxt->value->nodesetval != NULL)
12296                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12297                /*
12298                 * limit tree traversing to first node in the result
12299                 */
12300		if (ctxt->value->nodesetval->nodeNr > 1)
12301		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12302                *last =
12303                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12304                                                     nodesetval->nodeNr -
12305                                                     1];
12306            }
12307	    ctxt->context->doc = bakd;
12308	    ctxt->context->node = bak;
12309	    ctxt->context->proximityPosition = pp;
12310	    ctxt->context->contextSize = cs;
12311            cur =
12312                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12313	    CHECK_ERROR0;
12314            if ((ctxt->value != NULL)
12315                && (ctxt->value->type == XPATH_NODESET)
12316                && (ctxt->value->nodesetval != NULL)
12317                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12318            }
12319            CHECK_TYPE0(XPATH_NODESET);
12320            arg2 = valuePop(ctxt);
12321
12322            CHECK_TYPE0(XPATH_NODESET);
12323            arg1 = valuePop(ctxt);
12324
12325            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12326                                                    arg2->nodesetval);
12327            valuePush(ctxt, arg1);
12328	    xmlXPathReleaseObject(ctxt->context, arg2);
12329            /* optimizer */
12330	    if (total > cur)
12331		xmlXPathCompSwap(op);
12332            return (total + cur);
12333        case XPATH_OP_ROOT:
12334            xmlXPathRoot(ctxt);
12335            return (0);
12336        case XPATH_OP_NODE:
12337            if (op->ch1 != -1)
12338                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12339	    CHECK_ERROR0;
12340            if (op->ch2 != -1)
12341                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12342	    CHECK_ERROR0;
12343	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12344		ctxt->context->node));
12345            return (total);
12346        case XPATH_OP_RESET:
12347            if (op->ch1 != -1)
12348                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12349	    CHECK_ERROR0;
12350            if (op->ch2 != -1)
12351                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12352	    CHECK_ERROR0;
12353            ctxt->context->node = NULL;
12354            return (total);
12355        case XPATH_OP_COLLECT:{
12356                if (op->ch1 == -1)
12357                    return (0);
12358
12359                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12360		CHECK_ERROR0;
12361
12362                /*
12363                 * Optimization for [n] selection where n is a number
12364                 */
12365                if ((op->ch2 != -1) &&
12366                    (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
12367                    (comp->steps[op->ch2].ch1 == -1) &&
12368                    (comp->steps[op->ch2].ch2 != -1) &&
12369                    (comp->steps[comp->steps[op->ch2].ch2].op ==
12370                     XPATH_OP_VALUE)) {
12371                    xmlXPathObjectPtr val;
12372
12373                    val = comp->steps[comp->steps[op->ch2].ch2].value4;
12374                    if ((val != NULL) && (val->type == XPATH_NUMBER)) {
12375                        int indx = (int) val->floatval;
12376
12377                        if (val->floatval == (float) indx) {
12378                            total +=
12379                                xmlXPathNodeCollectAndTestNth(ctxt, op,
12380                                                              indx, NULL,
12381                                                              last);
12382                            return (total);
12383                        }
12384                    }
12385                }
12386                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
12387                return (total);
12388            }
12389        case XPATH_OP_VALUE:
12390            valuePush(ctxt,
12391                      xmlXPathCacheObjectCopy(ctxt->context,
12392			(xmlXPathObjectPtr) op->value4));
12393            return (0);
12394        case XPATH_OP_SORT:
12395            if (op->ch1 != -1)
12396                total +=
12397                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12398                                           last);
12399	    CHECK_ERROR0;
12400            if ((ctxt->value != NULL)
12401                && (ctxt->value->type == XPATH_NODESET)
12402                && (ctxt->value->nodesetval != NULL)
12403		&& (ctxt->value->nodesetval->nodeNr > 1))
12404                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12405            return (total);
12406        default:
12407            return (xmlXPathCompOpEval(ctxt, op));
12408    }
12409}
12410
12411#ifdef XP_OPTIMIZED_FILTER_FIRST
12412static int
12413xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12414			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12415{
12416    int total = 0;
12417    xmlXPathCompExprPtr comp;
12418    xmlXPathObjectPtr res;
12419    xmlXPathObjectPtr obj;
12420    xmlNodeSetPtr oldset;
12421    xmlNodePtr oldnode;
12422    xmlDocPtr oldDoc;
12423    int i;
12424
12425    CHECK_ERROR0;
12426    comp = ctxt->comp;
12427    /*
12428    * Optimization for ()[last()] selection i.e. the last elem
12429    */
12430    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12431	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12432	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12433	int f = comp->steps[op->ch2].ch1;
12434
12435	if ((f != -1) &&
12436	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12437	    (comp->steps[f].value5 == NULL) &&
12438	    (comp->steps[f].value == 0) &&
12439	    (comp->steps[f].value4 != NULL) &&
12440	    (xmlStrEqual
12441	    (comp->steps[f].value4, BAD_CAST "last"))) {
12442	    xmlNodePtr last = NULL;
12443
12444	    total +=
12445		xmlXPathCompOpEvalLast(ctxt,
12446		    &comp->steps[op->ch1],
12447		    &last);
12448	    CHECK_ERROR0;
12449	    /*
12450	    * The nodeset should be in document order,
12451	    * Keep only the last value
12452	    */
12453	    if ((ctxt->value != NULL) &&
12454		(ctxt->value->type == XPATH_NODESET) &&
12455		(ctxt->value->nodesetval != NULL) &&
12456		(ctxt->value->nodesetval->nodeTab != NULL) &&
12457		(ctxt->value->nodesetval->nodeNr > 1)) {
12458		ctxt->value->nodesetval->nodeTab[0] =
12459		    ctxt->value->nodesetval->nodeTab[ctxt->
12460		    value->
12461		    nodesetval->
12462		    nodeNr -
12463		    1];
12464		ctxt->value->nodesetval->nodeNr = 1;
12465		*first = *(ctxt->value->nodesetval->nodeTab);
12466	    }
12467	    return (total);
12468	}
12469    }
12470
12471    if (op->ch1 != -1)
12472	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12473    CHECK_ERROR0;
12474    if (op->ch2 == -1)
12475	return (total);
12476    if (ctxt->value == NULL)
12477	return (total);
12478
12479#ifdef LIBXML_XPTR_ENABLED
12480    oldnode = ctxt->context->node;
12481    /*
12482    * Hum are we filtering the result of an XPointer expression
12483    */
12484    if (ctxt->value->type == XPATH_LOCATIONSET) {
12485	xmlXPathObjectPtr tmp = NULL;
12486	xmlLocationSetPtr newlocset = NULL;
12487	xmlLocationSetPtr oldlocset;
12488
12489	/*
12490	* Extract the old locset, and then evaluate the result of the
12491	* expression for all the element in the locset. use it to grow
12492	* up a new locset.
12493	*/
12494	CHECK_TYPE0(XPATH_LOCATIONSET);
12495	obj = valuePop(ctxt);
12496	oldlocset = obj->user;
12497	ctxt->context->node = NULL;
12498
12499	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12500	    ctxt->context->contextSize = 0;
12501	    ctxt->context->proximityPosition = 0;
12502	    if (op->ch2 != -1)
12503		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12504	    res = valuePop(ctxt);
12505	    if (res != NULL) {
12506		xmlXPathReleaseObject(ctxt->context, res);
12507	    }
12508	    valuePush(ctxt, obj);
12509	    CHECK_ERROR0;
12510	    return (total);
12511	}
12512	newlocset = xmlXPtrLocationSetCreate(NULL);
12513
12514	for (i = 0; i < oldlocset->locNr; i++) {
12515	    /*
12516	    * Run the evaluation with a node list made of a
12517	    * single item in the nodelocset.
12518	    */
12519	    ctxt->context->node = oldlocset->locTab[i]->user;
12520	    ctxt->context->contextSize = oldlocset->locNr;
12521	    ctxt->context->proximityPosition = i + 1;
12522	    if (tmp == NULL) {
12523		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12524		    ctxt->context->node);
12525	    } else {
12526		xmlXPathNodeSetAddUnique(tmp->nodesetval,
12527		    ctxt->context->node);
12528	    }
12529	    valuePush(ctxt, tmp);
12530	    if (op->ch2 != -1)
12531		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12532	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12533		xmlXPathFreeObject(obj);
12534		return(0);
12535	    }
12536	    /*
12537	    * The result of the evaluation need to be tested to
12538	    * decided whether the filter succeeded or not
12539	    */
12540	    res = valuePop(ctxt);
12541	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12542		xmlXPtrLocationSetAdd(newlocset,
12543		    xmlXPathCacheObjectCopy(ctxt->context,
12544			oldlocset->locTab[i]));
12545	    }
12546	    /*
12547	    * Cleanup
12548	    */
12549	    if (res != NULL) {
12550		xmlXPathReleaseObject(ctxt->context, res);
12551	    }
12552	    if (ctxt->value == tmp) {
12553		valuePop(ctxt);
12554		xmlXPathNodeSetClear(tmp->nodesetval);
12555		/*
12556		* REVISIT TODO: Don't create a temporary nodeset
12557		* for everly iteration.
12558		*/
12559		/* OLD: xmlXPathFreeObject(res); */
12560	    } else
12561		tmp = NULL;
12562	    ctxt->context->node = NULL;
12563	    /*
12564	    * Only put the first node in the result, then leave.
12565	    */
12566	    if (newlocset->locNr > 0) {
12567		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
12568		break;
12569	    }
12570	}
12571	if (tmp != NULL) {
12572	    xmlXPathReleaseObject(ctxt->context, tmp);
12573	}
12574	/*
12575	* The result is used as the new evaluation locset.
12576	*/
12577	xmlXPathReleaseObject(ctxt->context, obj);
12578	ctxt->context->node = NULL;
12579	ctxt->context->contextSize = -1;
12580	ctxt->context->proximityPosition = -1;
12581	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12582	ctxt->context->node = oldnode;
12583	return (total);
12584    }
12585#endif /* LIBXML_XPTR_ENABLED */
12586
12587    /*
12588    * Extract the old set, and then evaluate the result of the
12589    * expression for all the element in the set. use it to grow
12590    * up a new set.
12591    */
12592    CHECK_TYPE0(XPATH_NODESET);
12593    obj = valuePop(ctxt);
12594    oldset = obj->nodesetval;
12595
12596    oldnode = ctxt->context->node;
12597    oldDoc = ctxt->context->doc;
12598    ctxt->context->node = NULL;
12599
12600    if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12601	ctxt->context->contextSize = 0;
12602	ctxt->context->proximityPosition = 0;
12603	/* QUESTION TODO: Why was this code commented out?
12604	    if (op->ch2 != -1)
12605		total +=
12606		    xmlXPathCompOpEval(ctxt,
12607			&comp->steps[op->ch2]);
12608	    CHECK_ERROR0;
12609	    res = valuePop(ctxt);
12610	    if (res != NULL)
12611		xmlXPathFreeObject(res);
12612	*/
12613	valuePush(ctxt, obj);
12614	ctxt->context->node = oldnode;
12615	CHECK_ERROR0;
12616    } else {
12617	xmlNodeSetPtr newset;
12618	xmlXPathObjectPtr tmp = NULL;
12619	/*
12620	* Initialize the new set.
12621	* Also set the xpath document in case things like
12622	* key() evaluation are attempted on the predicate
12623	*/
12624	newset = xmlXPathNodeSetCreate(NULL);
12625
12626	for (i = 0; i < oldset->nodeNr; i++) {
12627	    /*
12628	    * Run the evaluation with a node list made of
12629	    * a single item in the nodeset.
12630	    */
12631	    ctxt->context->node = oldset->nodeTab[i];
12632	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12633		(oldset->nodeTab[i]->doc != NULL))
12634		ctxt->context->doc = oldset->nodeTab[i]->doc;
12635	    if (tmp == NULL) {
12636		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12637		    ctxt->context->node);
12638	    } else {
12639		xmlXPathNodeSetAddUnique(tmp->nodesetval,
12640		    ctxt->context->node);
12641	    }
12642	    valuePush(ctxt, tmp);
12643	    ctxt->context->contextSize = oldset->nodeNr;
12644	    ctxt->context->proximityPosition = i + 1;
12645	    if (op->ch2 != -1)
12646		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12647	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12648		xmlXPathFreeNodeSet(newset);
12649		xmlXPathFreeObject(obj);
12650		return(0);
12651	    }
12652	    /*
12653	    * The result of the evaluation needs to be tested to
12654	    * decide whether the filter succeeded or not
12655	    */
12656	    res = valuePop(ctxt);
12657	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12658		xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
12659	    }
12660	    /*
12661	    * Cleanup
12662	    */
12663	    if (res != NULL) {
12664		xmlXPathReleaseObject(ctxt->context, res);
12665	    }
12666	    if (ctxt->value == tmp) {
12667		valuePop(ctxt);
12668		/*
12669		* Don't free the temporary nodeset
12670		* in order to avoid massive recreation inside this
12671		* loop.
12672		*/
12673		xmlXPathNodeSetClear(tmp->nodesetval);
12674	    } else
12675		tmp = NULL;
12676	    ctxt->context->node = NULL;
12677	    /*
12678	    * Only put the first node in the result, then leave.
12679	    */
12680	    if (newset->nodeNr > 0) {
12681		*first = *(newset->nodeTab);
12682		break;
12683	    }
12684	}
12685	if (tmp != NULL) {
12686	    xmlXPathReleaseObject(ctxt->context, tmp);
12687	}
12688	/*
12689	* The result is used as the new evaluation set.
12690	*/
12691	xmlXPathReleaseObject(ctxt->context, obj);
12692	ctxt->context->node = NULL;
12693	ctxt->context->contextSize = -1;
12694	ctxt->context->proximityPosition = -1;
12695	/* may want to move this past the '}' later */
12696	ctxt->context->doc = oldDoc;
12697	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
12698    }
12699    ctxt->context->node = oldnode;
12700    return(total);
12701}
12702#endif /* XP_OPTIMIZED_FILTER_FIRST */
12703
12704/**
12705 * xmlXPathCompOpEval:
12706 * @ctxt:  the XPath parser context with the compiled expression
12707 * @op:  an XPath compiled operation
12708 *
12709 * Evaluate the Precompiled XPath operation
12710 * Returns the number of nodes traversed
12711 */
12712static int
12713xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12714{
12715    int total = 0;
12716    int equal, ret;
12717    xmlXPathCompExprPtr comp;
12718    xmlXPathObjectPtr arg1, arg2;
12719    xmlNodePtr bak;
12720    xmlDocPtr bakd;
12721    int pp;
12722    int cs;
12723
12724    CHECK_ERROR0;
12725    comp = ctxt->comp;
12726    switch (op->op) {
12727        case XPATH_OP_END:
12728            return (0);
12729        case XPATH_OP_AND:
12730	    bakd = ctxt->context->doc;
12731	    bak = ctxt->context->node;
12732	    pp = ctxt->context->proximityPosition;
12733	    cs = ctxt->context->contextSize;
12734            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12735	    CHECK_ERROR0;
12736            xmlXPathBooleanFunction(ctxt, 1);
12737            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12738                return (total);
12739            arg2 = valuePop(ctxt);
12740	    ctxt->context->doc = bakd;
12741	    ctxt->context->node = bak;
12742	    ctxt->context->proximityPosition = pp;
12743	    ctxt->context->contextSize = cs;
12744            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12745	    if (ctxt->error) {
12746		xmlXPathFreeObject(arg2);
12747		return(0);
12748	    }
12749            xmlXPathBooleanFunction(ctxt, 1);
12750            arg1 = valuePop(ctxt);
12751            arg1->boolval &= arg2->boolval;
12752            valuePush(ctxt, arg1);
12753	    xmlXPathReleaseObject(ctxt->context, arg2);
12754            return (total);
12755        case XPATH_OP_OR:
12756	    bakd = ctxt->context->doc;
12757	    bak = ctxt->context->node;
12758	    pp = ctxt->context->proximityPosition;
12759	    cs = ctxt->context->contextSize;
12760            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12761	    CHECK_ERROR0;
12762            xmlXPathBooleanFunction(ctxt, 1);
12763            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12764                return (total);
12765            arg2 = valuePop(ctxt);
12766	    ctxt->context->doc = bakd;
12767	    ctxt->context->node = bak;
12768	    ctxt->context->proximityPosition = pp;
12769	    ctxt->context->contextSize = cs;
12770            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12771	    if (ctxt->error) {
12772		xmlXPathFreeObject(arg2);
12773		return(0);
12774	    }
12775            xmlXPathBooleanFunction(ctxt, 1);
12776            arg1 = valuePop(ctxt);
12777            arg1->boolval |= arg2->boolval;
12778            valuePush(ctxt, arg1);
12779	    xmlXPathReleaseObject(ctxt->context, arg2);
12780            return (total);
12781        case XPATH_OP_EQUAL:
12782	    bakd = ctxt->context->doc;
12783	    bak = ctxt->context->node;
12784	    pp = ctxt->context->proximityPosition;
12785	    cs = ctxt->context->contextSize;
12786            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12787	    CHECK_ERROR0;
12788	    ctxt->context->doc = bakd;
12789	    ctxt->context->node = bak;
12790	    ctxt->context->proximityPosition = pp;
12791	    ctxt->context->contextSize = cs;
12792            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12793	    CHECK_ERROR0;
12794	    if (op->value)
12795        	equal = xmlXPathEqualValues(ctxt);
12796	    else
12797		equal = xmlXPathNotEqualValues(ctxt);
12798	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
12799            return (total);
12800        case XPATH_OP_CMP:
12801	    bakd = ctxt->context->doc;
12802	    bak = ctxt->context->node;
12803	    pp = ctxt->context->proximityPosition;
12804	    cs = ctxt->context->contextSize;
12805            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12806	    CHECK_ERROR0;
12807	    ctxt->context->doc = bakd;
12808	    ctxt->context->node = bak;
12809	    ctxt->context->proximityPosition = pp;
12810	    ctxt->context->contextSize = cs;
12811            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12812	    CHECK_ERROR0;
12813            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
12814	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
12815            return (total);
12816        case XPATH_OP_PLUS:
12817	    bakd = ctxt->context->doc;
12818	    bak = ctxt->context->node;
12819	    pp = ctxt->context->proximityPosition;
12820	    cs = ctxt->context->contextSize;
12821            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12822	    CHECK_ERROR0;
12823            if (op->ch2 != -1) {
12824		ctxt->context->doc = bakd;
12825		ctxt->context->node = bak;
12826		ctxt->context->proximityPosition = pp;
12827		ctxt->context->contextSize = cs;
12828                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12829	    }
12830	    CHECK_ERROR0;
12831            if (op->value == 0)
12832                xmlXPathSubValues(ctxt);
12833            else if (op->value == 1)
12834                xmlXPathAddValues(ctxt);
12835            else if (op->value == 2)
12836                xmlXPathValueFlipSign(ctxt);
12837            else if (op->value == 3) {
12838                CAST_TO_NUMBER;
12839                CHECK_TYPE0(XPATH_NUMBER);
12840            }
12841            return (total);
12842        case XPATH_OP_MULT:
12843	    bakd = ctxt->context->doc;
12844	    bak = ctxt->context->node;
12845	    pp = ctxt->context->proximityPosition;
12846	    cs = ctxt->context->contextSize;
12847            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12848	    CHECK_ERROR0;
12849	    ctxt->context->doc = bakd;
12850	    ctxt->context->node = bak;
12851	    ctxt->context->proximityPosition = pp;
12852	    ctxt->context->contextSize = cs;
12853            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12854	    CHECK_ERROR0;
12855            if (op->value == 0)
12856                xmlXPathMultValues(ctxt);
12857            else if (op->value == 1)
12858                xmlXPathDivValues(ctxt);
12859            else if (op->value == 2)
12860                xmlXPathModValues(ctxt);
12861            return (total);
12862        case XPATH_OP_UNION:
12863	    bakd = ctxt->context->doc;
12864	    bak = ctxt->context->node;
12865	    pp = ctxt->context->proximityPosition;
12866	    cs = ctxt->context->contextSize;
12867            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12868	    CHECK_ERROR0;
12869	    ctxt->context->doc = bakd;
12870	    ctxt->context->node = bak;
12871	    ctxt->context->proximityPosition = pp;
12872	    ctxt->context->contextSize = cs;
12873            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12874	    CHECK_ERROR0;
12875            CHECK_TYPE0(XPATH_NODESET);
12876            arg2 = valuePop(ctxt);
12877
12878            CHECK_TYPE0(XPATH_NODESET);
12879            arg1 = valuePop(ctxt);
12880
12881	    if ((arg1->nodesetval == NULL) ||
12882		((arg2->nodesetval != NULL) &&
12883		 (arg2->nodesetval->nodeNr != 0)))
12884	    {
12885		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12886							arg2->nodesetval);
12887	    }
12888
12889            valuePush(ctxt, arg1);
12890	    xmlXPathReleaseObject(ctxt->context, arg2);
12891            return (total);
12892        case XPATH_OP_ROOT:
12893            xmlXPathRoot(ctxt);
12894            return (total);
12895        case XPATH_OP_NODE:
12896            if (op->ch1 != -1)
12897                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12898	    CHECK_ERROR0;
12899            if (op->ch2 != -1)
12900                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12901	    CHECK_ERROR0;
12902	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12903		ctxt->context->node));
12904            return (total);
12905        case XPATH_OP_RESET:
12906            if (op->ch1 != -1)
12907                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12908	    CHECK_ERROR0;
12909            if (op->ch2 != -1)
12910                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12911	    CHECK_ERROR0;
12912            ctxt->context->node = NULL;
12913            return (total);
12914        case XPATH_OP_COLLECT:{
12915                if (op->ch1 == -1)
12916                    return (total);
12917
12918                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12919		CHECK_ERROR0;
12920
12921		if ((op->ch2 != -1) &&
12922                    (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
12923                    (comp->steps[op->ch2].ch1 == -1) &&
12924                    (comp->steps[op->ch2].ch2 != -1) &&
12925                    (comp->steps[comp->steps[op->ch2].ch2].op ==
12926                     XPATH_OP_VALUE))
12927		{
12928                    xmlXPathObjectPtr val;
12929		    /*
12930		    * Optimization for [n] selection where n is a number
12931		    */
12932                    val = comp->steps[comp->steps[op->ch2].ch2].value4;
12933                    if ((val != NULL) && (val->type == XPATH_NUMBER)) {
12934                        int indx = (int) val->floatval;
12935
12936                        if (val->floatval == (float) indx) {
12937                            total +=
12938                                xmlXPathNodeCollectAndTestNth(ctxt, op,
12939                                                              indx, NULL,
12940                                                              NULL);
12941                            return (total);
12942                        }
12943                    }
12944                }
12945                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
12946                return (total);
12947            }
12948        case XPATH_OP_VALUE:
12949            valuePush(ctxt,
12950                      xmlXPathCacheObjectCopy(ctxt->context,
12951			(xmlXPathObjectPtr) op->value4));
12952            return (total);
12953        case XPATH_OP_VARIABLE:{
12954		xmlXPathObjectPtr val;
12955
12956                if (op->ch1 != -1)
12957                    total +=
12958                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12959                if (op->value5 == NULL) {
12960		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
12961		    if (val == NULL) {
12962			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
12963			return(0);
12964		    }
12965                    valuePush(ctxt, val);
12966		} else {
12967                    const xmlChar *URI;
12968
12969                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
12970                    if (URI == NULL) {
12971                        xmlGenericError(xmlGenericErrorContext,
12972                                        "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
12973                                        op->value4, op->value5);
12974                        return (total);
12975                    }
12976		    val = xmlXPathVariableLookupNS(ctxt->context,
12977                                                       op->value4, URI);
12978		    if (val == NULL) {
12979			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
12980			return(0);
12981		    }
12982                    valuePush(ctxt, val);
12983                }
12984                return (total);
12985            }
12986        case XPATH_OP_FUNCTION:{
12987                xmlXPathFunction func;
12988                const xmlChar *oldFunc, *oldFuncURI;
12989		int i;
12990
12991                if (op->ch1 != -1)
12992                    total +=
12993                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12994		if (ctxt->valueNr < op->value) {
12995		    xmlGenericError(xmlGenericErrorContext,
12996			    "xmlXPathCompOpEval: parameter error\n");
12997		    ctxt->error = XPATH_INVALID_OPERAND;
12998		    return (total);
12999		}
13000		for (i = 0; i < op->value; i++)
13001		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13002			xmlGenericError(xmlGenericErrorContext,
13003				"xmlXPathCompOpEval: parameter error\n");
13004			ctxt->error = XPATH_INVALID_OPERAND;
13005			return (total);
13006		    }
13007                if (op->cache != NULL)
13008                    XML_CAST_FPTR(func) = op->cache;
13009                else {
13010                    const xmlChar *URI = NULL;
13011
13012                    if (op->value5 == NULL)
13013                        func =
13014                            xmlXPathFunctionLookup(ctxt->context,
13015                                                   op->value4);
13016                    else {
13017                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13018                        if (URI == NULL) {
13019                            xmlGenericError(xmlGenericErrorContext,
13020                                            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13021                                            op->value4, op->value5);
13022                            return (total);
13023                        }
13024                        func = xmlXPathFunctionLookupNS(ctxt->context,
13025                                                        op->value4, URI);
13026                    }
13027                    if (func == NULL) {
13028                        xmlGenericError(xmlGenericErrorContext,
13029                                        "xmlXPathCompOpEval: function %s not found\n",
13030                                        op->value4);
13031                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13032                    }
13033                    op->cache = XML_CAST_FPTR(func);
13034                    op->cacheURI = (void *) URI;
13035                }
13036                oldFunc = ctxt->context->function;
13037                oldFuncURI = ctxt->context->functionURI;
13038                ctxt->context->function = op->value4;
13039                ctxt->context->functionURI = op->cacheURI;
13040                func(ctxt, op->value);
13041                ctxt->context->function = oldFunc;
13042                ctxt->context->functionURI = oldFuncURI;
13043                return (total);
13044            }
13045        case XPATH_OP_ARG:
13046	    bakd = ctxt->context->doc;
13047	    bak = ctxt->context->node;
13048	    pp = ctxt->context->proximityPosition;
13049	    cs = ctxt->context->contextSize;
13050            if (op->ch1 != -1)
13051                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13052	    ctxt->context->contextSize = cs;
13053	    ctxt->context->proximityPosition = pp;
13054	    ctxt->context->node = bak;
13055	    ctxt->context->doc = bakd;
13056	    CHECK_ERROR0;
13057            if (op->ch2 != -1) {
13058                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13059	        ctxt->context->doc = bakd;
13060	        ctxt->context->node = bak;
13061	        CHECK_ERROR0;
13062	    }
13063            return (total);
13064        case XPATH_OP_PREDICATE:
13065        case XPATH_OP_FILTER:{
13066                xmlXPathObjectPtr res;
13067                xmlXPathObjectPtr obj, tmp;
13068                xmlNodeSetPtr newset = NULL;
13069                xmlNodeSetPtr oldset;
13070                xmlNodePtr oldnode;
13071		xmlDocPtr oldDoc;
13072                int i;
13073
13074                /*
13075                 * Optimization for ()[1] selection i.e. the first elem
13076                 */
13077                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13078#ifdef XP_OPTIMIZED_FILTER_FIRST
13079		    /*
13080		    * FILTER TODO: Can we assume that the inner processing
13081		    *  will result in an ordered list if we have an
13082		    *  XPATH_OP_FILTER?
13083		    *  What about an additional field or flag on
13084		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13085		    *  to assume anything, so it would be more robust and
13086		    *  easier to optimize.
13087		    */
13088                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13089		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13090#else
13091		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13092#endif
13093                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13094                    xmlXPathObjectPtr val;
13095
13096                    val = comp->steps[op->ch2].value4;
13097                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13098                        (val->floatval == 1.0)) {
13099                        xmlNodePtr first = NULL;
13100
13101                        total +=
13102                            xmlXPathCompOpEvalFirst(ctxt,
13103                                                    &comp->steps[op->ch1],
13104                                                    &first);
13105			CHECK_ERROR0;
13106                        /*
13107                         * The nodeset should be in document order,
13108                         * Keep only the first value
13109                         */
13110                        if ((ctxt->value != NULL) &&
13111                            (ctxt->value->type == XPATH_NODESET) &&
13112                            (ctxt->value->nodesetval != NULL) &&
13113                            (ctxt->value->nodesetval->nodeNr > 1))
13114                            ctxt->value->nodesetval->nodeNr = 1;
13115                        return (total);
13116                    }
13117                }
13118                /*
13119                 * Optimization for ()[last()] selection i.e. the last elem
13120                 */
13121                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13122                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13123                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13124                    int f = comp->steps[op->ch2].ch1;
13125
13126                    if ((f != -1) &&
13127                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13128                        (comp->steps[f].value5 == NULL) &&
13129                        (comp->steps[f].value == 0) &&
13130                        (comp->steps[f].value4 != NULL) &&
13131                        (xmlStrEqual
13132                         (comp->steps[f].value4, BAD_CAST "last"))) {
13133                        xmlNodePtr last = NULL;
13134
13135                        total +=
13136                            xmlXPathCompOpEvalLast(ctxt,
13137                                                   &comp->steps[op->ch1],
13138                                                   &last);
13139			CHECK_ERROR0;
13140                        /*
13141                         * The nodeset should be in document order,
13142                         * Keep only the last value
13143                         */
13144                        if ((ctxt->value != NULL) &&
13145                            (ctxt->value->type == XPATH_NODESET) &&
13146                            (ctxt->value->nodesetval != NULL) &&
13147                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13148                            (ctxt->value->nodesetval->nodeNr > 1)) {
13149                            ctxt->value->nodesetval->nodeTab[0] =
13150                                ctxt->value->nodesetval->nodeTab[ctxt->
13151                                                                 value->
13152                                                                 nodesetval->
13153                                                                 nodeNr -
13154                                                                 1];
13155                            ctxt->value->nodesetval->nodeNr = 1;
13156                        }
13157                        return (total);
13158                    }
13159                }
13160		/*
13161		* Process inner predicates first.
13162		* Example "index[parent::book][1]":
13163		* ...
13164		*   PREDICATE   <-- we are here "[1]"
13165		*     PREDICATE <-- process "[parent::book]" first
13166		*       SORT
13167		*         COLLECT  'parent' 'name' 'node' book
13168		*           NODE
13169		*     ELEM Object is a number : 1
13170		*/
13171                if (op->ch1 != -1)
13172                    total +=
13173                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13174		CHECK_ERROR0;
13175                if (op->ch2 == -1)
13176                    return (total);
13177                if (ctxt->value == NULL)
13178                    return (total);
13179
13180                oldnode = ctxt->context->node;
13181
13182#ifdef LIBXML_XPTR_ENABLED
13183                /*
13184                 * Hum are we filtering the result of an XPointer expression
13185                 */
13186                if (ctxt->value->type == XPATH_LOCATIONSET) {
13187                    xmlLocationSetPtr newlocset = NULL;
13188                    xmlLocationSetPtr oldlocset;
13189
13190                    /*
13191                     * Extract the old locset, and then evaluate the result of the
13192                     * expression for all the element in the locset. use it to grow
13193                     * up a new locset.
13194                     */
13195                    CHECK_TYPE0(XPATH_LOCATIONSET);
13196                    obj = valuePop(ctxt);
13197                    oldlocset = obj->user;
13198                    ctxt->context->node = NULL;
13199
13200                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13201                        ctxt->context->contextSize = 0;
13202                        ctxt->context->proximityPosition = 0;
13203                        if (op->ch2 != -1)
13204                            total +=
13205                                xmlXPathCompOpEval(ctxt,
13206                                                   &comp->steps[op->ch2]);
13207                        res = valuePop(ctxt);
13208                        if (res != NULL) {
13209			    xmlXPathReleaseObject(ctxt->context, res);
13210			}
13211                        valuePush(ctxt, obj);
13212                        CHECK_ERROR0;
13213                        return (total);
13214                    }
13215                    newlocset = xmlXPtrLocationSetCreate(NULL);
13216
13217                    for (i = 0; i < oldlocset->locNr; i++) {
13218                        /*
13219                         * Run the evaluation with a node list made of a
13220                         * single item in the nodelocset.
13221                         */
13222                        ctxt->context->node = oldlocset->locTab[i]->user;
13223                        ctxt->context->contextSize = oldlocset->locNr;
13224                        ctxt->context->proximityPosition = i + 1;
13225			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13226			    ctxt->context->node);
13227                        valuePush(ctxt, tmp);
13228
13229                        if (op->ch2 != -1)
13230                            total +=
13231                                xmlXPathCompOpEval(ctxt,
13232                                                   &comp->steps[op->ch2]);
13233			if (ctxt->error != XPATH_EXPRESSION_OK) {
13234			    xmlXPathFreeObject(obj);
13235			    return(0);
13236			}
13237
13238                        /*
13239                         * The result of the evaluation need to be tested to
13240                         * decided whether the filter succeeded or not
13241                         */
13242                        res = valuePop(ctxt);
13243                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13244                            xmlXPtrLocationSetAdd(newlocset,
13245                                                  xmlXPathObjectCopy
13246                                                  (oldlocset->locTab[i]));
13247                        }
13248
13249                        /*
13250                         * Cleanup
13251                         */
13252                        if (res != NULL) {
13253			    xmlXPathReleaseObject(ctxt->context, res);
13254			}
13255                        if (ctxt->value == tmp) {
13256                            res = valuePop(ctxt);
13257			    xmlXPathReleaseObject(ctxt->context, res);
13258                        }
13259
13260                        ctxt->context->node = NULL;
13261                    }
13262
13263                    /*
13264                     * The result is used as the new evaluation locset.
13265                     */
13266		    xmlXPathReleaseObject(ctxt->context, obj);
13267                    ctxt->context->node = NULL;
13268                    ctxt->context->contextSize = -1;
13269                    ctxt->context->proximityPosition = -1;
13270                    valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13271                    ctxt->context->node = oldnode;
13272                    return (total);
13273                }
13274#endif /* LIBXML_XPTR_ENABLED */
13275
13276                /*
13277                 * Extract the old set, and then evaluate the result of the
13278                 * expression for all the element in the set. use it to grow
13279                 * up a new set.
13280                 */
13281                CHECK_TYPE0(XPATH_NODESET);
13282                obj = valuePop(ctxt);
13283                oldset = obj->nodesetval;
13284
13285                oldnode = ctxt->context->node;
13286		oldDoc = ctxt->context->doc;
13287                ctxt->context->node = NULL;
13288
13289                if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13290                    ctxt->context->contextSize = 0;
13291                    ctxt->context->proximityPosition = 0;
13292/*
13293                    if (op->ch2 != -1)
13294                        total +=
13295                            xmlXPathCompOpEval(ctxt,
13296                                               &comp->steps[op->ch2]);
13297		    CHECK_ERROR0;
13298                    res = valuePop(ctxt);
13299                    if (res != NULL)
13300                        xmlXPathFreeObject(res);
13301*/
13302                    valuePush(ctxt, obj);
13303                    ctxt->context->node = oldnode;
13304                    CHECK_ERROR0;
13305                } else {
13306		    tmp = NULL;
13307                    /*
13308                     * Initialize the new set.
13309		     * Also set the xpath document in case things like
13310		     * key() evaluation are attempted on the predicate
13311                     */
13312                    newset = xmlXPathNodeSetCreate(NULL);
13313		    /*
13314		    * SPEC XPath 1.0:
13315		    *  "For each node in the node-set to be filtered, the
13316		    *  PredicateExpr is evaluated with that node as the
13317		    *  context node, with the number of nodes in the
13318		    *  node-set as the context size, and with the proximity
13319		    *  position of the node in the node-set with respect to
13320		    *  the axis as the context position;"
13321		    * @oldset is the node-set" to be filtered.
13322		    *
13323		    * SPEC XPath 1.0:
13324		    *  "only predicates change the context position and
13325		    *  context size (see [2.4 Predicates])."
13326		    * Example:
13327		    *   node-set  context pos
13328		    *    nA         1
13329		    *    nB         2
13330		    *    nC         3
13331		    *   After applying predicate [position() > 1] :
13332		    *   node-set  context pos
13333		    *    nB         1
13334		    *    nC         2
13335		    *
13336		    * removed the first node in the node-set, then
13337		    * the context position of the
13338		    */
13339                    for (i = 0; i < oldset->nodeNr; i++) {
13340                        /*
13341                         * Run the evaluation with a node list made of
13342                         * a single item in the nodeset.
13343                         */
13344                        ctxt->context->node = oldset->nodeTab[i];
13345			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13346			    (oldset->nodeTab[i]->doc != NULL))
13347		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13348			if (tmp == NULL) {
13349			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13350				ctxt->context->node);
13351			} else {
13352			    xmlXPathNodeSetAddUnique(tmp->nodesetval,
13353				ctxt->context->node);
13354			}
13355                        valuePush(ctxt, tmp);
13356                        ctxt->context->contextSize = oldset->nodeNr;
13357                        ctxt->context->proximityPosition = i + 1;
13358			/*
13359			* Evaluate the predicate against the context node.
13360			* Can/should we optimize position() predicates
13361			* here (e.g. "[1]")?
13362			*/
13363                        if (op->ch2 != -1)
13364                            total +=
13365                                xmlXPathCompOpEval(ctxt,
13366                                                   &comp->steps[op->ch2]);
13367			if (ctxt->error != XPATH_EXPRESSION_OK) {
13368			    xmlXPathFreeNodeSet(newset);
13369			    xmlXPathFreeObject(obj);
13370			    return(0);
13371			}
13372
13373                        /*
13374                         * The result of the evaluation needs to be tested to
13375                         * decide whether the filter succeeded or not
13376                         */
13377			/*
13378			* OPTIMIZE TODO: Can we use
13379			* xmlXPathNodeSetAdd*Unique()* instead?
13380			*/
13381                        res = valuePop(ctxt);
13382                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13383                            xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13384                        }
13385
13386                        /*
13387                         * Cleanup
13388                         */
13389                        if (res != NULL) {
13390			    xmlXPathReleaseObject(ctxt->context, res);
13391			}
13392                        if (ctxt->value == tmp) {
13393                            valuePop(ctxt);
13394			    xmlXPathNodeSetClear(tmp->nodesetval);
13395			    /*
13396			    * Don't free the temporary nodeset
13397			    * in order to avoid massive recreation inside this
13398			    * loop.
13399			    */
13400                        } else
13401			    tmp = NULL;
13402                        ctxt->context->node = NULL;
13403                    }
13404		    if (tmp != NULL)
13405			xmlXPathReleaseObject(ctxt->context, tmp);
13406                    /*
13407                     * The result is used as the new evaluation set.
13408                     */
13409		    xmlXPathReleaseObject(ctxt->context, obj);
13410                    ctxt->context->node = NULL;
13411                    ctxt->context->contextSize = -1;
13412                    ctxt->context->proximityPosition = -1;
13413		    /* may want to move this past the '}' later */
13414		    ctxt->context->doc = oldDoc;
13415		    valuePush(ctxt,
13416			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13417                }
13418                ctxt->context->node = oldnode;
13419                return (total);
13420            }
13421        case XPATH_OP_SORT:
13422            if (op->ch1 != -1)
13423                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13424	    CHECK_ERROR0;
13425            if ((ctxt->value != NULL) &&
13426                (ctxt->value->type == XPATH_NODESET) &&
13427                (ctxt->value->nodesetval != NULL) &&
13428		(ctxt->value->nodesetval->nodeNr > 1))
13429	    {
13430                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13431	    }
13432            return (total);
13433#ifdef LIBXML_XPTR_ENABLED
13434        case XPATH_OP_RANGETO:{
13435                xmlXPathObjectPtr range;
13436                xmlXPathObjectPtr res, obj;
13437                xmlXPathObjectPtr tmp;
13438                xmlLocationSetPtr newlocset = NULL;
13439		    xmlLocationSetPtr oldlocset;
13440                xmlNodeSetPtr oldset;
13441                int i, j;
13442
13443                if (op->ch1 != -1)
13444                    total +=
13445                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13446                if (op->ch2 == -1)
13447                    return (total);
13448
13449                if (ctxt->value->type == XPATH_LOCATIONSET) {
13450                    /*
13451                     * Extract the old locset, and then evaluate the result of the
13452                     * expression for all the element in the locset. use it to grow
13453                     * up a new locset.
13454                     */
13455                    CHECK_TYPE0(XPATH_LOCATIONSET);
13456                    obj = valuePop(ctxt);
13457                    oldlocset = obj->user;
13458
13459                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13460		        ctxt->context->node = NULL;
13461                        ctxt->context->contextSize = 0;
13462                        ctxt->context->proximityPosition = 0;
13463                        total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13464                        res = valuePop(ctxt);
13465                        if (res != NULL) {
13466			    xmlXPathReleaseObject(ctxt->context, res);
13467			}
13468                        valuePush(ctxt, obj);
13469                        CHECK_ERROR0;
13470                        return (total);
13471                    }
13472                    newlocset = xmlXPtrLocationSetCreate(NULL);
13473
13474                    for (i = 0; i < oldlocset->locNr; i++) {
13475                        /*
13476                         * Run the evaluation with a node list made of a
13477                         * single item in the nodelocset.
13478                         */
13479                        ctxt->context->node = oldlocset->locTab[i]->user;
13480                        ctxt->context->contextSize = oldlocset->locNr;
13481                        ctxt->context->proximityPosition = i + 1;
13482			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13483			    ctxt->context->node);
13484                        valuePush(ctxt, tmp);
13485
13486                        if (op->ch2 != -1)
13487                            total +=
13488                                xmlXPathCompOpEval(ctxt,
13489                                                   &comp->steps[op->ch2]);
13490			if (ctxt->error != XPATH_EXPRESSION_OK) {
13491			    xmlXPathFreeObject(obj);
13492			    return(0);
13493			}
13494
13495                        res = valuePop(ctxt);
13496			if (res->type == XPATH_LOCATIONSET) {
13497			    xmlLocationSetPtr rloc =
13498			        (xmlLocationSetPtr)res->user;
13499			    for (j=0; j<rloc->locNr; j++) {
13500			        range = xmlXPtrNewRange(
13501				  oldlocset->locTab[i]->user,
13502				  oldlocset->locTab[i]->index,
13503				  rloc->locTab[j]->user2,
13504				  rloc->locTab[j]->index2);
13505				if (range != NULL) {
13506				    xmlXPtrLocationSetAdd(newlocset, range);
13507				}
13508			    }
13509			} else {
13510			    range = xmlXPtrNewRangeNodeObject(
13511				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13512                            if (range != NULL) {
13513                                xmlXPtrLocationSetAdd(newlocset,range);
13514			    }
13515                        }
13516
13517                        /*
13518                         * Cleanup
13519                         */
13520                        if (res != NULL) {
13521			    xmlXPathReleaseObject(ctxt->context, res);
13522			}
13523                        if (ctxt->value == tmp) {
13524                            res = valuePop(ctxt);
13525			    xmlXPathReleaseObject(ctxt->context, res);
13526                        }
13527
13528                        ctxt->context->node = NULL;
13529                    }
13530		} else {	/* Not a location set */
13531                    CHECK_TYPE0(XPATH_NODESET);
13532                    obj = valuePop(ctxt);
13533                    oldset = obj->nodesetval;
13534                    ctxt->context->node = NULL;
13535
13536                    newlocset = xmlXPtrLocationSetCreate(NULL);
13537
13538                    if (oldset != NULL) {
13539                        for (i = 0; i < oldset->nodeNr; i++) {
13540                            /*
13541                             * Run the evaluation with a node list made of a single item
13542                             * in the nodeset.
13543                             */
13544                            ctxt->context->node = oldset->nodeTab[i];
13545			    /*
13546			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13547			    */
13548			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13549				ctxt->context->node);
13550                            valuePush(ctxt, tmp);
13551
13552                            if (op->ch2 != -1)
13553                                total +=
13554                                    xmlXPathCompOpEval(ctxt,
13555                                                   &comp->steps[op->ch2]);
13556			    if (ctxt->error != XPATH_EXPRESSION_OK) {
13557				xmlXPathFreeObject(obj);
13558				return(0);
13559			    }
13560
13561                            res = valuePop(ctxt);
13562                            range =
13563                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13564                                                      res);
13565                            if (range != NULL) {
13566                                xmlXPtrLocationSetAdd(newlocset, range);
13567                            }
13568
13569                            /*
13570                             * Cleanup
13571                             */
13572                            if (res != NULL) {
13573				xmlXPathReleaseObject(ctxt->context, res);
13574			    }
13575                            if (ctxt->value == tmp) {
13576                                res = valuePop(ctxt);
13577				xmlXPathReleaseObject(ctxt->context, res);
13578                            }
13579
13580                            ctxt->context->node = NULL;
13581                        }
13582                    }
13583                }
13584
13585                /*
13586                 * The result is used as the new evaluation set.
13587                 */
13588		xmlXPathReleaseObject(ctxt->context, obj);
13589                ctxt->context->node = NULL;
13590                ctxt->context->contextSize = -1;
13591                ctxt->context->proximityPosition = -1;
13592                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13593                return (total);
13594            }
13595#endif /* LIBXML_XPTR_ENABLED */
13596    }
13597    xmlGenericError(xmlGenericErrorContext,
13598                    "XPath: unknown precompiled operation %d\n", op->op);
13599    return (total);
13600}
13601
13602#ifdef XPATH_STREAMING
13603/**
13604 * xmlXPathRunStreamEval:
13605 * @ctxt:  the XPath parser context with the compiled expression
13606 *
13607 * Evaluate the Precompiled Streamable XPath expression in the given context.
13608 */
13609static xmlXPathObjectPtr
13610xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
13611    int max_depth, min_depth;
13612    int from_root;
13613    int ret, depth;
13614#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13615    int eval_all_nodes;
13616#endif
13617    xmlNodePtr cur = NULL, limit = NULL;
13618    xmlXPathObjectPtr retval;
13619    xmlStreamCtxtPtr patstream;
13620
13621    int nb_nodes = 0;
13622
13623    if ((ctxt == NULL) || (comp == NULL))
13624        return(NULL);
13625    max_depth = xmlPatternMaxDepth(comp);
13626    if (max_depth == -1)
13627        return(NULL);
13628    if (max_depth == -2)
13629        max_depth = 10000;
13630    min_depth = xmlPatternMinDepth(comp);
13631    if (min_depth == -1)
13632        return(NULL);
13633    from_root = xmlPatternFromRoot(comp);
13634    if (from_root < 0)
13635        return(NULL);
13636#if 0
13637    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13638#endif
13639
13640    retval = xmlXPathCacheNewNodeSet(ctxt, NULL);
13641    if (retval == NULL)
13642        return(NULL);
13643
13644    /*
13645     * handle the special cases of / amd . being matched
13646     */
13647    if (min_depth == 0) {
13648	if (from_root) {
13649	    xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
13650	} else {
13651	    xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
13652	}
13653    }
13654    if (max_depth == 0) {
13655	return(retval);
13656    }
13657
13658    if (from_root) {
13659        cur = (xmlNodePtr)ctxt->doc;
13660    } else if (ctxt->node != NULL) {
13661        switch (ctxt->node->type) {
13662            case XML_ELEMENT_NODE:
13663            case XML_DOCUMENT_NODE:
13664            case XML_DOCUMENT_FRAG_NODE:
13665            case XML_HTML_DOCUMENT_NODE:
13666#ifdef LIBXML_DOCB_ENABLED
13667            case XML_DOCB_DOCUMENT_NODE:
13668#endif
13669	        cur = ctxt->node;
13670		break;
13671            case XML_ATTRIBUTE_NODE:
13672            case XML_TEXT_NODE:
13673            case XML_CDATA_SECTION_NODE:
13674            case XML_ENTITY_REF_NODE:
13675            case XML_ENTITY_NODE:
13676            case XML_PI_NODE:
13677            case XML_COMMENT_NODE:
13678            case XML_NOTATION_NODE:
13679            case XML_DTD_NODE:
13680            case XML_DOCUMENT_TYPE_NODE:
13681            case XML_ELEMENT_DECL:
13682            case XML_ATTRIBUTE_DECL:
13683            case XML_ENTITY_DECL:
13684            case XML_NAMESPACE_DECL:
13685            case XML_XINCLUDE_START:
13686            case XML_XINCLUDE_END:
13687		break;
13688	}
13689	limit = cur;
13690    }
13691    if (cur == NULL)
13692        return(retval);
13693
13694    patstream = xmlPatternGetStreamCtxt(comp);
13695    if (patstream == NULL) {
13696        return(retval);
13697    }
13698
13699#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13700    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13701#endif
13702
13703    if (from_root) {
13704	ret = xmlStreamPush(patstream, NULL, NULL);
13705	if (ret < 0) {
13706	} else if (ret == 1) {
13707	    xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
13708	}
13709    }
13710    depth = 0;
13711    goto scan_children;
13712next_node:
13713    do {
13714        nb_nodes++;
13715
13716	switch (cur->type) {
13717	    case XML_ELEMENT_NODE:
13718#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13719	    case XML_TEXT_NODE:
13720	    case XML_CDATA_SECTION_NODE:
13721	    case XML_COMMENT_NODE:
13722	    case XML_PI_NODE:
13723#endif
13724		if (cur->type == XML_ELEMENT_NODE) {
13725		    ret = xmlStreamPush(patstream, cur->name,
13726				(cur->ns ? cur->ns->href : NULL));
13727		}
13728#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13729		else if (eval_all_nodes)
13730		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13731		else
13732		    break;
13733#endif
13734
13735		if (ret < 0) {
13736		    /* NOP. */
13737		} else if (ret == 1) {
13738		    xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
13739		}
13740		if ((cur->children == NULL) || (depth >= max_depth)) {
13741		    ret = xmlStreamPop(patstream);
13742		    while (cur->next != NULL) {
13743			cur = cur->next;
13744			if ((cur->type != XML_ENTITY_DECL) &&
13745			    (cur->type != XML_DTD_NODE))
13746			    goto next_node;
13747		    }
13748		}
13749	    default:
13750		break;
13751	}
13752
13753scan_children:
13754	if ((cur->children != NULL) && (depth < max_depth)) {
13755	    /*
13756	     * Do not descend on entities declarations
13757	     */
13758	    if (cur->children->type != XML_ENTITY_DECL) {
13759		cur = cur->children;
13760		depth++;
13761		/*
13762		 * Skip DTDs
13763		 */
13764		if (cur->type != XML_DTD_NODE)
13765		    continue;
13766	    }
13767	}
13768
13769	if (cur == limit)
13770	    break;
13771
13772	while (cur->next != NULL) {
13773	    cur = cur->next;
13774	    if ((cur->type != XML_ENTITY_DECL) &&
13775		(cur->type != XML_DTD_NODE))
13776		goto next_node;
13777	}
13778
13779	do {
13780	    cur = cur->parent;
13781	    depth--;
13782	    if ((cur == NULL) || (cur == limit))
13783	        goto done;
13784	    if (cur->type == XML_ELEMENT_NODE) {
13785		ret = xmlStreamPop(patstream);
13786	    }
13787#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13788	    else if ((eval_all_nodes) &&
13789		((cur->type == XML_TEXT_NODE) ||
13790		 (cur->type == XML_CDATA_SECTION_NODE) ||
13791		 (cur->type == XML_COMMENT_NODE) ||
13792		 (cur->type == XML_PI_NODE)))
13793	    {
13794		ret = xmlStreamPop(patstream);
13795	    }
13796#endif
13797	    if (cur->next != NULL) {
13798		cur = cur->next;
13799		break;
13800	    }
13801	} while (cur != NULL);
13802
13803    } while ((cur != NULL) && (depth >= 0));
13804done:
13805#if 0
13806    printf("stream eval: checked %d nodes selected %d\n",
13807           nb_nodes, retval->nodesetval->nodeNr);
13808#endif
13809    xmlFreeStreamCtxt(patstream);
13810    return(retval);
13811}
13812#endif /* XPATH_STREAMING */
13813
13814/**
13815 * xmlXPathRunEval:
13816 * @ctxt:  the XPath parser context with the compiled expression
13817 *
13818 * Evaluate the Precompiled XPath expression in the given context.
13819 */
13820static void
13821xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
13822    xmlXPathCompExprPtr comp;
13823
13824    if ((ctxt == NULL) || (ctxt->comp == NULL))
13825	return;
13826
13827    if (ctxt->valueTab == NULL) {
13828	/* Allocate the value stack */
13829	ctxt->valueTab = (xmlXPathObjectPtr *)
13830			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13831	if (ctxt->valueTab == NULL) {
13832	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13833	    xmlFree(ctxt);
13834	}
13835	ctxt->valueNr = 0;
13836	ctxt->valueMax = 10;
13837	ctxt->value = NULL;
13838    }
13839#ifdef XPATH_STREAMING
13840    if (ctxt->comp->stream) {
13841        xmlXPathObjectPtr ret;
13842        ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
13843	if (ret != NULL) {
13844	    valuePush(ctxt, ret);
13845	    return;
13846	}
13847    }
13848#endif
13849    comp = ctxt->comp;
13850    if(comp->last < 0) {
13851	xmlGenericError(xmlGenericErrorContext,
13852	    "xmlXPathRunEval: last is less than zero\n");
13853	return;
13854    }
13855    xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13856}
13857
13858/************************************************************************
13859 *									*
13860 * 			Public interfaces				*
13861 *									*
13862 ************************************************************************/
13863
13864/**
13865 * xmlXPathEvalPredicate:
13866 * @ctxt:  the XPath context
13867 * @res:  the Predicate Expression evaluation result
13868 *
13869 * Evaluate a predicate result for the current node.
13870 * A PredicateExpr is evaluated by evaluating the Expr and converting
13871 * the result to a boolean. If the result is a number, the result will
13872 * be converted to true if the number is equal to the position of the
13873 * context node in the context node list (as returned by the position
13874 * function) and will be converted to false otherwise; if the result
13875 * is not a number, then the result will be converted as if by a call
13876 * to the boolean function.
13877 *
13878 * Returns 1 if predicate is true, 0 otherwise
13879 */
13880int
13881xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13882    if ((ctxt == NULL) || (res == NULL)) return(0);
13883    switch (res->type) {
13884        case XPATH_BOOLEAN:
13885	    return(res->boolval);
13886        case XPATH_NUMBER:
13887	    return(res->floatval == ctxt->proximityPosition);
13888        case XPATH_NODESET:
13889        case XPATH_XSLT_TREE:
13890	    if (res->nodesetval == NULL)
13891		return(0);
13892	    return(res->nodesetval->nodeNr != 0);
13893        case XPATH_STRING:
13894	    return((res->stringval != NULL) &&
13895	           (xmlStrlen(res->stringval) != 0));
13896        default:
13897	    STRANGE
13898    }
13899    return(0);
13900}
13901
13902/**
13903 * xmlXPathEvaluatePredicateResult:
13904 * @ctxt:  the XPath Parser context
13905 * @res:  the Predicate Expression evaluation result
13906 *
13907 * Evaluate a predicate result for the current node.
13908 * A PredicateExpr is evaluated by evaluating the Expr and converting
13909 * the result to a boolean. If the result is a number, the result will
13910 * be converted to true if the number is equal to the position of the
13911 * context node in the context node list (as returned by the position
13912 * function) and will be converted to false otherwise; if the result
13913 * is not a number, then the result will be converted as if by a call
13914 * to the boolean function.
13915 *
13916 * Returns 1 if predicate is true, 0 otherwise
13917 */
13918int
13919xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13920                                xmlXPathObjectPtr res) {
13921    if ((ctxt == NULL) || (res == NULL)) return(0);
13922    switch (res->type) {
13923        case XPATH_BOOLEAN:
13924	    return(res->boolval);
13925        case XPATH_NUMBER:
13926#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
13927	    return((res->floatval == ctxt->context->proximityPosition) &&
13928	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
13929#else
13930	    return(res->floatval == ctxt->context->proximityPosition);
13931#endif
13932        case XPATH_NODESET:
13933        case XPATH_XSLT_TREE:
13934	    if (res->nodesetval == NULL)
13935		return(0);
13936	    return(res->nodesetval->nodeNr != 0);
13937        case XPATH_STRING:
13938	    return((res->stringval != NULL) &&
13939	           (xmlStrlen(res->stringval) != 0));
13940#ifdef LIBXML_XPTR_ENABLED
13941	case XPATH_LOCATIONSET:{
13942	    xmlLocationSetPtr ptr = res->user;
13943	    if (ptr == NULL)
13944	        return(0);
13945	    return (ptr->locNr != 0);
13946	    }
13947#endif
13948        default:
13949	    STRANGE
13950    }
13951    return(0);
13952}
13953
13954#ifdef XPATH_STREAMING
13955/**
13956 * xmlXPathTryStreamCompile:
13957 * @ctxt: an XPath context
13958 * @str:  the XPath expression
13959 *
13960 * Try to compile the XPath expression as a streamable subset.
13961 *
13962 * Returns the compiled expression or NULL if failed to compile.
13963 */
13964static xmlXPathCompExprPtr
13965xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13966    /*
13967     * Optimization: use streaming patterns when the XPath expression can
13968     * be compiled to a stream lookup
13969     */
13970    xmlPatternPtr stream;
13971    xmlXPathCompExprPtr comp;
13972    xmlDictPtr dict = NULL;
13973    const xmlChar **namespaces = NULL;
13974    xmlNsPtr ns;
13975    int i, j;
13976
13977    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
13978        (!xmlStrchr(str, '@'))) {
13979	const xmlChar *tmp;
13980
13981	/*
13982	 * We don't try to handle expressions using the verbose axis
13983	 * specifiers ("::"), just the simplied form at this point.
13984	 * Additionally, if there is no list of namespaces available and
13985	 *  there's a ":" in the expression, indicating a prefixed QName,
13986	 *  then we won't try to compile either. xmlPatterncompile() needs
13987	 *  to have a list of namespaces at compilation time in order to
13988	 *  compile prefixed name tests.
13989	 */
13990	tmp = xmlStrchr(str, ':');
13991	if ((tmp != NULL) &&
13992	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
13993	    return(NULL);
13994
13995	if (ctxt != NULL) {
13996	    dict = ctxt->dict;
13997	    if (ctxt->nsNr > 0) {
13998		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
13999		if (namespaces == NULL) {
14000		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14001		    return(NULL);
14002		}
14003		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14004		    ns = ctxt->namespaces[j];
14005		    namespaces[i++] = ns->href;
14006		    namespaces[i++] = ns->prefix;
14007		}
14008		namespaces[i++] = NULL;
14009		namespaces[i++] = NULL;
14010	    }
14011	}
14012
14013	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14014			&namespaces[0]);
14015	if (namespaces != NULL) {
14016	    xmlFree((xmlChar **)namespaces);
14017 	}
14018	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14019	    comp = xmlXPathNewCompExpr();
14020	    if (comp == NULL) {
14021		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14022		return(NULL);
14023	    }
14024	    comp->stream = stream;
14025	    comp->dict = dict;
14026	    if (comp->dict)
14027		xmlDictReference(comp->dict);
14028	    return(comp);
14029	}
14030	xmlFreePattern(stream);
14031    }
14032    return(NULL);
14033}
14034#endif /* XPATH_STREAMING */
14035
14036static int
14037xmlXPathCanRewriteDosExpression(xmlChar *expr)
14038{
14039    if (expr == NULL)
14040	return(0);
14041    do {
14042        if ((*expr == '/') && (*(++expr) == '/'))
14043	    return(1);
14044    } while (*expr++);
14045    return(0);
14046}
14047static void
14048xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14049{
14050    /*
14051    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14052    * internal representation.
14053    */
14054    if (op->ch1 != -1) {
14055	if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14056	    ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14057	    ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14058	    ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14059	{
14060	    /*
14061	    * This is an "foo"
14062	    */
14063	    xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14064
14065	    if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14066		(prevop->ch1 != -1) &&
14067		((xmlXPathAxisVal) prevop->value ==
14068		    AXIS_DESCENDANT_OR_SELF) &&
14069		(prevop->ch2 == -1) &&
14070		((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14071		((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14072		(comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14073	    {
14074		/*
14075		* This is a "descendant-or-self::node()" without predicates.
14076		* Eliminate it.
14077		*/
14078		op->ch1 = prevop->ch1;
14079		op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14080	    }
14081	}
14082	if (op->ch1 != -1)
14083	    xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14084    }
14085    if (op->ch2 != -1)
14086	xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14087}
14088
14089/**
14090 * xmlXPathCtxtCompile:
14091 * @ctxt: an XPath context
14092 * @str:  the XPath expression
14093 *
14094 * Compile an XPath expression
14095 *
14096 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14097 *         the caller has to free the object.
14098 */
14099xmlXPathCompExprPtr
14100xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14101    xmlXPathParserContextPtr pctxt;
14102    xmlXPathCompExprPtr comp;
14103
14104#ifdef XPATH_STREAMING
14105    comp = xmlXPathTryStreamCompile(ctxt, str);
14106    if (comp != NULL)
14107        return(comp);
14108#endif
14109
14110    xmlXPathInit();
14111
14112    pctxt = xmlXPathNewParserContext(str, ctxt);
14113    xmlXPathCompileExpr(pctxt, 1);
14114
14115    if( pctxt->error != XPATH_EXPRESSION_OK )
14116    {
14117        xmlXPathFreeParserContext(pctxt);
14118        return(NULL);
14119    }
14120
14121    if (*pctxt->cur != 0) {
14122	/*
14123	 * aleksey: in some cases this line prints *second* error message
14124	 * (see bug #78858) and probably this should be fixed.
14125	 * However, we are not sure that all error messages are printed
14126	 * out in other places. It's not critical so we leave it as-is for now
14127	 */
14128	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14129	comp = NULL;
14130    } else {
14131	comp = pctxt->comp;
14132	pctxt->comp = NULL;
14133    }
14134    xmlXPathFreeParserContext(pctxt);
14135    if (comp != NULL) {
14136	comp->expr = xmlStrdup(str);
14137#ifdef DEBUG_EVAL_COUNTS
14138	comp->string = xmlStrdup(str);
14139	comp->nb = 0;
14140#endif
14141	if ((comp->nbStep > 2) &&
14142	    (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14143	{
14144	    xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14145	}
14146    }
14147    return(comp);
14148}
14149
14150/**
14151 * xmlXPathCompile:
14152 * @str:  the XPath expression
14153 *
14154 * Compile an XPath expression
14155 *
14156 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14157 *         the caller has to free the object.
14158 */
14159xmlXPathCompExprPtr
14160xmlXPathCompile(const xmlChar *str) {
14161    return(xmlXPathCtxtCompile(NULL, str));
14162}
14163
14164/**
14165 * xmlXPathCompiledEval:
14166 * @comp:  the compiled XPath expression
14167 * @ctx:  the XPath context
14168 *
14169 * Evaluate the Precompiled XPath expression in the given context.
14170 *
14171 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14172 *         the caller has to free the object.
14173 */
14174xmlXPathObjectPtr
14175xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
14176    xmlXPathParserContextPtr ctxt;
14177    xmlXPathObjectPtr res, tmp, init = NULL;
14178    int stack = 0;
14179#ifndef LIBXML_THREAD_ENABLED
14180    static int reentance = 0;
14181#endif
14182
14183    CHECK_CTXT(ctx)
14184
14185    if (comp == NULL)
14186	return(NULL);
14187    xmlXPathInit();
14188
14189#ifndef LIBXML_THREAD_ENABLED
14190    reentance++;
14191    if (reentance > 1)
14192	xmlXPathDisableOptimizer = 1;
14193#endif
14194
14195#ifdef DEBUG_EVAL_COUNTS
14196    comp->nb++;
14197    if ((comp->string != NULL) && (comp->nb > 100)) {
14198	fprintf(stderr, "100 x %s\n", comp->string);
14199	comp->nb = 0;
14200    }
14201#endif
14202    ctxt = xmlXPathCompParserContext(comp, ctx);
14203    xmlXPathRunEval(ctxt);
14204
14205    if (ctxt->value == NULL) {
14206	xmlGenericError(xmlGenericErrorContext,
14207		"xmlXPathCompiledEval: evaluation failed\n");
14208	res = NULL;
14209    } else {
14210	res = valuePop(ctxt);
14211    }
14212
14213
14214    do {
14215        tmp = valuePop(ctxt);
14216	if (tmp != NULL) {
14217	    if (tmp != init)
14218		stack++;
14219	    xmlXPathReleaseObject(ctx, tmp);
14220        }
14221    } while (tmp != NULL);
14222    if ((stack != 0) && (res != NULL)) {
14223	xmlGenericError(xmlGenericErrorContext,
14224		"xmlXPathCompiledEval: %d object left on the stack\n",
14225	        stack);
14226    }
14227    if (ctxt->error != XPATH_EXPRESSION_OK) {
14228	xmlXPathFreeObject(res);
14229	res = NULL;
14230    }
14231    ctxt->comp = NULL;
14232    xmlXPathFreeParserContext(ctxt);
14233#ifndef LIBXML_THREAD_ENABLED
14234    reentance--;
14235#endif
14236    return(res);
14237}
14238
14239/**
14240 * xmlXPathEvalExpr:
14241 * @ctxt:  the XPath Parser context
14242 *
14243 * Parse and evaluate an XPath expression in the given context,
14244 * then push the result on the context stack
14245 */
14246void
14247xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14248#ifdef XPATH_STREAMING
14249    xmlXPathCompExprPtr comp;
14250#endif
14251
14252    if (ctxt == NULL) return;
14253
14254#ifdef XPATH_STREAMING
14255    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14256    if (comp != NULL) {
14257        if (ctxt->comp != NULL)
14258	    xmlXPathFreeCompExpr(ctxt->comp);
14259        ctxt->comp = comp;
14260	if (ctxt->cur != NULL)
14261	    while (*ctxt->cur != 0) ctxt->cur++;
14262    } else
14263#endif
14264    {
14265	xmlXPathCompileExpr(ctxt, 1);
14266	if ((ctxt->comp != NULL) &&
14267	    (ctxt->comp->nbStep > 2) &&
14268	    (xmlXPathCanRewriteDosExpression(ctxt->comp->expr) == 1))
14269	{
14270	    xmlXPathRewriteDOSExpression(ctxt->comp,
14271		&ctxt->comp->steps[comp->last]);
14272	}
14273    }
14274    CHECK_ERROR;
14275    xmlXPathRunEval(ctxt);
14276}
14277
14278/**
14279 * xmlXPathEval:
14280 * @str:  the XPath expression
14281 * @ctx:  the XPath context
14282 *
14283 * Evaluate the XPath Location Path in the given context.
14284 *
14285 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14286 *         the caller has to free the object.
14287 */
14288xmlXPathObjectPtr
14289xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14290    xmlXPathParserContextPtr ctxt;
14291    xmlXPathObjectPtr res, tmp, init = NULL;
14292    int stack = 0;
14293
14294    CHECK_CTXT(ctx)
14295
14296    xmlXPathInit();
14297
14298    ctxt = xmlXPathNewParserContext(str, ctx);
14299    xmlXPathEvalExpr(ctxt);
14300
14301    if (ctxt->value == NULL) {
14302	xmlGenericError(xmlGenericErrorContext,
14303		"xmlXPathEval: evaluation failed\n");
14304	res = NULL;
14305    } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14306#ifdef XPATH_STREAMING
14307            && (ctxt->comp->stream == NULL)
14308#endif
14309	      ) {
14310	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14311	res = NULL;
14312    } else {
14313	res = valuePop(ctxt);
14314    }
14315
14316    do {
14317        tmp = valuePop(ctxt);
14318	if (tmp != NULL) {
14319	    if (tmp != init)
14320		stack++;
14321	    xmlXPathReleaseObject(ctx, tmp);
14322        }
14323    } while (tmp != NULL);
14324    if ((stack != 0) && (res != NULL)) {
14325	xmlGenericError(xmlGenericErrorContext,
14326		"xmlXPathEval: %d object left on the stack\n",
14327	        stack);
14328    }
14329    if (ctxt->error != XPATH_EXPRESSION_OK) {
14330	xmlXPathFreeObject(res);
14331	res = NULL;
14332    }
14333
14334    xmlXPathFreeParserContext(ctxt);
14335    return(res);
14336}
14337
14338/**
14339 * xmlXPathEvalExpression:
14340 * @str:  the XPath expression
14341 * @ctxt:  the XPath context
14342 *
14343 * Evaluate the XPath expression in the given context.
14344 *
14345 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14346 *         the caller has to free the object.
14347 */
14348xmlXPathObjectPtr
14349xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14350    xmlXPathParserContextPtr pctxt;
14351    xmlXPathObjectPtr res, tmp;
14352    int stack = 0;
14353
14354    CHECK_CTXT(ctxt)
14355
14356    xmlXPathInit();
14357
14358    pctxt = xmlXPathNewParserContext(str, ctxt);
14359    xmlXPathEvalExpr(pctxt);
14360
14361    if (*pctxt->cur != 0) {
14362	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14363	res = NULL;
14364    } else {
14365	res = valuePop(pctxt);
14366    }
14367    do {
14368        tmp = valuePop(pctxt);
14369	if (tmp != NULL) {
14370	    xmlXPathReleaseObject(ctxt, tmp);
14371	    stack++;
14372	}
14373    } while (tmp != NULL);
14374    if ((stack != 0) && (res != NULL)) {
14375	xmlGenericError(xmlGenericErrorContext,
14376		"xmlXPathEvalExpression: %d object left on the stack\n",
14377	        stack);
14378    }
14379    xmlXPathFreeParserContext(pctxt);
14380    return(res);
14381}
14382
14383/************************************************************************
14384 *									*
14385 *	Extra functions not pertaining to the XPath spec		*
14386 *									*
14387 ************************************************************************/
14388/**
14389 * xmlXPathEscapeUriFunction:
14390 * @ctxt:  the XPath Parser context
14391 * @nargs:  the number of arguments
14392 *
14393 * Implement the escape-uri() XPath function
14394 *    string escape-uri(string $str, bool $escape-reserved)
14395 *
14396 * This function applies the URI escaping rules defined in section 2 of [RFC
14397 * 2396] to the string supplied as $uri-part, which typically represents all
14398 * or part of a URI. The effect of the function is to replace any special
14399 * character in the string by an escape sequence of the form %xx%yy...,
14400 * where xxyy... is the hexadecimal representation of the octets used to
14401 * represent the character in UTF-8.
14402 *
14403 * The set of characters that are escaped depends on the setting of the
14404 * boolean argument $escape-reserved.
14405 *
14406 * If $escape-reserved is true, all characters are escaped other than lower
14407 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14408 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14409 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14410 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14411 * A-F).
14412 *
14413 * If $escape-reserved is false, the behavior differs in that characters
14414 * referred to in [RFC 2396] as reserved characters are not escaped. These
14415 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14416 *
14417 * [RFC 2396] does not define whether escaped URIs should use lower case or
14418 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14419 * compared using string comparison functions, this function must always use
14420 * the upper-case letters A-F.
14421 *
14422 * Generally, $escape-reserved should be set to true when escaping a string
14423 * that is to form a single part of a URI, and to false when escaping an
14424 * entire URI or URI reference.
14425 *
14426 * In the case of non-ascii characters, the string is encoded according to
14427 * utf-8 and then converted according to RFC 2396.
14428 *
14429 * Examples
14430 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14431 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14432 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14433 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14434 *
14435 */
14436static void
14437xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14438    xmlXPathObjectPtr str;
14439    int escape_reserved;
14440    xmlBufferPtr target;
14441    xmlChar *cptr;
14442    xmlChar escape[4];
14443
14444    CHECK_ARITY(2);
14445
14446    escape_reserved = xmlXPathPopBoolean(ctxt);
14447
14448    CAST_TO_STRING;
14449    str = valuePop(ctxt);
14450
14451    target = xmlBufferCreate();
14452
14453    escape[0] = '%';
14454    escape[3] = 0;
14455
14456    if (target) {
14457	for (cptr = str->stringval; *cptr; cptr++) {
14458	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
14459		(*cptr >= 'a' && *cptr <= 'z') ||
14460		(*cptr >= '0' && *cptr <= '9') ||
14461		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
14462		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
14463		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14464		(*cptr == '%' &&
14465		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14466		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14467		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
14468		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14469		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14470		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14471		(!escape_reserved &&
14472		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14473		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14474		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14475		  *cptr == ','))) {
14476		xmlBufferAdd(target, cptr, 1);
14477	    } else {
14478		if ((*cptr >> 4) < 10)
14479		    escape[1] = '0' + (*cptr >> 4);
14480		else
14481		    escape[1] = 'A' - 10 + (*cptr >> 4);
14482		if ((*cptr & 0xF) < 10)
14483		    escape[2] = '0' + (*cptr & 0xF);
14484		else
14485		    escape[2] = 'A' - 10 + (*cptr & 0xF);
14486
14487		xmlBufferAdd(target, &escape[0], 3);
14488	    }
14489	}
14490    }
14491    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14492	xmlBufferContent(target)));
14493    xmlBufferFree(target);
14494    xmlXPathReleaseObject(ctxt->context, str);
14495}
14496
14497/**
14498 * xmlXPathRegisterAllFunctions:
14499 * @ctxt:  the XPath context
14500 *
14501 * Registers all default XPath functions in this context
14502 */
14503void
14504xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14505{
14506    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14507                         xmlXPathBooleanFunction);
14508    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14509                         xmlXPathCeilingFunction);
14510    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14511                         xmlXPathCountFunction);
14512    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14513                         xmlXPathConcatFunction);
14514    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14515                         xmlXPathContainsFunction);
14516    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14517                         xmlXPathIdFunction);
14518    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14519                         xmlXPathFalseFunction);
14520    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14521                         xmlXPathFloorFunction);
14522    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14523                         xmlXPathLastFunction);
14524    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14525                         xmlXPathLangFunction);
14526    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14527                         xmlXPathLocalNameFunction);
14528    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14529                         xmlXPathNotFunction);
14530    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14531                         xmlXPathNameFunction);
14532    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14533                         xmlXPathNamespaceURIFunction);
14534    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14535                         xmlXPathNormalizeFunction);
14536    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14537                         xmlXPathNumberFunction);
14538    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14539                         xmlXPathPositionFunction);
14540    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14541                         xmlXPathRoundFunction);
14542    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14543                         xmlXPathStringFunction);
14544    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14545                         xmlXPathStringLengthFunction);
14546    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14547                         xmlXPathStartsWithFunction);
14548    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14549                         xmlXPathSubstringFunction);
14550    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14551                         xmlXPathSubstringBeforeFunction);
14552    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14553                         xmlXPathSubstringAfterFunction);
14554    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14555                         xmlXPathSumFunction);
14556    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14557                         xmlXPathTrueFunction);
14558    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14559                         xmlXPathTranslateFunction);
14560
14561    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14562	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14563                         xmlXPathEscapeUriFunction);
14564}
14565
14566#endif /* LIBXML_XPATH_ENABLED */
14567#define bottom_xpath
14568#include "elfgcchack.h"
14569