xpath.c revision 12d37ab63441baf9e03db70168cc1d0d6f1c2373
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 *
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 * TODO:
69 * There are a few spots where some tests are done which depend upon ascii
70 * data.  These should be enhanced for full UTF8 support (see particularly
71 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
72 */
73
74#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
75/************************************************************************
76 * 									*
77 * 			Floating point stuff				*
78 * 									*
79 ************************************************************************/
80
81#ifndef TRIO_REPLACE_STDIO
82#define TRIO_PUBLIC static
83#endif
84#include "trionan.c"
85
86/*
87 * The lack of portability of this section of the libc is annoying !
88 */
89double xmlXPathNAN = 0;
90double xmlXPathPINF = 1;
91double xmlXPathNINF = -1;
92double xmlXPathNZERO = 0;
93static int xmlXPathInitialized = 0;
94
95/**
96 * xmlXPathInit:
97 *
98 * Initialize the XPath environment
99 */
100void
101xmlXPathInit(void) {
102    if (xmlXPathInitialized) return;
103
104    xmlXPathPINF = trio_pinf();
105    xmlXPathNINF = trio_ninf();
106    xmlXPathNAN = trio_nan();
107    xmlXPathNZERO = trio_nzero();
108
109    xmlXPathInitialized = 1;
110}
111
112/**
113 * xmlXPathIsNaN:
114 * @val:  a double value
115 *
116 * Provides a portable isnan() function to detect whether a double
117 * is a NotaNumber. Based on trio code
118 * http://sourceforge.net/projects/ctrio/
119 *
120 * Returns 1 if the value is a NaN, 0 otherwise
121 */
122int
123xmlXPathIsNaN(double val) {
124    return(trio_isnan(val));
125}
126
127/**
128 * xmlXPathIsInf:
129 * @val:  a double value
130 *
131 * Provides a portable isinf() function to detect whether a double
132 * is a +Infinite or -Infinite. Based on trio code
133 * http://sourceforge.net/projects/ctrio/
134 *
135 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
136 */
137int
138xmlXPathIsInf(double val) {
139    return(trio_isinf(val));
140}
141
142#endif /* SCHEMAS or XPATH */
143#ifdef LIBXML_XPATH_ENABLED
144/**
145 * xmlXPathGetSign:
146 * @val:  a double value
147 *
148 * Provides a portable function to detect the sign of a double
149 * Modified from trio code
150 * http://sourceforge.net/projects/ctrio/
151 *
152 * Returns 1 if the value is Negative, 0 if positive
153 */
154static int
155xmlXPathGetSign(double val) {
156    return(trio_signbit(val));
157}
158
159
160/*
161 * TODO: when compatibility allows remove all "fake node libxslt" strings
162 *       the test should just be name[0] = ' '
163 */
164/* #define DEBUG */
165/* #define DEBUG_STEP */
166/* #define DEBUG_STEP_NTH */
167/* #define DEBUG_EXPR */
168/* #define DEBUG_EVAL_COUNTS */
169
170static xmlNs xmlXPathXMLNamespaceStruct = {
171    NULL,
172    XML_NAMESPACE_DECL,
173    XML_XML_NAMESPACE,
174    BAD_CAST "xml",
175    NULL
176};
177static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
178#ifndef LIBXML_THREAD_ENABLED
179/*
180 * Optimizer is disabled only when threaded apps are detected while
181 * the library ain't compiled for thread safety.
182 */
183static int xmlXPathDisableOptimizer = 0;
184#endif
185
186/************************************************************************
187 *									*
188 *			Error handling routines				*
189 *									*
190 ************************************************************************/
191
192/*
193 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
194 */
195static const char *xmlXPathErrorMessages[] = {
196    "Ok\n",
197    "Number encoding\n",
198    "Unfinished literal\n",
199    "Start of literal\n",
200    "Expected $ for variable reference\n",
201    "Undefined variable\n",
202    "Invalid predicate\n",
203    "Invalid expression\n",
204    "Missing closing curly brace\n",
205    "Unregistered function\n",
206    "Invalid operand\n",
207    "Invalid type\n",
208    "Invalid number of arguments\n",
209    "Invalid context size\n",
210    "Invalid context position\n",
211    "Memory allocation error\n",
212    "Syntax error\n",
213    "Resource error\n",
214    "Sub resource error\n",
215    "Undefined namespace prefix\n",
216    "Encoding error\n",
217    "Char out of XML range\n",
218    "Invalid or incomplete context\n",
219    "?? Unknown error ??\n"	/* Must be last in the list! */
220};
221#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
222		   sizeof(xmlXPathErrorMessages[0])) - 1)
223/**
224 * xmlXPathErrMemory:
225 * @ctxt:  an XPath context
226 * @extra:  extra informations
227 *
228 * Handle a redefinition of attribute error
229 */
230static void
231xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
232{
233    if (ctxt != NULL) {
234        if (extra) {
235            xmlChar buf[200];
236
237            xmlStrPrintf(buf, 200,
238                         BAD_CAST "Memory allocation failed : %s\n",
239                         extra);
240            ctxt->lastError.message = (char *) xmlStrdup(buf);
241        } else {
242            ctxt->lastError.message = (char *)
243	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
244        }
245        ctxt->lastError.domain = XML_FROM_XPATH;
246        ctxt->lastError.code = XML_ERR_NO_MEMORY;
247	if (ctxt->error != NULL)
248	    ctxt->error(ctxt->userData, &ctxt->lastError);
249    } else {
250        if (extra)
251            __xmlRaiseError(NULL, NULL, NULL,
252                            NULL, NULL, XML_FROM_XPATH,
253                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
254                            extra, NULL, NULL, 0, 0,
255                            "Memory allocation failed : %s\n", extra);
256        else
257            __xmlRaiseError(NULL, NULL, NULL,
258                            NULL, NULL, XML_FROM_XPATH,
259                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
260                            NULL, NULL, NULL, 0, 0,
261                            "Memory allocation failed\n");
262    }
263}
264
265/**
266 * xmlXPathPErrMemory:
267 * @ctxt:  an XPath parser context
268 * @extra:  extra informations
269 *
270 * Handle a redefinition of attribute error
271 */
272static void
273xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
274{
275    ctxt->error = XPATH_MEMORY_ERROR;
276    if (ctxt == NULL)
277	xmlXPathErrMemory(NULL, extra);
278    else
279	xmlXPathErrMemory(ctxt->context, extra);
280}
281
282/**
283 * xmlXPathErr:
284 * @ctxt:  a XPath parser context
285 * @error:  the error code
286 *
287 * Handle an XPath error
288 */
289void
290xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
291{
292    if ((error < 0) || (error > MAXERRNO))
293	error = MAXERRNO;
294    if (ctxt == NULL) {
295	__xmlRaiseError(NULL, NULL, NULL,
296			NULL, NULL, XML_FROM_XPATH,
297			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
298			XML_ERR_ERROR, NULL, 0,
299			NULL, NULL, NULL, 0, 0,
300			xmlXPathErrorMessages[error]);
301	return;
302    }
303    ctxt->error = error;
304    if (ctxt->context == NULL) {
305	__xmlRaiseError(NULL, NULL, NULL,
306			NULL, NULL, XML_FROM_XPATH,
307			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
308			XML_ERR_ERROR, NULL, 0,
309			(const char *) ctxt->base, NULL, NULL,
310			ctxt->cur - ctxt->base, 0,
311			xmlXPathErrorMessages[error]);
312	return;
313    }
314    ctxt->context->lastError.domain = XML_FROM_XPATH;
315    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
316                           XPATH_EXPRESSION_OK;
317    ctxt->context->lastError.level = XML_ERR_ERROR;
318    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
319    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
320    ctxt->context->lastError.node = ctxt->context->debugNode;
321    if (ctxt->context->error != NULL) {
322	ctxt->context->error(ctxt->context->userData,
323	                     &ctxt->context->lastError);
324    } else {
325	__xmlRaiseError(NULL, NULL, NULL,
326			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
327			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
328			XML_ERR_ERROR, NULL, 0,
329			(const char *) ctxt->base, NULL, NULL,
330			ctxt->cur - ctxt->base, 0,
331			xmlXPathErrorMessages[error]);
332    }
333
334}
335
336/**
337 * xmlXPatherror:
338 * @ctxt:  the XPath Parser context
339 * @file:  the file name
340 * @line:  the line number
341 * @no:  the error number
342 *
343 * Formats an error message.
344 */
345void
346xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
347              int line ATTRIBUTE_UNUSED, int no) {
348    xmlXPathErr(ctxt, no);
349}
350
351
352/************************************************************************
353 * 									*
354 * 			Parser Types					*
355 * 									*
356 ************************************************************************/
357
358/*
359 * Types are private:
360 */
361
362typedef enum {
363    XPATH_OP_END=0,
364    XPATH_OP_AND,
365    XPATH_OP_OR,
366    XPATH_OP_EQUAL,
367    XPATH_OP_CMP,
368    XPATH_OP_PLUS,
369    XPATH_OP_MULT,
370    XPATH_OP_UNION,
371    XPATH_OP_ROOT,
372    XPATH_OP_NODE,
373    XPATH_OP_RESET,
374    XPATH_OP_COLLECT,
375    XPATH_OP_VALUE,
376    XPATH_OP_VARIABLE,
377    XPATH_OP_FUNCTION,
378    XPATH_OP_ARG,
379    XPATH_OP_PREDICATE,
380    XPATH_OP_FILTER,
381    XPATH_OP_SORT
382#ifdef LIBXML_XPTR_ENABLED
383    ,XPATH_OP_RANGETO
384#endif
385} xmlXPathOp;
386
387typedef enum {
388    AXIS_ANCESTOR = 1,
389    AXIS_ANCESTOR_OR_SELF,
390    AXIS_ATTRIBUTE,
391    AXIS_CHILD,
392    AXIS_DESCENDANT,
393    AXIS_DESCENDANT_OR_SELF,
394    AXIS_FOLLOWING,
395    AXIS_FOLLOWING_SIBLING,
396    AXIS_NAMESPACE,
397    AXIS_PARENT,
398    AXIS_PRECEDING,
399    AXIS_PRECEDING_SIBLING,
400    AXIS_SELF
401} xmlXPathAxisVal;
402
403typedef enum {
404    NODE_TEST_NONE = 0,
405    NODE_TEST_TYPE = 1,
406    NODE_TEST_PI = 2,
407    NODE_TEST_ALL = 3,
408    NODE_TEST_NS = 4,
409    NODE_TEST_NAME = 5
410} xmlXPathTestVal;
411
412typedef enum {
413    NODE_TYPE_NODE = 0,
414    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
415    NODE_TYPE_TEXT = XML_TEXT_NODE,
416    NODE_TYPE_PI = XML_PI_NODE
417} xmlXPathTypeVal;
418
419
420typedef struct _xmlXPathStepOp xmlXPathStepOp;
421typedef xmlXPathStepOp *xmlXPathStepOpPtr;
422struct _xmlXPathStepOp {
423    xmlXPathOp op;		/* The identifier of the operation */
424    int ch1;			/* First child */
425    int ch2;			/* Second child */
426    int value;
427    int value2;
428    int value3;
429    void *value4;
430    void *value5;
431    void *cache;
432    void *cacheURI;
433};
434
435struct _xmlXPathCompExpr {
436    int nbStep;			/* Number of steps in this expression */
437    int maxStep;		/* Maximum number of steps allocated */
438    xmlXPathStepOp *steps;	/* ops for computation of this expression */
439    int last;			/* index of last step in expression */
440    xmlChar *expr;		/* the expression being computed */
441    xmlDictPtr dict;		/* the dictionnary to use if any */
442#ifdef DEBUG_EVAL_COUNTS
443    int nb;
444    xmlChar *string;
445#endif
446#ifdef XPATH_STREAMING
447    xmlPatternPtr stream;
448#endif
449};
450
451/************************************************************************
452 * 									*
453 * 			Parser Type functions 				*
454 * 									*
455 ************************************************************************/
456
457/**
458 * xmlXPathNewCompExpr:
459 *
460 * Create a new Xpath component
461 *
462 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
463 */
464static xmlXPathCompExprPtr
465xmlXPathNewCompExpr(void) {
466    xmlXPathCompExprPtr cur;
467
468    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
469    if (cur == NULL) {
470        xmlXPathErrMemory(NULL, "allocating component\n");
471	return(NULL);
472    }
473    memset(cur, 0, sizeof(xmlXPathCompExpr));
474    cur->maxStep = 10;
475    cur->nbStep = 0;
476    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
477	                                   sizeof(xmlXPathStepOp));
478    if (cur->steps == NULL) {
479        xmlXPathErrMemory(NULL, "allocating steps\n");
480	xmlFree(cur);
481	return(NULL);
482    }
483    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
484    cur->last = -1;
485#ifdef DEBUG_EVAL_COUNTS
486    cur->nb = 0;
487#endif
488    return(cur);
489}
490
491/**
492 * xmlXPathFreeCompExpr:
493 * @comp:  an XPATH comp
494 *
495 * Free up the memory allocated by @comp
496 */
497void
498xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
499{
500    xmlXPathStepOpPtr op;
501    int i;
502
503    if (comp == NULL)
504        return;
505    if (comp->dict == NULL) {
506	for (i = 0; i < comp->nbStep; i++) {
507	    op = &comp->steps[i];
508	    if (op->value4 != NULL) {
509		if (op->op == XPATH_OP_VALUE)
510		    xmlXPathFreeObject(op->value4);
511		else
512		    xmlFree(op->value4);
513	    }
514	    if (op->value5 != NULL)
515		xmlFree(op->value5);
516	}
517    } else {
518	for (i = 0; i < comp->nbStep; i++) {
519	    op = &comp->steps[i];
520	    if (op->value4 != NULL) {
521		if (op->op == XPATH_OP_VALUE)
522		    xmlXPathFreeObject(op->value4);
523	    }
524	}
525        xmlDictFree(comp->dict);
526    }
527    if (comp->steps != NULL) {
528        xmlFree(comp->steps);
529    }
530#ifdef DEBUG_EVAL_COUNTS
531    if (comp->string != NULL) {
532        xmlFree(comp->string);
533    }
534#endif
535#ifdef XPATH_STREAMING
536    if (comp->stream != NULL) {
537        xmlFreePatternList(comp->stream);
538    }
539#endif
540    if (comp->expr != NULL) {
541        xmlFree(comp->expr);
542    }
543
544    xmlFree(comp);
545}
546
547/**
548 * xmlXPathCompExprAdd:
549 * @comp:  the compiled expression
550 * @ch1: first child index
551 * @ch2: second child index
552 * @op:  an op
553 * @value:  the first int value
554 * @value2:  the second int value
555 * @value3:  the third int value
556 * @value4:  the first string value
557 * @value5:  the second string value
558 *
559 * Add a step to an XPath Compiled Expression
560 *
561 * Returns -1 in case of failure, the index otherwise
562 */
563static int
564xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
565   xmlXPathOp op, int value,
566   int value2, int value3, void *value4, void *value5) {
567    if (comp->nbStep >= comp->maxStep) {
568	xmlXPathStepOp *real;
569
570	comp->maxStep *= 2;
571	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
572		                      comp->maxStep * sizeof(xmlXPathStepOp));
573	if (real == NULL) {
574	    comp->maxStep /= 2;
575	    xmlXPathErrMemory(NULL, "adding step\n");
576	    return(-1);
577	}
578	comp->steps = real;
579    }
580    comp->last = comp->nbStep;
581    comp->steps[comp->nbStep].ch1 = ch1;
582    comp->steps[comp->nbStep].ch2 = ch2;
583    comp->steps[comp->nbStep].op = op;
584    comp->steps[comp->nbStep].value = value;
585    comp->steps[comp->nbStep].value2 = value2;
586    comp->steps[comp->nbStep].value3 = value3;
587    if ((comp->dict != NULL) &&
588        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
589	 (op == XPATH_OP_COLLECT))) {
590        if (value4 != NULL) {
591	    comp->steps[comp->nbStep].value4 = (xmlChar *)
592	        (void *)xmlDictLookup(comp->dict, value4, -1);
593	    xmlFree(value4);
594	} else
595	    comp->steps[comp->nbStep].value4 = NULL;
596        if (value5 != NULL) {
597	    comp->steps[comp->nbStep].value5 = (xmlChar *)
598	        (void *)xmlDictLookup(comp->dict, value5, -1);
599	    xmlFree(value5);
600	} else
601	    comp->steps[comp->nbStep].value5 = NULL;
602    } else {
603	comp->steps[comp->nbStep].value4 = value4;
604	comp->steps[comp->nbStep].value5 = value5;
605    }
606    comp->steps[comp->nbStep].cache = NULL;
607    return(comp->nbStep++);
608}
609
610/**
611 * xmlXPathCompSwap:
612 * @comp:  the compiled expression
613 * @op: operation index
614 *
615 * Swaps 2 operations in the compiled expression
616 */
617static void
618xmlXPathCompSwap(xmlXPathStepOpPtr op) {
619    int tmp;
620
621#ifndef LIBXML_THREAD_ENABLED
622    /*
623     * Since this manipulates possibly shared variables, this is
624     * disabled if one detects that the library is used in a multithreaded
625     * application
626     */
627    if (xmlXPathDisableOptimizer)
628	return;
629#endif
630
631    tmp = op->ch1;
632    op->ch1 = op->ch2;
633    op->ch2 = tmp;
634}
635
636#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
637    xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
638	                (op), (val), (val2), (val3), (val4), (val5))
639#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
640    xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
641	                (op), (val), (val2), (val3), (val4), (val5))
642
643#define PUSH_LEAVE_EXPR(op, val, val2) 					\
644xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
645
646#define PUSH_UNARY_EXPR(op, ch, val, val2) 				\
647xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
648
649#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) 			\
650xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
651			(val), (val2), 0 ,NULL ,NULL)
652
653/************************************************************************
654 *									*
655 * 		Debugging related functions				*
656 *									*
657 ************************************************************************/
658
659#define STRANGE 							\
660    xmlGenericError(xmlGenericErrorContext,				\
661	    "Internal error at %s:%d\n",				\
662            __FILE__, __LINE__);
663
664#ifdef LIBXML_DEBUG_ENABLED
665static void
666xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
667    int i;
668    char shift[100];
669
670    for (i = 0;((i < depth) && (i < 25));i++)
671        shift[2 * i] = shift[2 * i + 1] = ' ';
672    shift[2 * i] = shift[2 * i + 1] = 0;
673    if (cur == NULL) {
674	fprintf(output, shift);
675	fprintf(output, "Node is NULL !\n");
676	return;
677
678    }
679
680    if ((cur->type == XML_DOCUMENT_NODE) ||
681	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
682	fprintf(output, shift);
683	fprintf(output, " /\n");
684    } else if (cur->type == XML_ATTRIBUTE_NODE)
685	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
686    else
687	xmlDebugDumpOneNode(output, cur, depth);
688}
689static void
690xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
691    xmlNodePtr tmp;
692    int i;
693    char shift[100];
694
695    for (i = 0;((i < depth) && (i < 25));i++)
696        shift[2 * i] = shift[2 * i + 1] = ' ';
697    shift[2 * i] = shift[2 * i + 1] = 0;
698    if (cur == NULL) {
699	fprintf(output, shift);
700	fprintf(output, "Node is NULL !\n");
701	return;
702
703    }
704
705    while (cur != NULL) {
706	tmp = cur;
707	cur = cur->next;
708	xmlDebugDumpOneNode(output, tmp, depth);
709    }
710}
711
712static void
713xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
714    int i;
715    char shift[100];
716
717    for (i = 0;((i < depth) && (i < 25));i++)
718        shift[2 * i] = shift[2 * i + 1] = ' ';
719    shift[2 * i] = shift[2 * i + 1] = 0;
720
721    if (cur == NULL) {
722	fprintf(output, shift);
723	fprintf(output, "NodeSet is NULL !\n");
724	return;
725
726    }
727
728    if (cur != NULL) {
729	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
730	for (i = 0;i < cur->nodeNr;i++) {
731	    fprintf(output, shift);
732	    fprintf(output, "%d", i + 1);
733	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
734	}
735    }
736}
737
738static void
739xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
740    int i;
741    char shift[100];
742
743    for (i = 0;((i < depth) && (i < 25));i++)
744        shift[2 * i] = shift[2 * i + 1] = ' ';
745    shift[2 * i] = shift[2 * i + 1] = 0;
746
747    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
748	fprintf(output, shift);
749	fprintf(output, "Value Tree is NULL !\n");
750	return;
751
752    }
753
754    fprintf(output, shift);
755    fprintf(output, "%d", i + 1);
756    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
757}
758#if defined(LIBXML_XPTR_ENABLED)
759static void
760xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
761    int i;
762    char shift[100];
763
764    for (i = 0;((i < depth) && (i < 25));i++)
765        shift[2 * i] = shift[2 * i + 1] = ' ';
766    shift[2 * i] = shift[2 * i + 1] = 0;
767
768    if (cur == NULL) {
769	fprintf(output, shift);
770	fprintf(output, "LocationSet is NULL !\n");
771	return;
772
773    }
774
775    for (i = 0;i < cur->locNr;i++) {
776	fprintf(output, shift);
777        fprintf(output, "%d : ", i + 1);
778	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
779    }
780}
781#endif /* LIBXML_XPTR_ENABLED */
782
783/**
784 * xmlXPathDebugDumpObject:
785 * @output:  the FILE * to dump the output
786 * @cur:  the object to inspect
787 * @depth:  indentation level
788 *
789 * Dump the content of the object for debugging purposes
790 */
791void
792xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
793    int i;
794    char shift[100];
795
796    if (output == NULL) return;
797
798    for (i = 0;((i < depth) && (i < 25));i++)
799        shift[2 * i] = shift[2 * i + 1] = ' ';
800    shift[2 * i] = shift[2 * i + 1] = 0;
801
802    fprintf(output, shift);
803
804    if (cur == NULL) {
805        fprintf(output, "Object is empty (NULL)\n");
806	return;
807    }
808    switch(cur->type) {
809        case XPATH_UNDEFINED:
810	    fprintf(output, "Object is uninitialized\n");
811	    break;
812        case XPATH_NODESET:
813	    fprintf(output, "Object is a Node Set :\n");
814	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
815	    break;
816	case XPATH_XSLT_TREE:
817	    fprintf(output, "Object is an XSLT value tree :\n");
818	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
819	    break;
820        case XPATH_BOOLEAN:
821	    fprintf(output, "Object is a Boolean : ");
822	    if (cur->boolval) fprintf(output, "true\n");
823	    else fprintf(output, "false\n");
824	    break;
825        case XPATH_NUMBER:
826	    switch (xmlXPathIsInf(cur->floatval)) {
827	    case 1:
828		fprintf(output, "Object is a number : Infinity\n");
829		break;
830	    case -1:
831		fprintf(output, "Object is a number : -Infinity\n");
832		break;
833	    default:
834		if (xmlXPathIsNaN(cur->floatval)) {
835		    fprintf(output, "Object is a number : NaN\n");
836		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
837		    fprintf(output, "Object is a number : 0\n");
838		} else {
839		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
840		}
841	    }
842	    break;
843        case XPATH_STRING:
844	    fprintf(output, "Object is a string : ");
845	    xmlDebugDumpString(output, cur->stringval);
846	    fprintf(output, "\n");
847	    break;
848	case XPATH_POINT:
849	    fprintf(output, "Object is a point : index %d in node", cur->index);
850	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
851	    fprintf(output, "\n");
852	    break;
853	case XPATH_RANGE:
854	    if ((cur->user2 == NULL) ||
855		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
856		fprintf(output, "Object is a collapsed range :\n");
857		fprintf(output, shift);
858		if (cur->index >= 0)
859		    fprintf(output, "index %d in ", cur->index);
860		fprintf(output, "node\n");
861		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
862			              depth + 1);
863	    } else  {
864		fprintf(output, "Object is a range :\n");
865		fprintf(output, shift);
866		fprintf(output, "From ");
867		if (cur->index >= 0)
868		    fprintf(output, "index %d in ", cur->index);
869		fprintf(output, "node\n");
870		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
871			              depth + 1);
872		fprintf(output, shift);
873		fprintf(output, "To ");
874		if (cur->index2 >= 0)
875		    fprintf(output, "index %d in ", cur->index2);
876		fprintf(output, "node\n");
877		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
878			              depth + 1);
879		fprintf(output, "\n");
880	    }
881	    break;
882	case XPATH_LOCATIONSET:
883#if defined(LIBXML_XPTR_ENABLED)
884	    fprintf(output, "Object is a Location Set:\n");
885	    xmlXPathDebugDumpLocationSet(output,
886		    (xmlLocationSetPtr) cur->user, depth);
887#endif
888	    break;
889	case XPATH_USERS:
890	    fprintf(output, "Object is user defined\n");
891	    break;
892    }
893}
894
895static void
896xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
897	                     xmlXPathStepOpPtr op, int depth) {
898    int i;
899    char shift[100];
900
901    for (i = 0;((i < depth) && (i < 25));i++)
902        shift[2 * i] = shift[2 * i + 1] = ' ';
903    shift[2 * i] = shift[2 * i + 1] = 0;
904
905    fprintf(output, shift);
906    if (op == NULL) {
907	fprintf(output, "Step is NULL\n");
908	return;
909    }
910    switch (op->op) {
911        case XPATH_OP_END:
912	    fprintf(output, "END"); break;
913        case XPATH_OP_AND:
914	    fprintf(output, "AND"); break;
915        case XPATH_OP_OR:
916	    fprintf(output, "OR"); break;
917        case XPATH_OP_EQUAL:
918	     if (op->value)
919		 fprintf(output, "EQUAL =");
920	     else
921		 fprintf(output, "EQUAL !=");
922	     break;
923        case XPATH_OP_CMP:
924	     if (op->value)
925		 fprintf(output, "CMP <");
926	     else
927		 fprintf(output, "CMP >");
928	     if (!op->value2)
929		 fprintf(output, "=");
930	     break;
931        case XPATH_OP_PLUS:
932	     if (op->value == 0)
933		 fprintf(output, "PLUS -");
934	     else if (op->value == 1)
935		 fprintf(output, "PLUS +");
936	     else if (op->value == 2)
937		 fprintf(output, "PLUS unary -");
938	     else if (op->value == 3)
939		 fprintf(output, "PLUS unary - -");
940	     break;
941        case XPATH_OP_MULT:
942	     if (op->value == 0)
943		 fprintf(output, "MULT *");
944	     else if (op->value == 1)
945		 fprintf(output, "MULT div");
946	     else
947		 fprintf(output, "MULT mod");
948	     break;
949        case XPATH_OP_UNION:
950	     fprintf(output, "UNION"); break;
951        case XPATH_OP_ROOT:
952	     fprintf(output, "ROOT"); break;
953        case XPATH_OP_NODE:
954	     fprintf(output, "NODE"); break;
955        case XPATH_OP_RESET:
956	     fprintf(output, "RESET"); break;
957        case XPATH_OP_SORT:
958	     fprintf(output, "SORT"); break;
959        case XPATH_OP_COLLECT: {
960	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
961	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
962	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
963	    const xmlChar *prefix = op->value4;
964	    const xmlChar *name = op->value5;
965
966	    fprintf(output, "COLLECT ");
967	    switch (axis) {
968		case AXIS_ANCESTOR:
969		    fprintf(output, " 'ancestors' "); break;
970		case AXIS_ANCESTOR_OR_SELF:
971		    fprintf(output, " 'ancestors-or-self' "); break;
972		case AXIS_ATTRIBUTE:
973		    fprintf(output, " 'attributes' "); break;
974		case AXIS_CHILD:
975		    fprintf(output, " 'child' "); break;
976		case AXIS_DESCENDANT:
977		    fprintf(output, " 'descendant' "); break;
978		case AXIS_DESCENDANT_OR_SELF:
979		    fprintf(output, " 'descendant-or-self' "); break;
980		case AXIS_FOLLOWING:
981		    fprintf(output, " 'following' "); break;
982		case AXIS_FOLLOWING_SIBLING:
983		    fprintf(output, " 'following-siblings' "); break;
984		case AXIS_NAMESPACE:
985		    fprintf(output, " 'namespace' "); break;
986		case AXIS_PARENT:
987		    fprintf(output, " 'parent' "); break;
988		case AXIS_PRECEDING:
989		    fprintf(output, " 'preceding' "); break;
990		case AXIS_PRECEDING_SIBLING:
991		    fprintf(output, " 'preceding-sibling' "); break;
992		case AXIS_SELF:
993		    fprintf(output, " 'self' "); break;
994	    }
995	    switch (test) {
996                case NODE_TEST_NONE:
997		    fprintf(output, "'none' "); break;
998                case NODE_TEST_TYPE:
999		    fprintf(output, "'type' "); break;
1000                case NODE_TEST_PI:
1001		    fprintf(output, "'PI' "); break;
1002                case NODE_TEST_ALL:
1003		    fprintf(output, "'all' "); break;
1004                case NODE_TEST_NS:
1005		    fprintf(output, "'namespace' "); break;
1006                case NODE_TEST_NAME:
1007		    fprintf(output, "'name' "); break;
1008	    }
1009	    switch (type) {
1010                case NODE_TYPE_NODE:
1011		    fprintf(output, "'node' "); break;
1012                case NODE_TYPE_COMMENT:
1013		    fprintf(output, "'comment' "); break;
1014                case NODE_TYPE_TEXT:
1015		    fprintf(output, "'text' "); break;
1016                case NODE_TYPE_PI:
1017		    fprintf(output, "'PI' "); break;
1018	    }
1019	    if (prefix != NULL)
1020		fprintf(output, "%s:", prefix);
1021	    if (name != NULL)
1022		fprintf(output, "%s", (const char *) name);
1023	    break;
1024
1025        }
1026	case XPATH_OP_VALUE: {
1027	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1028
1029	    fprintf(output, "ELEM ");
1030	    xmlXPathDebugDumpObject(output, object, 0);
1031	    goto finish;
1032	}
1033	case XPATH_OP_VARIABLE: {
1034	    const xmlChar *prefix = op->value5;
1035	    const xmlChar *name = op->value4;
1036
1037	    if (prefix != NULL)
1038		fprintf(output, "VARIABLE %s:%s", prefix, name);
1039	    else
1040		fprintf(output, "VARIABLE %s", name);
1041	    break;
1042	}
1043	case XPATH_OP_FUNCTION: {
1044	    int nbargs = op->value;
1045	    const xmlChar *prefix = op->value5;
1046	    const xmlChar *name = op->value4;
1047
1048	    if (prefix != NULL)
1049		fprintf(output, "FUNCTION %s:%s(%d args)",
1050			prefix, name, nbargs);
1051	    else
1052		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1053	    break;
1054	}
1055        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1056        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1057        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1058#ifdef LIBXML_XPTR_ENABLED
1059        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1060#endif
1061	default:
1062        fprintf(output, "UNKNOWN %d\n", op->op); return;
1063    }
1064    fprintf(output, "\n");
1065finish:
1066    if (op->ch1 >= 0)
1067	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1068    if (op->ch2 >= 0)
1069	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1070}
1071
1072/**
1073 * xmlXPathDebugDumpCompExpr:
1074 * @output:  the FILE * for the output
1075 * @comp:  the precompiled XPath expression
1076 * @depth:  the indentation level.
1077 *
1078 * Dumps the tree of the compiled XPath expression.
1079 */
1080void
1081xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1082	                  int depth) {
1083    int i;
1084    char shift[100];
1085
1086    if ((output == NULL) || (comp == NULL)) return;
1087
1088    for (i = 0;((i < depth) && (i < 25));i++)
1089        shift[2 * i] = shift[2 * i + 1] = ' ';
1090    shift[2 * i] = shift[2 * i + 1] = 0;
1091
1092    fprintf(output, shift);
1093
1094    if (comp == NULL) {
1095	fprintf(output, "Compiled Expression is NULL\n");
1096	return;
1097    }
1098    fprintf(output, "Compiled Expression : %d elements\n",
1099	    comp->nbStep);
1100    i = comp->last;
1101    xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1102}
1103#endif /* LIBXML_DEBUG_ENABLED */
1104
1105/************************************************************************
1106 *									*
1107 * 		Parser stacks related functions and macros		*
1108 *									*
1109 ************************************************************************/
1110
1111/**
1112 * valuePop:
1113 * @ctxt: an XPath evaluation context
1114 *
1115 * Pops the top XPath object from the value stack
1116 *
1117 * Returns the XPath object just removed
1118 */
1119extern xmlXPathObjectPtr
1120valuePop(xmlXPathParserContextPtr ctxt)
1121{
1122    xmlXPathObjectPtr ret;
1123
1124    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1125        return (0);
1126    ctxt->valueNr--;
1127    if (ctxt->valueNr > 0)
1128        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1129    else
1130        ctxt->value = NULL;
1131    ret = ctxt->valueTab[ctxt->valueNr];
1132    ctxt->valueTab[ctxt->valueNr] = 0;
1133    return (ret);
1134}
1135/**
1136 * valuePush:
1137 * @ctxt:  an XPath evaluation context
1138 * @value:  the XPath object
1139 *
1140 * Pushes a new XPath object on top of the value stack
1141 *
1142 * returns the number of items on the value stack
1143 */
1144extern int
1145valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1146{
1147    if ((ctxt == NULL) || (value == NULL)) return(-1);
1148    if (ctxt->valueNr >= ctxt->valueMax) {
1149        xmlXPathObjectPtr *tmp;
1150
1151        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1152                                             2 * ctxt->valueMax *
1153                                             sizeof(ctxt->valueTab[0]));
1154        if (tmp == NULL) {
1155            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1156            return (0);
1157        }
1158        ctxt->valueMax *= 2;
1159	ctxt->valueTab = tmp;
1160    }
1161    ctxt->valueTab[ctxt->valueNr] = value;
1162    ctxt->value = value;
1163    return (ctxt->valueNr++);
1164}
1165
1166/**
1167 * xmlXPathPopBoolean:
1168 * @ctxt:  an XPath parser context
1169 *
1170 * Pops a boolean from the stack, handling conversion if needed.
1171 * Check error with #xmlXPathCheckError.
1172 *
1173 * Returns the boolean
1174 */
1175int
1176xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1177    xmlXPathObjectPtr obj;
1178    int ret;
1179
1180    obj = valuePop(ctxt);
1181    if (obj == NULL) {
1182	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1183	return(0);
1184    }
1185    if (obj->type != XPATH_BOOLEAN)
1186	ret = xmlXPathCastToBoolean(obj);
1187    else
1188        ret = obj->boolval;
1189    xmlXPathFreeObject(obj);
1190    return(ret);
1191}
1192
1193/**
1194 * xmlXPathPopNumber:
1195 * @ctxt:  an XPath parser context
1196 *
1197 * Pops a number from the stack, handling conversion if needed.
1198 * Check error with #xmlXPathCheckError.
1199 *
1200 * Returns the number
1201 */
1202double
1203xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1204    xmlXPathObjectPtr obj;
1205    double ret;
1206
1207    obj = valuePop(ctxt);
1208    if (obj == NULL) {
1209	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1210	return(0);
1211    }
1212    if (obj->type != XPATH_NUMBER)
1213	ret = xmlXPathCastToNumber(obj);
1214    else
1215        ret = obj->floatval;
1216    xmlXPathFreeObject(obj);
1217    return(ret);
1218}
1219
1220/**
1221 * xmlXPathPopString:
1222 * @ctxt:  an XPath parser context
1223 *
1224 * Pops a string from the stack, handling conversion if needed.
1225 * Check error with #xmlXPathCheckError.
1226 *
1227 * Returns the string
1228 */
1229xmlChar *
1230xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1231    xmlXPathObjectPtr obj;
1232    xmlChar * ret;
1233
1234    obj = valuePop(ctxt);
1235    if (obj == NULL) {
1236	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1237	return(NULL);
1238    }
1239    ret = xmlXPathCastToString(obj);	/* this does required strdup */
1240    /* TODO: needs refactoring somewhere else */
1241    if (obj->stringval == ret)
1242	obj->stringval = NULL;
1243    xmlXPathFreeObject(obj);
1244    return(ret);
1245}
1246
1247/**
1248 * xmlXPathPopNodeSet:
1249 * @ctxt:  an XPath parser context
1250 *
1251 * Pops a node-set from the stack, handling conversion if needed.
1252 * Check error with #xmlXPathCheckError.
1253 *
1254 * Returns the node-set
1255 */
1256xmlNodeSetPtr
1257xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1258    xmlXPathObjectPtr obj;
1259    xmlNodeSetPtr ret;
1260
1261    if (ctxt == NULL) return(NULL);
1262    if (ctxt->value == NULL) {
1263	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1264	return(NULL);
1265    }
1266    if (!xmlXPathStackIsNodeSet(ctxt)) {
1267	xmlXPathSetTypeError(ctxt);
1268	return(NULL);
1269    }
1270    obj = valuePop(ctxt);
1271    ret = obj->nodesetval;
1272#if 0
1273    /* to fix memory leak of not clearing obj->user */
1274    if (obj->boolval && obj->user != NULL)
1275        xmlFreeNodeList((xmlNodePtr) obj->user);
1276#endif
1277    xmlXPathFreeNodeSetList(obj);
1278    return(ret);
1279}
1280
1281/**
1282 * xmlXPathPopExternal:
1283 * @ctxt:  an XPath parser context
1284 *
1285 * Pops an external object from the stack, handling conversion if needed.
1286 * Check error with #xmlXPathCheckError.
1287 *
1288 * Returns the object
1289 */
1290void *
1291xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1292    xmlXPathObjectPtr obj;
1293    void * ret;
1294
1295    if ((ctxt == NULL) || (ctxt->value == NULL)) {
1296	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1297	return(NULL);
1298    }
1299    if (ctxt->value->type != XPATH_USERS) {
1300	xmlXPathSetTypeError(ctxt);
1301	return(NULL);
1302    }
1303    obj = valuePop(ctxt);
1304    ret = obj->user;
1305    xmlXPathFreeObject(obj);
1306    return(ret);
1307}
1308
1309/*
1310 * Macros for accessing the content. Those should be used only by the parser,
1311 * and not exported.
1312 *
1313 * Dirty macros, i.e. one need to make assumption on the context to use them
1314 *
1315 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
1316 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
1317 *           in ISO-Latin or UTF-8.
1318 *           This should be used internally by the parser
1319 *           only to compare to ASCII values otherwise it would break when
1320 *           running with UTF-8 encoding.
1321 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
1322 *           to compare on ASCII based substring.
1323 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1324 *           strings within the parser.
1325 *   CURRENT Returns the current char value, with the full decoding of
1326 *           UTF-8 if we are using this mode. It returns an int.
1327 *   NEXT    Skip to the next character, this does the proper decoding
1328 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
1329 *           It returns the pointer to the current xmlChar.
1330 */
1331
1332#define CUR (*ctxt->cur)
1333#define SKIP(val) ctxt->cur += (val)
1334#define NXT(val) ctxt->cur[(val)]
1335#define CUR_PTR ctxt->cur
1336#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1337
1338#define COPY_BUF(l,b,i,v)                                              \
1339    if (l == 1) b[i++] = (xmlChar) v;                                  \
1340    else i += xmlCopyChar(l,&b[i],v)
1341
1342#define NEXTL(l)  ctxt->cur += l
1343
1344#define SKIP_BLANKS 							\
1345    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
1346
1347#define CURRENT (*ctxt->cur)
1348#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
1349
1350
1351#ifndef DBL_DIG
1352#define DBL_DIG 16
1353#endif
1354#ifndef DBL_EPSILON
1355#define DBL_EPSILON 1E-9
1356#endif
1357
1358#define UPPER_DOUBLE 1E9
1359#define LOWER_DOUBLE 1E-5
1360
1361#define INTEGER_DIGITS DBL_DIG
1362#define FRACTION_DIGITS (DBL_DIG + 1)
1363#define EXPONENT_DIGITS (3 + 2)
1364
1365/**
1366 * xmlXPathFormatNumber:
1367 * @number:     number to format
1368 * @buffer:     output buffer
1369 * @buffersize: size of output buffer
1370 *
1371 * Convert the number into a string representation.
1372 */
1373static void
1374xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1375{
1376    switch (xmlXPathIsInf(number)) {
1377    case 1:
1378	if (buffersize > (int)sizeof("Infinity"))
1379	    snprintf(buffer, buffersize, "Infinity");
1380	break;
1381    case -1:
1382	if (buffersize > (int)sizeof("-Infinity"))
1383	    snprintf(buffer, buffersize, "-Infinity");
1384	break;
1385    default:
1386	if (xmlXPathIsNaN(number)) {
1387	    if (buffersize > (int)sizeof("NaN"))
1388		snprintf(buffer, buffersize, "NaN");
1389	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
1390	    snprintf(buffer, buffersize, "0");
1391	} else if (number == ((int) number)) {
1392	    char work[30];
1393	    char *ptr, *cur;
1394	    int res, value = (int) number;
1395
1396            ptr = &buffer[0];
1397	    if (value < 0) {
1398		*ptr++ = '-';
1399		value = -value;
1400	    }
1401	    if (value == 0) {
1402		*ptr++ = '0';
1403	    } else {
1404		cur = &work[0];
1405		while (value != 0) {
1406		    res = value % 10;
1407		    value = value / 10;
1408		    *cur++ = '0' + res;
1409		}
1410		cur--;
1411		while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1412		    *ptr++ = *cur--;
1413		}
1414	    }
1415	    if (ptr - buffer < buffersize) {
1416		*ptr = 0;
1417	    } else if (buffersize > 0) {
1418		ptr--;
1419		*ptr = 0;
1420	    }
1421	} else {
1422	    /* 3 is sign, decimal point, and terminating zero */
1423	    char work[DBL_DIG + EXPONENT_DIGITS + 3];
1424	    int integer_place, fraction_place;
1425	    char *ptr;
1426	    char *after_fraction;
1427	    double absolute_value;
1428	    int size;
1429
1430	    absolute_value = fabs(number);
1431
1432	    /*
1433	     * First choose format - scientific or regular floating point.
1434	     * In either case, result is in work, and after_fraction points
1435	     * just past the fractional part.
1436	    */
1437	    if ( ((absolute_value > UPPER_DOUBLE) ||
1438		  (absolute_value < LOWER_DOUBLE)) &&
1439		 (absolute_value != 0.0) ) {
1440		/* Use scientific notation */
1441		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1442		fraction_place = DBL_DIG - 1;
1443		snprintf(work, sizeof(work),"%*.*e",
1444			 integer_place, fraction_place, number);
1445		after_fraction = strchr(work + DBL_DIG, 'e');
1446	    }
1447	    else {
1448		/* Use regular notation */
1449		if (absolute_value > 0.0)
1450		    integer_place = 1 + (int)log10(absolute_value);
1451		else
1452		    integer_place = 0;
1453		fraction_place = (integer_place > 0)
1454		    ? DBL_DIG - integer_place
1455		    : DBL_DIG;
1456		size = snprintf(work, sizeof(work), "%0.*f",
1457				fraction_place, number);
1458		after_fraction = work + size;
1459	    }
1460
1461	    /* Remove fractional trailing zeroes */
1462	    ptr = after_fraction;
1463	    while (*(--ptr) == '0')
1464		;
1465	    if (*ptr != '.')
1466	        ptr++;
1467	    while ((*ptr++ = *after_fraction++) != 0);
1468
1469	    /* Finally copy result back to caller */
1470	    size = strlen(work) + 1;
1471	    if (size > buffersize) {
1472		work[buffersize - 1] = 0;
1473		size = buffersize;
1474	    }
1475	    memmove(buffer, work, size);
1476	}
1477	break;
1478    }
1479}
1480
1481
1482/************************************************************************
1483 *									*
1484 *			Routines to handle NodeSets			*
1485 *									*
1486 ************************************************************************/
1487
1488/**
1489 * xmlXPathOrderDocElems:
1490 * @doc:  an input document
1491 *
1492 * Call this routine to speed up XPath computation on static documents.
1493 * This stamps all the element nodes with the document order
1494 * Like for line information, the order is kept in the element->content
1495 * field, the value stored is actually - the node number (starting at -1)
1496 * to be able to differentiate from line numbers.
1497 *
1498 * Returns the number of elements found in the document or -1 in case
1499 *    of error.
1500 */
1501long
1502xmlXPathOrderDocElems(xmlDocPtr doc) {
1503    long count = 0;
1504    xmlNodePtr cur;
1505
1506    if (doc == NULL)
1507	return(-1);
1508    cur = doc->children;
1509    while (cur != NULL) {
1510	if (cur->type == XML_ELEMENT_NODE) {
1511	    cur->content = (void *) (-(++count));
1512	    if (cur->children != NULL) {
1513		cur = cur->children;
1514		continue;
1515	    }
1516	}
1517	if (cur->next != NULL) {
1518	    cur = cur->next;
1519	    continue;
1520	}
1521	do {
1522	    cur = cur->parent;
1523	    if (cur == NULL)
1524		break;
1525	    if (cur == (xmlNodePtr) doc) {
1526		cur = NULL;
1527		break;
1528	    }
1529	    if (cur->next != NULL) {
1530		cur = cur->next;
1531		break;
1532	    }
1533	} while (cur != NULL);
1534    }
1535    return(count);
1536}
1537
1538/**
1539 * xmlXPathCmpNodes:
1540 * @node1:  the first node
1541 * @node2:  the second node
1542 *
1543 * Compare two nodes w.r.t document order
1544 *
1545 * Returns -2 in case of error 1 if first point < second point, 0 if
1546 *         it's the same node, -1 otherwise
1547 */
1548int
1549xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1550    int depth1, depth2;
1551    int attr1 = 0, attr2 = 0;
1552    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
1553    xmlNodePtr cur, root;
1554
1555    if ((node1 == NULL) || (node2 == NULL))
1556	return(-2);
1557    /*
1558     * a couple of optimizations which will avoid computations in most cases
1559     */
1560    if (node1->type == XML_ATTRIBUTE_NODE) {
1561	attr1 = 1;
1562	attrNode1 = node1;
1563	node1 = node1->parent;
1564    }
1565    if (node2->type == XML_ATTRIBUTE_NODE) {
1566	attr2 = 1;
1567	attrNode2 = node2;
1568	node2 = node2->parent;
1569    }
1570    if (node1 == node2) {
1571	if (attr1 == attr2) {
1572	    /* not required, but we keep attributes in order */
1573	    if (attr1 != 0) {
1574	        cur = attrNode2->prev;
1575		while (cur != NULL) {
1576		    if (cur == attrNode1)
1577		        return (1);
1578		    cur = cur->prev;
1579		}
1580		return (-1);
1581	    }
1582	    return(0);
1583	}
1584	if (attr2 == 1)
1585	    return(1);
1586	return(-1);
1587    }
1588    if ((node1->type == XML_NAMESPACE_DECL) ||
1589        (node2->type == XML_NAMESPACE_DECL))
1590	return(1);
1591    if (node1 == node2->prev)
1592	return(1);
1593    if (node1 == node2->next)
1594	return(-1);
1595
1596    /*
1597     * Speedup using document order if availble.
1598     */
1599    if ((node1->type == XML_ELEMENT_NODE) &&
1600	(node2->type == XML_ELEMENT_NODE) &&
1601	(0 > (long) node1->content) &&
1602	(0 > (long) node2->content) &&
1603	(node1->doc == node2->doc)) {
1604	long l1, l2;
1605
1606	l1 = -((long) node1->content);
1607	l2 = -((long) node2->content);
1608	if (l1 < l2)
1609	    return(1);
1610	if (l1 > l2)
1611	    return(-1);
1612    }
1613
1614    /*
1615     * compute depth to root
1616     */
1617    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1618	if (cur == node1)
1619	    return(1);
1620	depth2++;
1621    }
1622    root = cur;
1623    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1624	if (cur == node2)
1625	    return(-1);
1626	depth1++;
1627    }
1628    /*
1629     * Distinct document (or distinct entities :-( ) case.
1630     */
1631    if (root != cur) {
1632	return(-2);
1633    }
1634    /*
1635     * get the nearest common ancestor.
1636     */
1637    while (depth1 > depth2) {
1638	depth1--;
1639	node1 = node1->parent;
1640    }
1641    while (depth2 > depth1) {
1642	depth2--;
1643	node2 = node2->parent;
1644    }
1645    while (node1->parent != node2->parent) {
1646	node1 = node1->parent;
1647	node2 = node2->parent;
1648	/* should not happen but just in case ... */
1649	if ((node1 == NULL) || (node2 == NULL))
1650	    return(-2);
1651    }
1652    /*
1653     * Find who's first.
1654     */
1655    if (node1 == node2->prev)
1656	return(1);
1657    if (node1 == node2->next)
1658	return(-1);
1659    /*
1660     * Speedup using document order if availble.
1661     */
1662    if ((node1->type == XML_ELEMENT_NODE) &&
1663	(node2->type == XML_ELEMENT_NODE) &&
1664	(0 > (long) node1->content) &&
1665	(0 > (long) node2->content) &&
1666	(node1->doc == node2->doc)) {
1667	long l1, l2;
1668
1669	l1 = -((long) node1->content);
1670	l2 = -((long) node2->content);
1671	if (l1 < l2)
1672	    return(1);
1673	if (l1 > l2)
1674	    return(-1);
1675    }
1676
1677    for (cur = node1->next;cur != NULL;cur = cur->next)
1678	if (cur == node2)
1679	    return(1);
1680    return(-1); /* assume there is no sibling list corruption */
1681}
1682
1683/**
1684 * xmlXPathNodeSetSort:
1685 * @set:  the node set
1686 *
1687 * Sort the node set in document order
1688 */
1689void
1690xmlXPathNodeSetSort(xmlNodeSetPtr set) {
1691    int i, j, incr, len;
1692    xmlNodePtr tmp;
1693
1694    if (set == NULL)
1695	return;
1696
1697    /* Use Shell's sort to sort the node-set */
1698    len = set->nodeNr;
1699    for (incr = len / 2; incr > 0; incr /= 2) {
1700	for (i = incr; i < len; i++) {
1701	    j = i - incr;
1702	    while (j >= 0) {
1703		if (xmlXPathCmpNodes(set->nodeTab[j],
1704				     set->nodeTab[j + incr]) == -1) {
1705		    tmp = set->nodeTab[j];
1706		    set->nodeTab[j] = set->nodeTab[j + incr];
1707		    set->nodeTab[j + incr] = tmp;
1708		    j -= incr;
1709		} else
1710		    break;
1711	    }
1712	}
1713    }
1714}
1715
1716#define XML_NODESET_DEFAULT	10
1717/**
1718 * xmlXPathNodeSetDupNs:
1719 * @node:  the parent node of the namespace XPath node
1720 * @ns:  the libxml namespace declaration node.
1721 *
1722 * Namespace node in libxml don't match the XPath semantic. In a node set
1723 * the namespace nodes are duplicated and the next pointer is set to the
1724 * parent node in the XPath semantic.
1725 *
1726 * Returns the newly created object.
1727 */
1728static xmlNodePtr
1729xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1730    xmlNsPtr cur;
1731
1732    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1733	return(NULL);
1734    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1735	return((xmlNodePtr) ns);
1736
1737    /*
1738     * Allocate a new Namespace and fill the fields.
1739     */
1740    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1741    if (cur == NULL) {
1742        xmlXPathErrMemory(NULL, "duplicating namespace\n");
1743	return(NULL);
1744    }
1745    memset(cur, 0, sizeof(xmlNs));
1746    cur->type = XML_NAMESPACE_DECL;
1747    if (ns->href != NULL)
1748	cur->href = xmlStrdup(ns->href);
1749    if (ns->prefix != NULL)
1750	cur->prefix = xmlStrdup(ns->prefix);
1751    cur->next = (xmlNsPtr) node;
1752    return((xmlNodePtr) cur);
1753}
1754
1755/**
1756 * xmlXPathNodeSetFreeNs:
1757 * @ns:  the XPath namespace node found in a nodeset.
1758 *
1759 * Namespace nodes in libxml don't match the XPath semantic. In a node set
1760 * the namespace nodes are duplicated and the next pointer is set to the
1761 * parent node in the XPath semantic. Check if such a node needs to be freed
1762 */
1763void
1764xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1765    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1766	return;
1767
1768    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1769	if (ns->href != NULL)
1770	    xmlFree((xmlChar *)ns->href);
1771	if (ns->prefix != NULL)
1772	    xmlFree((xmlChar *)ns->prefix);
1773	xmlFree(ns);
1774    }
1775}
1776
1777/**
1778 * xmlXPathNodeSetCreate:
1779 * @val:  an initial xmlNodePtr, or NULL
1780 *
1781 * Create a new xmlNodeSetPtr of type double and of value @val
1782 *
1783 * Returns the newly created object.
1784 */
1785xmlNodeSetPtr
1786xmlXPathNodeSetCreate(xmlNodePtr val) {
1787    xmlNodeSetPtr ret;
1788
1789    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1790    if (ret == NULL) {
1791        xmlXPathErrMemory(NULL, "creating nodeset\n");
1792	return(NULL);
1793    }
1794    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1795    if (val != NULL) {
1796        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1797					     sizeof(xmlNodePtr));
1798	if (ret->nodeTab == NULL) {
1799	    xmlXPathErrMemory(NULL, "creating nodeset\n");
1800	    xmlFree(ret);
1801	    return(NULL);
1802	}
1803	memset(ret->nodeTab, 0 ,
1804	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1805        ret->nodeMax = XML_NODESET_DEFAULT;
1806	if (val->type == XML_NAMESPACE_DECL) {
1807	    xmlNsPtr ns = (xmlNsPtr) val;
1808
1809	    ret->nodeTab[ret->nodeNr++] =
1810		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1811	} else
1812	    ret->nodeTab[ret->nodeNr++] = val;
1813    }
1814    return(ret);
1815}
1816
1817/**
1818 * xmlXPathNodeSetContains:
1819 * @cur:  the node-set
1820 * @val:  the node
1821 *
1822 * checks whether @cur contains @val
1823 *
1824 * Returns true (1) if @cur contains @val, false (0) otherwise
1825 */
1826int
1827xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1828    int i;
1829
1830    if ((cur == NULL) || (val == NULL)) return(0);
1831    if (val->type == XML_NAMESPACE_DECL) {
1832	for (i = 0; i < cur->nodeNr; i++) {
1833	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1834		xmlNsPtr ns1, ns2;
1835
1836		ns1 = (xmlNsPtr) val;
1837		ns2 = (xmlNsPtr) cur->nodeTab[i];
1838		if (ns1 == ns2)
1839		    return(1);
1840		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1841	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
1842		    return(1);
1843	    }
1844	}
1845    } else {
1846	for (i = 0; i < cur->nodeNr; i++) {
1847	    if (cur->nodeTab[i] == val)
1848		return(1);
1849	}
1850    }
1851    return(0);
1852}
1853
1854/**
1855 * xmlXPathNodeSetAddNs:
1856 * @cur:  the initial node set
1857 * @node:  the hosting node
1858 * @ns:  a the namespace node
1859 *
1860 * add a new namespace node to an existing NodeSet
1861 */
1862void
1863xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1864    int i;
1865
1866
1867    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
1868        (ns->type != XML_NAMESPACE_DECL) ||
1869	(node->type != XML_ELEMENT_NODE))
1870	return;
1871
1872    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
1873    /*
1874     * prevent duplicates
1875     */
1876    for (i = 0;i < cur->nodeNr;i++) {
1877        if ((cur->nodeTab[i] != NULL) &&
1878	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
1879	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
1880	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1881	    return;
1882    }
1883
1884    /*
1885     * grow the nodeTab if needed
1886     */
1887    if (cur->nodeMax == 0) {
1888        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1889					     sizeof(xmlNodePtr));
1890	if (cur->nodeTab == NULL) {
1891	    xmlXPathErrMemory(NULL, "growing nodeset\n");
1892	    return;
1893	}
1894	memset(cur->nodeTab, 0 ,
1895	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1896        cur->nodeMax = XML_NODESET_DEFAULT;
1897    } else if (cur->nodeNr == cur->nodeMax) {
1898        xmlNodePtr *temp;
1899
1900        cur->nodeMax *= 2;
1901	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1902				      sizeof(xmlNodePtr));
1903	if (temp == NULL) {
1904	    xmlXPathErrMemory(NULL, "growing nodeset\n");
1905	    return;
1906	}
1907	cur->nodeTab = temp;
1908    }
1909    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1910}
1911
1912/**
1913 * xmlXPathNodeSetAdd:
1914 * @cur:  the initial node set
1915 * @val:  a new xmlNodePtr
1916 *
1917 * add a new xmlNodePtr to an existing NodeSet
1918 */
1919void
1920xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1921    int i;
1922
1923    if ((cur == NULL) || (val == NULL)) return;
1924
1925#if 0
1926    if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1927	return;	/* an XSLT fake node */
1928#endif
1929
1930    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
1931    /*
1932     * prevent duplcates
1933     */
1934    for (i = 0;i < cur->nodeNr;i++)
1935        if (cur->nodeTab[i] == val) return;
1936
1937    /*
1938     * grow the nodeTab if needed
1939     */
1940    if (cur->nodeMax == 0) {
1941        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1942					     sizeof(xmlNodePtr));
1943	if (cur->nodeTab == NULL) {
1944	    xmlXPathErrMemory(NULL, "growing nodeset\n");
1945	    return;
1946	}
1947	memset(cur->nodeTab, 0 ,
1948	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1949        cur->nodeMax = XML_NODESET_DEFAULT;
1950    } else if (cur->nodeNr == cur->nodeMax) {
1951        xmlNodePtr *temp;
1952
1953        cur->nodeMax *= 2;
1954	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1955				      sizeof(xmlNodePtr));
1956	if (temp == NULL) {
1957	    xmlXPathErrMemory(NULL, "growing nodeset\n");
1958	    return;
1959	}
1960	cur->nodeTab = temp;
1961    }
1962    if (val->type == XML_NAMESPACE_DECL) {
1963	xmlNsPtr ns = (xmlNsPtr) val;
1964
1965	cur->nodeTab[cur->nodeNr++] =
1966	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1967    } else
1968	cur->nodeTab[cur->nodeNr++] = val;
1969}
1970
1971/**
1972 * xmlXPathNodeSetAddUnique:
1973 * @cur:  the initial node set
1974 * @val:  a new xmlNodePtr
1975 *
1976 * add a new xmlNodePtr to an existing NodeSet, optimized version
1977 * when we are sure the node is not already in the set.
1978 */
1979void
1980xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1981    if ((cur == NULL) || (val == NULL)) return;
1982
1983#if 0
1984    if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1985	return;	/* an XSLT fake node */
1986#endif
1987
1988    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
1989    /*
1990     * grow the nodeTab if needed
1991     */
1992    if (cur->nodeMax == 0) {
1993        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1994					     sizeof(xmlNodePtr));
1995	if (cur->nodeTab == NULL) {
1996	    xmlXPathErrMemory(NULL, "growing nodeset\n");
1997	    return;
1998	}
1999	memset(cur->nodeTab, 0 ,
2000	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2001        cur->nodeMax = XML_NODESET_DEFAULT;
2002    } else if (cur->nodeNr == cur->nodeMax) {
2003        xmlNodePtr *temp;
2004
2005        cur->nodeMax *= 2;
2006	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
2007				      sizeof(xmlNodePtr));
2008	if (temp == NULL) {
2009	    xmlXPathErrMemory(NULL, "growing nodeset\n");
2010	    return;
2011	}
2012	cur->nodeTab = temp;
2013    }
2014    if (val->type == XML_NAMESPACE_DECL) {
2015	xmlNsPtr ns = (xmlNsPtr) val;
2016
2017	cur->nodeTab[cur->nodeNr++] =
2018	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2019    } else
2020	cur->nodeTab[cur->nodeNr++] = val;
2021}
2022
2023/**
2024 * xmlXPathNodeSetMerge:
2025 * @val1:  the first NodeSet or NULL
2026 * @val2:  the second NodeSet
2027 *
2028 * Merges two nodesets, all nodes from @val2 are added to @val1
2029 * if @val1 is NULL, a new set is created and copied from @val2
2030 *
2031 * Returns @val1 once extended or NULL in case of error.
2032 */
2033xmlNodeSetPtr
2034xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
2035    int i, j, initNr, skip;
2036
2037    if (val2 == NULL) return(val1);
2038    if (val1 == NULL) {
2039	val1 = xmlXPathNodeSetCreate(NULL);
2040    }
2041
2042    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2043    initNr = val1->nodeNr;
2044
2045    for (i = 0;i < val2->nodeNr;i++) {
2046	/*
2047	 * check against duplicates
2048	 */
2049	skip = 0;
2050	for (j = 0; j < initNr; j++) {
2051	    if (val1->nodeTab[j] == val2->nodeTab[i]) {
2052		skip = 1;
2053		break;
2054	    } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2055		       (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2056		xmlNsPtr ns1, ns2;
2057		ns1 = (xmlNsPtr) val1->nodeTab[j];
2058		ns2 = (xmlNsPtr) val2->nodeTab[i];
2059		if ((ns1->next == ns2->next) &&
2060		    (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2061		    skip = 1;
2062		    break;
2063		}
2064	    }
2065	}
2066	if (skip)
2067	    continue;
2068
2069	/*
2070	 * grow the nodeTab if needed
2071	 */
2072	if (val1->nodeMax == 0) {
2073	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2074						    sizeof(xmlNodePtr));
2075	    if (val1->nodeTab == NULL) {
2076	        xmlXPathErrMemory(NULL, "merging nodeset\n");
2077		return(NULL);
2078	    }
2079	    memset(val1->nodeTab, 0 ,
2080		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2081	    val1->nodeMax = XML_NODESET_DEFAULT;
2082	} else if (val1->nodeNr == val1->nodeMax) {
2083	    xmlNodePtr *temp;
2084
2085	    val1->nodeMax *= 2;
2086	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2087					     sizeof(xmlNodePtr));
2088	    if (temp == NULL) {
2089	        xmlXPathErrMemory(NULL, "merging nodeset\n");
2090		return(NULL);
2091	    }
2092	    val1->nodeTab = temp;
2093	}
2094	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2095	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2096
2097	    val1->nodeTab[val1->nodeNr++] =
2098		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2099	} else
2100	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2101    }
2102
2103    return(val1);
2104}
2105
2106/**
2107 * xmlXPathNodeSetMergeUnique:
2108 * @val1:  the first NodeSet or NULL
2109 * @val2:  the second NodeSet
2110 *
2111 * Merges two nodesets, all nodes from @val2 are added to @val1
2112 * if @val1 is NULL, a new set is created and copied from @val2
2113 *
2114 * Returns @val1 once extended or NULL in case of error.
2115 */
2116static xmlNodeSetPtr
2117xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
2118    int i;
2119
2120    if (val2 == NULL) return(val1);
2121    if (val1 == NULL) {
2122	val1 = xmlXPathNodeSetCreate(NULL);
2123    }
2124
2125    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2126
2127    for (i = 0;i < val2->nodeNr;i++) {
2128	/*
2129	 * grow the nodeTab if needed
2130	 */
2131	if (val1->nodeMax == 0) {
2132	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2133						    sizeof(xmlNodePtr));
2134	    if (val1->nodeTab == NULL) {
2135	        xmlXPathErrMemory(NULL, "merging nodeset\n");
2136		return(NULL);
2137	    }
2138	    memset(val1->nodeTab, 0 ,
2139		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2140	    val1->nodeMax = XML_NODESET_DEFAULT;
2141	} else if (val1->nodeNr == val1->nodeMax) {
2142	    xmlNodePtr *temp;
2143
2144	    val1->nodeMax *= 2;
2145	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2146					     sizeof(xmlNodePtr));
2147	    if (temp == NULL) {
2148	        xmlXPathErrMemory(NULL, "merging nodeset\n");
2149		return(NULL);
2150	    }
2151	    val1->nodeTab = temp;
2152	}
2153	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2154	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2155
2156	    val1->nodeTab[val1->nodeNr++] =
2157		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2158	} else
2159	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2160    }
2161
2162    return(val1);
2163}
2164
2165/**
2166 * xmlXPathNodeSetDel:
2167 * @cur:  the initial node set
2168 * @val:  an xmlNodePtr
2169 *
2170 * Removes an xmlNodePtr from an existing NodeSet
2171 */
2172void
2173xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2174    int i;
2175
2176    if (cur == NULL) return;
2177    if (val == NULL) return;
2178
2179    /*
2180     * find node in nodeTab
2181     */
2182    for (i = 0;i < cur->nodeNr;i++)
2183        if (cur->nodeTab[i] == val) break;
2184
2185    if (i >= cur->nodeNr) {	/* not found */
2186#ifdef DEBUG
2187        xmlGenericError(xmlGenericErrorContext,
2188	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2189		val->name);
2190#endif
2191        return;
2192    }
2193    if ((cur->nodeTab[i] != NULL) &&
2194	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2195	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
2196    cur->nodeNr--;
2197    for (;i < cur->nodeNr;i++)
2198        cur->nodeTab[i] = cur->nodeTab[i + 1];
2199    cur->nodeTab[cur->nodeNr] = NULL;
2200}
2201
2202/**
2203 * xmlXPathNodeSetRemove:
2204 * @cur:  the initial node set
2205 * @val:  the index to remove
2206 *
2207 * Removes an entry from an existing NodeSet list.
2208 */
2209void
2210xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2211    if (cur == NULL) return;
2212    if (val >= cur->nodeNr) return;
2213    if ((cur->nodeTab[val] != NULL) &&
2214	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2215	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
2216    cur->nodeNr--;
2217    for (;val < cur->nodeNr;val++)
2218        cur->nodeTab[val] = cur->nodeTab[val + 1];
2219    cur->nodeTab[cur->nodeNr] = NULL;
2220}
2221
2222/**
2223 * xmlXPathFreeNodeSet:
2224 * @obj:  the xmlNodeSetPtr to free
2225 *
2226 * Free the NodeSet compound (not the actual nodes !).
2227 */
2228void
2229xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2230    if (obj == NULL) return;
2231    if (obj->nodeTab != NULL) {
2232	int i;
2233
2234	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
2235	for (i = 0;i < obj->nodeNr;i++)
2236	    if ((obj->nodeTab[i] != NULL) &&
2237		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2238		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2239	xmlFree(obj->nodeTab);
2240    }
2241    xmlFree(obj);
2242}
2243
2244/**
2245 * xmlXPathFreeValueTree:
2246 * @obj:  the xmlNodeSetPtr to free
2247 *
2248 * Free the NodeSet compound and the actual tree, this is different
2249 * from xmlXPathFreeNodeSet()
2250 */
2251static void
2252xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2253    int i;
2254
2255    if (obj == NULL) return;
2256
2257    if (obj->nodeTab != NULL) {
2258	for (i = 0;i < obj->nodeNr;i++) {
2259	    if (obj->nodeTab[i] != NULL) {
2260		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2261		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2262		} else {
2263		    xmlFreeNodeList(obj->nodeTab[i]);
2264		}
2265	    }
2266	}
2267	xmlFree(obj->nodeTab);
2268    }
2269    xmlFree(obj);
2270}
2271
2272#if defined(DEBUG) || defined(DEBUG_STEP)
2273/**
2274 * xmlGenericErrorContextNodeSet:
2275 * @output:  a FILE * for the output
2276 * @obj:  the xmlNodeSetPtr to display
2277 *
2278 * Quick display of a NodeSet
2279 */
2280void
2281xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2282    int i;
2283
2284    if (output == NULL) output = xmlGenericErrorContext;
2285    if (obj == NULL)  {
2286        fprintf(output, "NodeSet == NULL !\n");
2287	return;
2288    }
2289    if (obj->nodeNr == 0) {
2290        fprintf(output, "NodeSet is empty\n");
2291	return;
2292    }
2293    if (obj->nodeTab == NULL) {
2294	fprintf(output, " nodeTab == NULL !\n");
2295	return;
2296    }
2297    for (i = 0; i < obj->nodeNr; i++) {
2298        if (obj->nodeTab[i] == NULL) {
2299	    fprintf(output, " NULL !\n");
2300	    return;
2301        }
2302	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2303	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2304	    fprintf(output, " /");
2305	else if (obj->nodeTab[i]->name == NULL)
2306	    fprintf(output, " noname!");
2307	else fprintf(output, " %s", obj->nodeTab[i]->name);
2308    }
2309    fprintf(output, "\n");
2310}
2311#endif
2312
2313/**
2314 * xmlXPathNewNodeSet:
2315 * @val:  the NodePtr value
2316 *
2317 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2318 * it with the single Node @val
2319 *
2320 * Returns the newly created object.
2321 */
2322xmlXPathObjectPtr
2323xmlXPathNewNodeSet(xmlNodePtr val) {
2324    xmlXPathObjectPtr ret;
2325
2326    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2327    if (ret == NULL) {
2328        xmlXPathErrMemory(NULL, "creating nodeset\n");
2329	return(NULL);
2330    }
2331    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2332    ret->type = XPATH_NODESET;
2333    ret->boolval = 0;
2334    ret->nodesetval = xmlXPathNodeSetCreate(val);
2335    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2336    return(ret);
2337}
2338
2339/**
2340 * xmlXPathNewValueTree:
2341 * @val:  the NodePtr value
2342 *
2343 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2344 * it with the tree root @val
2345 *
2346 * Returns the newly created object.
2347 */
2348xmlXPathObjectPtr
2349xmlXPathNewValueTree(xmlNodePtr val) {
2350    xmlXPathObjectPtr ret;
2351
2352    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2353    if (ret == NULL) {
2354        xmlXPathErrMemory(NULL, "creating result value tree\n");
2355	return(NULL);
2356    }
2357    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2358    ret->type = XPATH_XSLT_TREE;
2359    ret->boolval = 1;
2360    ret->user = (void *) val;
2361    ret->nodesetval = xmlXPathNodeSetCreate(val);
2362    return(ret);
2363}
2364
2365/**
2366 * xmlXPathNewNodeSetList:
2367 * @val:  an existing NodeSet
2368 *
2369 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2370 * it with the Nodeset @val
2371 *
2372 * Returns the newly created object.
2373 */
2374xmlXPathObjectPtr
2375xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2376{
2377    xmlXPathObjectPtr ret;
2378    int i;
2379
2380    if (val == NULL)
2381        ret = NULL;
2382    else if (val->nodeTab == NULL)
2383        ret = xmlXPathNewNodeSet(NULL);
2384    else {
2385        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2386        for (i = 1; i < val->nodeNr; ++i)
2387            xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2388    }
2389
2390    return (ret);
2391}
2392
2393/**
2394 * xmlXPathWrapNodeSet:
2395 * @val:  the NodePtr value
2396 *
2397 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2398 *
2399 * Returns the newly created object.
2400 */
2401xmlXPathObjectPtr
2402xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2403    xmlXPathObjectPtr ret;
2404
2405    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2406    if (ret == NULL) {
2407        xmlXPathErrMemory(NULL, "creating node set object\n");
2408	return(NULL);
2409    }
2410    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2411    ret->type = XPATH_NODESET;
2412    ret->nodesetval = val;
2413    return(ret);
2414}
2415
2416/**
2417 * xmlXPathFreeNodeSetList:
2418 * @obj:  an existing NodeSetList object
2419 *
2420 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2421 * the list contrary to xmlXPathFreeObject().
2422 */
2423void
2424xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2425    if (obj == NULL) return;
2426    xmlFree(obj);
2427}
2428
2429/**
2430 * xmlXPathDifference:
2431 * @nodes1:  a node-set
2432 * @nodes2:  a node-set
2433 *
2434 * Implements the EXSLT - Sets difference() function:
2435 *    node-set set:difference (node-set, node-set)
2436 *
2437 * Returns the difference between the two node sets, or nodes1 if
2438 *         nodes2 is empty
2439 */
2440xmlNodeSetPtr
2441xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2442    xmlNodeSetPtr ret;
2443    int i, l1;
2444    xmlNodePtr cur;
2445
2446    if (xmlXPathNodeSetIsEmpty(nodes2))
2447	return(nodes1);
2448
2449    ret = xmlXPathNodeSetCreate(NULL);
2450    if (xmlXPathNodeSetIsEmpty(nodes1))
2451	return(ret);
2452
2453    l1 = xmlXPathNodeSetGetLength(nodes1);
2454
2455    for (i = 0; i < l1; i++) {
2456	cur = xmlXPathNodeSetItem(nodes1, i);
2457	if (!xmlXPathNodeSetContains(nodes2, cur))
2458	    xmlXPathNodeSetAddUnique(ret, cur);
2459    }
2460    return(ret);
2461}
2462
2463/**
2464 * xmlXPathIntersection:
2465 * @nodes1:  a node-set
2466 * @nodes2:  a node-set
2467 *
2468 * Implements the EXSLT - Sets intersection() function:
2469 *    node-set set:intersection (node-set, node-set)
2470 *
2471 * Returns a node set comprising the nodes that are within both the
2472 *         node sets passed as arguments
2473 */
2474xmlNodeSetPtr
2475xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2476    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2477    int i, l1;
2478    xmlNodePtr cur;
2479
2480    if (xmlXPathNodeSetIsEmpty(nodes1))
2481	return(ret);
2482    if (xmlXPathNodeSetIsEmpty(nodes2))
2483	return(ret);
2484
2485    l1 = xmlXPathNodeSetGetLength(nodes1);
2486
2487    for (i = 0; i < l1; i++) {
2488	cur = xmlXPathNodeSetItem(nodes1, i);
2489	if (xmlXPathNodeSetContains(nodes2, cur))
2490	    xmlXPathNodeSetAddUnique(ret, cur);
2491    }
2492    return(ret);
2493}
2494
2495/**
2496 * xmlXPathDistinctSorted:
2497 * @nodes:  a node-set, sorted by document order
2498 *
2499 * Implements the EXSLT - Sets distinct() function:
2500 *    node-set set:distinct (node-set)
2501 *
2502 * Returns a subset of the nodes contained in @nodes, or @nodes if
2503 *         it is empty
2504 */
2505xmlNodeSetPtr
2506xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2507    xmlNodeSetPtr ret;
2508    xmlHashTablePtr hash;
2509    int i, l;
2510    xmlChar * strval;
2511    xmlNodePtr cur;
2512
2513    if (xmlXPathNodeSetIsEmpty(nodes))
2514	return(nodes);
2515
2516    ret = xmlXPathNodeSetCreate(NULL);
2517    l = xmlXPathNodeSetGetLength(nodes);
2518    hash = xmlHashCreate (l);
2519    for (i = 0; i < l; i++) {
2520	cur = xmlXPathNodeSetItem(nodes, i);
2521	strval = xmlXPathCastNodeToString(cur);
2522	if (xmlHashLookup(hash, strval) == NULL) {
2523	    xmlHashAddEntry(hash, strval, strval);
2524	    xmlXPathNodeSetAddUnique(ret, cur);
2525	} else {
2526	    xmlFree(strval);
2527	}
2528    }
2529    xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2530    return(ret);
2531}
2532
2533/**
2534 * xmlXPathDistinct:
2535 * @nodes:  a node-set
2536 *
2537 * Implements the EXSLT - Sets distinct() function:
2538 *    node-set set:distinct (node-set)
2539 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2540 * is called with the sorted node-set
2541 *
2542 * Returns a subset of the nodes contained in @nodes, or @nodes if
2543 *         it is empty
2544 */
2545xmlNodeSetPtr
2546xmlXPathDistinct (xmlNodeSetPtr nodes) {
2547    if (xmlXPathNodeSetIsEmpty(nodes))
2548	return(nodes);
2549
2550    xmlXPathNodeSetSort(nodes);
2551    return(xmlXPathDistinctSorted(nodes));
2552}
2553
2554/**
2555 * xmlXPathHasSameNodes:
2556 * @nodes1:  a node-set
2557 * @nodes2:  a node-set
2558 *
2559 * Implements the EXSLT - Sets has-same-nodes function:
2560 *    boolean set:has-same-node(node-set, node-set)
2561 *
2562 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2563 *         otherwise
2564 */
2565int
2566xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2567    int i, l;
2568    xmlNodePtr cur;
2569
2570    if (xmlXPathNodeSetIsEmpty(nodes1) ||
2571	xmlXPathNodeSetIsEmpty(nodes2))
2572	return(0);
2573
2574    l = xmlXPathNodeSetGetLength(nodes1);
2575    for (i = 0; i < l; i++) {
2576	cur = xmlXPathNodeSetItem(nodes1, i);
2577	if (xmlXPathNodeSetContains(nodes2, cur))
2578	    return(1);
2579    }
2580    return(0);
2581}
2582
2583/**
2584 * xmlXPathNodeLeadingSorted:
2585 * @nodes: a node-set, sorted by document order
2586 * @node: a node
2587 *
2588 * Implements the EXSLT - Sets leading() function:
2589 *    node-set set:leading (node-set, node-set)
2590 *
2591 * Returns the nodes in @nodes that precede @node in document order,
2592 *         @nodes if @node is NULL or an empty node-set if @nodes
2593 *         doesn't contain @node
2594 */
2595xmlNodeSetPtr
2596xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2597    int i, l;
2598    xmlNodePtr cur;
2599    xmlNodeSetPtr ret;
2600
2601    if (node == NULL)
2602	return(nodes);
2603
2604    ret = xmlXPathNodeSetCreate(NULL);
2605    if (xmlXPathNodeSetIsEmpty(nodes) ||
2606	(!xmlXPathNodeSetContains(nodes, node)))
2607	return(ret);
2608
2609    l = xmlXPathNodeSetGetLength(nodes);
2610    for (i = 0; i < l; i++) {
2611	cur = xmlXPathNodeSetItem(nodes, i);
2612	if (cur == node)
2613	    break;
2614	xmlXPathNodeSetAddUnique(ret, cur);
2615    }
2616    return(ret);
2617}
2618
2619/**
2620 * xmlXPathNodeLeading:
2621 * @nodes:  a node-set
2622 * @node:  a node
2623 *
2624 * Implements the EXSLT - Sets leading() function:
2625 *    node-set set:leading (node-set, node-set)
2626 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2627 * is called.
2628 *
2629 * Returns the nodes in @nodes that precede @node in document order,
2630 *         @nodes if @node is NULL or an empty node-set if @nodes
2631 *         doesn't contain @node
2632 */
2633xmlNodeSetPtr
2634xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2635    xmlXPathNodeSetSort(nodes);
2636    return(xmlXPathNodeLeadingSorted(nodes, node));
2637}
2638
2639/**
2640 * xmlXPathLeadingSorted:
2641 * @nodes1:  a node-set, sorted by document order
2642 * @nodes2:  a node-set, sorted by document order
2643 *
2644 * Implements the EXSLT - Sets leading() function:
2645 *    node-set set:leading (node-set, node-set)
2646 *
2647 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2648 *         in document order, @nodes1 if @nodes2 is NULL or empty or
2649 *         an empty node-set if @nodes1 doesn't contain @nodes2
2650 */
2651xmlNodeSetPtr
2652xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2653    if (xmlXPathNodeSetIsEmpty(nodes2))
2654	return(nodes1);
2655    return(xmlXPathNodeLeadingSorted(nodes1,
2656				     xmlXPathNodeSetItem(nodes2, 1)));
2657}
2658
2659/**
2660 * xmlXPathLeading:
2661 * @nodes1:  a node-set
2662 * @nodes2:  a node-set
2663 *
2664 * Implements the EXSLT - Sets leading() function:
2665 *    node-set set:leading (node-set, node-set)
2666 * @nodes1 and @nodes2 are sorted by document order, then
2667 * #exslSetsLeadingSorted is called.
2668 *
2669 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2670 *         in document order, @nodes1 if @nodes2 is NULL or empty or
2671 *         an empty node-set if @nodes1 doesn't contain @nodes2
2672 */
2673xmlNodeSetPtr
2674xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2675    if (xmlXPathNodeSetIsEmpty(nodes2))
2676	return(nodes1);
2677    if (xmlXPathNodeSetIsEmpty(nodes1))
2678	return(xmlXPathNodeSetCreate(NULL));
2679    xmlXPathNodeSetSort(nodes1);
2680    xmlXPathNodeSetSort(nodes2);
2681    return(xmlXPathNodeLeadingSorted(nodes1,
2682				     xmlXPathNodeSetItem(nodes2, 1)));
2683}
2684
2685/**
2686 * xmlXPathNodeTrailingSorted:
2687 * @nodes: a node-set, sorted by document order
2688 * @node: a node
2689 *
2690 * Implements the EXSLT - Sets trailing() function:
2691 *    node-set set:trailing (node-set, node-set)
2692 *
2693 * Returns the nodes in @nodes that follow @node in document order,
2694 *         @nodes if @node is NULL or an empty node-set if @nodes
2695 *         doesn't contain @node
2696 */
2697xmlNodeSetPtr
2698xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2699    int i, l;
2700    xmlNodePtr cur;
2701    xmlNodeSetPtr ret;
2702
2703    if (node == NULL)
2704	return(nodes);
2705
2706    ret = xmlXPathNodeSetCreate(NULL);
2707    if (xmlXPathNodeSetIsEmpty(nodes) ||
2708	(!xmlXPathNodeSetContains(nodes, node)))
2709	return(ret);
2710
2711    l = xmlXPathNodeSetGetLength(nodes);
2712    for (i = l; i > 0; i--) {
2713	cur = xmlXPathNodeSetItem(nodes, i);
2714	if (cur == node)
2715	    break;
2716	xmlXPathNodeSetAddUnique(ret, cur);
2717    }
2718    return(ret);
2719}
2720
2721/**
2722 * xmlXPathNodeTrailing:
2723 * @nodes:  a node-set
2724 * @node:  a node
2725 *
2726 * Implements the EXSLT - Sets trailing() function:
2727 *    node-set set:trailing (node-set, node-set)
2728 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2729 * is called.
2730 *
2731 * Returns the nodes in @nodes that follow @node in document order,
2732 *         @nodes if @node is NULL or an empty node-set if @nodes
2733 *         doesn't contain @node
2734 */
2735xmlNodeSetPtr
2736xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2737    xmlXPathNodeSetSort(nodes);
2738    return(xmlXPathNodeTrailingSorted(nodes, node));
2739}
2740
2741/**
2742 * xmlXPathTrailingSorted:
2743 * @nodes1:  a node-set, sorted by document order
2744 * @nodes2:  a node-set, sorted by document order
2745 *
2746 * Implements the EXSLT - Sets trailing() function:
2747 *    node-set set:trailing (node-set, node-set)
2748 *
2749 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2750 *         in document order, @nodes1 if @nodes2 is NULL or empty or
2751 *         an empty node-set if @nodes1 doesn't contain @nodes2
2752 */
2753xmlNodeSetPtr
2754xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2755    if (xmlXPathNodeSetIsEmpty(nodes2))
2756	return(nodes1);
2757    return(xmlXPathNodeTrailingSorted(nodes1,
2758				      xmlXPathNodeSetItem(nodes2, 0)));
2759}
2760
2761/**
2762 * xmlXPathTrailing:
2763 * @nodes1:  a node-set
2764 * @nodes2:  a node-set
2765 *
2766 * Implements the EXSLT - Sets trailing() function:
2767 *    node-set set:trailing (node-set, node-set)
2768 * @nodes1 and @nodes2 are sorted by document order, then
2769 * #xmlXPathTrailingSorted is called.
2770 *
2771 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2772 *         in document order, @nodes1 if @nodes2 is NULL or empty or
2773 *         an empty node-set if @nodes1 doesn't contain @nodes2
2774 */
2775xmlNodeSetPtr
2776xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2777    if (xmlXPathNodeSetIsEmpty(nodes2))
2778	return(nodes1);
2779    if (xmlXPathNodeSetIsEmpty(nodes1))
2780	return(xmlXPathNodeSetCreate(NULL));
2781    xmlXPathNodeSetSort(nodes1);
2782    xmlXPathNodeSetSort(nodes2);
2783    return(xmlXPathNodeTrailingSorted(nodes1,
2784				      xmlXPathNodeSetItem(nodes2, 0)));
2785}
2786
2787/************************************************************************
2788 *									*
2789 *		Routines to handle extra functions			*
2790 *									*
2791 ************************************************************************/
2792
2793/**
2794 * xmlXPathRegisterFunc:
2795 * @ctxt:  the XPath context
2796 * @name:  the function name
2797 * @f:  the function implementation or NULL
2798 *
2799 * Register a new function. If @f is NULL it unregisters the function
2800 *
2801 * Returns 0 in case of success, -1 in case of error
2802 */
2803int
2804xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2805		     xmlXPathFunction f) {
2806    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2807}
2808
2809/**
2810 * xmlXPathRegisterFuncNS:
2811 * @ctxt:  the XPath context
2812 * @name:  the function name
2813 * @ns_uri:  the function namespace URI
2814 * @f:  the function implementation or NULL
2815 *
2816 * Register a new function. If @f is NULL it unregisters the function
2817 *
2818 * Returns 0 in case of success, -1 in case of error
2819 */
2820int
2821xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2822		       const xmlChar *ns_uri, xmlXPathFunction f) {
2823    if (ctxt == NULL)
2824	return(-1);
2825    if (name == NULL)
2826	return(-1);
2827
2828    if (ctxt->funcHash == NULL)
2829	ctxt->funcHash = xmlHashCreate(0);
2830    if (ctxt->funcHash == NULL)
2831	return(-1);
2832    if (f == NULL)
2833        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
2834    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
2835}
2836
2837/**
2838 * xmlXPathRegisterFuncLookup:
2839 * @ctxt:  the XPath context
2840 * @f:  the lookup function
2841 * @funcCtxt:  the lookup data
2842 *
2843 * Registers an external mechanism to do function lookup.
2844 */
2845void
2846xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2847			    xmlXPathFuncLookupFunc f,
2848			    void *funcCtxt) {
2849    if (ctxt == NULL)
2850	return;
2851    ctxt->funcLookupFunc = f;
2852    ctxt->funcLookupData = funcCtxt;
2853}
2854
2855/**
2856 * xmlXPathFunctionLookup:
2857 * @ctxt:  the XPath context
2858 * @name:  the function name
2859 *
2860 * Search in the Function array of the context for the given
2861 * function.
2862 *
2863 * Returns the xmlXPathFunction or NULL if not found
2864 */
2865xmlXPathFunction
2866xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2867    if (ctxt == NULL)
2868	return (NULL);
2869
2870    if (ctxt->funcLookupFunc != NULL) {
2871	xmlXPathFunction ret;
2872	xmlXPathFuncLookupFunc f;
2873
2874	f = ctxt->funcLookupFunc;
2875	ret = f(ctxt->funcLookupData, name, NULL);
2876	if (ret != NULL)
2877	    return(ret);
2878    }
2879    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2880}
2881
2882/**
2883 * xmlXPathFunctionLookupNS:
2884 * @ctxt:  the XPath context
2885 * @name:  the function name
2886 * @ns_uri:  the function namespace URI
2887 *
2888 * Search in the Function array of the context for the given
2889 * function.
2890 *
2891 * Returns the xmlXPathFunction or NULL if not found
2892 */
2893xmlXPathFunction
2894xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2895			 const xmlChar *ns_uri) {
2896    xmlXPathFunction ret;
2897
2898    if (ctxt == NULL)
2899	return(NULL);
2900    if (name == NULL)
2901	return(NULL);
2902
2903    if (ctxt->funcLookupFunc != NULL) {
2904	xmlXPathFuncLookupFunc f;
2905
2906	f = ctxt->funcLookupFunc;
2907	ret = f(ctxt->funcLookupData, name, ns_uri);
2908	if (ret != NULL)
2909	    return(ret);
2910    }
2911
2912    if (ctxt->funcHash == NULL)
2913	return(NULL);
2914
2915    XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
2916    return(ret);
2917}
2918
2919/**
2920 * xmlXPathRegisteredFuncsCleanup:
2921 * @ctxt:  the XPath context
2922 *
2923 * Cleanup the XPath context data associated to registered functions
2924 */
2925void
2926xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2927    if (ctxt == NULL)
2928	return;
2929
2930    xmlHashFree(ctxt->funcHash, NULL);
2931    ctxt->funcHash = NULL;
2932}
2933
2934/************************************************************************
2935 *									*
2936 *			Routines to handle Variables			*
2937 *									*
2938 ************************************************************************/
2939
2940/**
2941 * xmlXPathRegisterVariable:
2942 * @ctxt:  the XPath context
2943 * @name:  the variable name
2944 * @value:  the variable value or NULL
2945 *
2946 * Register a new variable value. If @value is NULL it unregisters
2947 * the variable
2948 *
2949 * Returns 0 in case of success, -1 in case of error
2950 */
2951int
2952xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2953			 xmlXPathObjectPtr value) {
2954    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2955}
2956
2957/**
2958 * xmlXPathRegisterVariableNS:
2959 * @ctxt:  the XPath context
2960 * @name:  the variable name
2961 * @ns_uri:  the variable namespace URI
2962 * @value:  the variable value or NULL
2963 *
2964 * Register a new variable value. If @value is NULL it unregisters
2965 * the variable
2966 *
2967 * Returns 0 in case of success, -1 in case of error
2968 */
2969int
2970xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2971			   const xmlChar *ns_uri,
2972			   xmlXPathObjectPtr value) {
2973    if (ctxt == NULL)
2974	return(-1);
2975    if (name == NULL)
2976	return(-1);
2977
2978    if (ctxt->varHash == NULL)
2979	ctxt->varHash = xmlHashCreate(0);
2980    if (ctxt->varHash == NULL)
2981	return(-1);
2982    if (value == NULL)
2983        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2984	                           (xmlHashDeallocator)xmlXPathFreeObject));
2985    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2986			       (void *) value,
2987			       (xmlHashDeallocator)xmlXPathFreeObject));
2988}
2989
2990/**
2991 * xmlXPathRegisterVariableLookup:
2992 * @ctxt:  the XPath context
2993 * @f:  the lookup function
2994 * @data:  the lookup data
2995 *
2996 * register an external mechanism to do variable lookup
2997 */
2998void
2999xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
3000	 xmlXPathVariableLookupFunc f, void *data) {
3001    if (ctxt == NULL)
3002	return;
3003    ctxt->varLookupFunc = f;
3004    ctxt->varLookupData = data;
3005}
3006
3007/**
3008 * xmlXPathVariableLookup:
3009 * @ctxt:  the XPath context
3010 * @name:  the variable name
3011 *
3012 * Search in the Variable array of the context for the given
3013 * variable value.
3014 *
3015 * Returns a copy of the value or NULL if not found
3016 */
3017xmlXPathObjectPtr
3018xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3019    if (ctxt == NULL)
3020	return(NULL);
3021
3022    if (ctxt->varLookupFunc != NULL) {
3023	xmlXPathObjectPtr ret;
3024
3025	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3026	        (ctxt->varLookupData, name, NULL);
3027	return(ret);
3028    }
3029    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3030}
3031
3032/**
3033 * xmlXPathVariableLookupNS:
3034 * @ctxt:  the XPath context
3035 * @name:  the variable name
3036 * @ns_uri:  the variable namespace URI
3037 *
3038 * Search in the Variable array of the context for the given
3039 * variable value.
3040 *
3041 * Returns the a copy of the value or NULL if not found
3042 */
3043xmlXPathObjectPtr
3044xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3045			 const xmlChar *ns_uri) {
3046    if (ctxt == NULL)
3047	return(NULL);
3048
3049    if (ctxt->varLookupFunc != NULL) {
3050	xmlXPathObjectPtr ret;
3051
3052	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3053	        (ctxt->varLookupData, name, ns_uri);
3054	if (ret != NULL) return(ret);
3055    }
3056
3057    if (ctxt->varHash == NULL)
3058	return(NULL);
3059    if (name == NULL)
3060	return(NULL);
3061
3062    return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3063		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
3064}
3065
3066/**
3067 * xmlXPathRegisteredVariablesCleanup:
3068 * @ctxt:  the XPath context
3069 *
3070 * Cleanup the XPath context data associated to registered variables
3071 */
3072void
3073xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3074    if (ctxt == NULL)
3075	return;
3076
3077    xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
3078    ctxt->varHash = NULL;
3079}
3080
3081/**
3082 * xmlXPathRegisterNs:
3083 * @ctxt:  the XPath context
3084 * @prefix:  the namespace prefix
3085 * @ns_uri:  the namespace name
3086 *
3087 * Register a new namespace. If @ns_uri is NULL it unregisters
3088 * the namespace
3089 *
3090 * Returns 0 in case of success, -1 in case of error
3091 */
3092int
3093xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3094			   const xmlChar *ns_uri) {
3095    if (ctxt == NULL)
3096	return(-1);
3097    if (prefix == NULL)
3098	return(-1);
3099
3100    if (ctxt->nsHash == NULL)
3101	ctxt->nsHash = xmlHashCreate(10);
3102    if (ctxt->nsHash == NULL)
3103	return(-1);
3104    if (ns_uri == NULL)
3105        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
3106	                          (xmlHashDeallocator)xmlFree));
3107    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
3108			      (xmlHashDeallocator)xmlFree));
3109}
3110
3111/**
3112 * xmlXPathNsLookup:
3113 * @ctxt:  the XPath context
3114 * @prefix:  the namespace prefix value
3115 *
3116 * Search in the namespace declaration array of the context for the given
3117 * namespace name associated to the given prefix
3118 *
3119 * Returns the value or NULL if not found
3120 */
3121const xmlChar *
3122xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3123    if (ctxt == NULL)
3124	return(NULL);
3125    if (prefix == NULL)
3126	return(NULL);
3127
3128#ifdef XML_XML_NAMESPACE
3129    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3130	return(XML_XML_NAMESPACE);
3131#endif
3132
3133    if (ctxt->namespaces != NULL) {
3134	int i;
3135
3136	for (i = 0;i < ctxt->nsNr;i++) {
3137	    if ((ctxt->namespaces[i] != NULL) &&
3138		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3139		return(ctxt->namespaces[i]->href);
3140	}
3141    }
3142
3143    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3144}
3145
3146/**
3147 * xmlXPathRegisteredNsCleanup:
3148 * @ctxt:  the XPath context
3149 *
3150 * Cleanup the XPath context data associated to registered variables
3151 */
3152void
3153xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3154    if (ctxt == NULL)
3155	return;
3156
3157    xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
3158    ctxt->nsHash = NULL;
3159}
3160
3161/************************************************************************
3162 *									*
3163 *			Routines to handle Values			*
3164 *									*
3165 ************************************************************************/
3166
3167/* Allocations are terrible, one needs to optimize all this !!! */
3168
3169/**
3170 * xmlXPathNewFloat:
3171 * @val:  the double value
3172 *
3173 * Create a new xmlXPathObjectPtr of type double and of value @val
3174 *
3175 * Returns the newly created object.
3176 */
3177xmlXPathObjectPtr
3178xmlXPathNewFloat(double val) {
3179    xmlXPathObjectPtr ret;
3180
3181    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3182    if (ret == NULL) {
3183        xmlXPathErrMemory(NULL, "creating float object\n");
3184	return(NULL);
3185    }
3186    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3187    ret->type = XPATH_NUMBER;
3188    ret->floatval = val;
3189    return(ret);
3190}
3191
3192/**
3193 * xmlXPathNewBoolean:
3194 * @val:  the boolean value
3195 *
3196 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3197 *
3198 * Returns the newly created object.
3199 */
3200xmlXPathObjectPtr
3201xmlXPathNewBoolean(int val) {
3202    xmlXPathObjectPtr ret;
3203
3204    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3205    if (ret == NULL) {
3206        xmlXPathErrMemory(NULL, "creating boolean object\n");
3207	return(NULL);
3208    }
3209    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3210    ret->type = XPATH_BOOLEAN;
3211    ret->boolval = (val != 0);
3212    return(ret);
3213}
3214
3215/**
3216 * xmlXPathNewString:
3217 * @val:  the xmlChar * value
3218 *
3219 * Create a new xmlXPathObjectPtr of type string and of value @val
3220 *
3221 * Returns the newly created object.
3222 */
3223xmlXPathObjectPtr
3224xmlXPathNewString(const xmlChar *val) {
3225    xmlXPathObjectPtr ret;
3226
3227    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3228    if (ret == NULL) {
3229        xmlXPathErrMemory(NULL, "creating string object\n");
3230	return(NULL);
3231    }
3232    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3233    ret->type = XPATH_STRING;
3234    if (val != NULL)
3235	ret->stringval = xmlStrdup(val);
3236    else
3237	ret->stringval = xmlStrdup((const xmlChar *)"");
3238    return(ret);
3239}
3240
3241/**
3242 * xmlXPathWrapString:
3243 * @val:  the xmlChar * value
3244 *
3245 * Wraps the @val string into an XPath object.
3246 *
3247 * Returns the newly created object.
3248 */
3249xmlXPathObjectPtr
3250xmlXPathWrapString (xmlChar *val) {
3251    xmlXPathObjectPtr ret;
3252
3253    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3254    if (ret == NULL) {
3255        xmlXPathErrMemory(NULL, "creating string object\n");
3256	return(NULL);
3257    }
3258    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3259    ret->type = XPATH_STRING;
3260    ret->stringval = val;
3261    return(ret);
3262}
3263
3264/**
3265 * xmlXPathNewCString:
3266 * @val:  the char * value
3267 *
3268 * Create a new xmlXPathObjectPtr of type string and of value @val
3269 *
3270 * Returns the newly created object.
3271 */
3272xmlXPathObjectPtr
3273xmlXPathNewCString(const char *val) {
3274    xmlXPathObjectPtr ret;
3275
3276    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3277    if (ret == NULL) {
3278        xmlXPathErrMemory(NULL, "creating string object\n");
3279	return(NULL);
3280    }
3281    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3282    ret->type = XPATH_STRING;
3283    ret->stringval = xmlStrdup(BAD_CAST val);
3284    return(ret);
3285}
3286
3287/**
3288 * xmlXPathWrapCString:
3289 * @val:  the char * value
3290 *
3291 * Wraps a string into an XPath object.
3292 *
3293 * Returns the newly created object.
3294 */
3295xmlXPathObjectPtr
3296xmlXPathWrapCString (char * val) {
3297    return(xmlXPathWrapString((xmlChar *)(val)));
3298}
3299
3300/**
3301 * xmlXPathWrapExternal:
3302 * @val:  the user data
3303 *
3304 * Wraps the @val data into an XPath object.
3305 *
3306 * Returns the newly created object.
3307 */
3308xmlXPathObjectPtr
3309xmlXPathWrapExternal (void *val) {
3310    xmlXPathObjectPtr ret;
3311
3312    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3313    if (ret == NULL) {
3314        xmlXPathErrMemory(NULL, "creating user object\n");
3315	return(NULL);
3316    }
3317    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3318    ret->type = XPATH_USERS;
3319    ret->user = val;
3320    return(ret);
3321}
3322
3323/**
3324 * xmlXPathObjectCopy:
3325 * @val:  the original object
3326 *
3327 * allocate a new copy of a given object
3328 *
3329 * Returns the newly created object.
3330 */
3331xmlXPathObjectPtr
3332xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3333    xmlXPathObjectPtr ret;
3334
3335    if (val == NULL)
3336	return(NULL);
3337
3338    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3339    if (ret == NULL) {
3340        xmlXPathErrMemory(NULL, "copying object\n");
3341	return(NULL);
3342    }
3343    memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3344    switch (val->type) {
3345	case XPATH_BOOLEAN:
3346	case XPATH_NUMBER:
3347	case XPATH_POINT:
3348	case XPATH_RANGE:
3349	    break;
3350	case XPATH_STRING:
3351	    ret->stringval = xmlStrdup(val->stringval);
3352	    break;
3353	case XPATH_XSLT_TREE:
3354#if 0
3355/*
3356  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3357  this previous handling is no longer correct, and can cause some serious
3358  problems (ref. bug 145547)
3359*/
3360	    if ((val->nodesetval != NULL) &&
3361		(val->nodesetval->nodeTab != NULL)) {
3362		xmlNodePtr cur, tmp;
3363		xmlDocPtr top;
3364
3365		ret->boolval = 1;
3366		top =  xmlNewDoc(NULL);
3367		top->name = (char *)
3368		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
3369		ret->user = top;
3370		if (top != NULL) {
3371		    top->doc = top;
3372		    cur = val->nodesetval->nodeTab[0]->children;
3373		    while (cur != NULL) {
3374			tmp = xmlDocCopyNode(cur, top, 1);
3375			xmlAddChild((xmlNodePtr) top, tmp);
3376			cur = cur->next;
3377		    }
3378		}
3379
3380		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
3381	    } else
3382		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
3383	    /* Deallocate the copied tree value */
3384	    break;
3385#endif
3386	case XPATH_NODESET:
3387	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
3388	    /* Do not deallocate the copied tree value */
3389	    ret->boolval = 0;
3390	    break;
3391	case XPATH_LOCATIONSET:
3392#ifdef LIBXML_XPTR_ENABLED
3393	{
3394	    xmlLocationSetPtr loc = val->user;
3395	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3396	    break;
3397	}
3398#endif
3399        case XPATH_USERS:
3400	    ret->user = val->user;
3401	    break;
3402        case XPATH_UNDEFINED:
3403	    xmlGenericError(xmlGenericErrorContext,
3404		    "xmlXPathObjectCopy: unsupported type %d\n",
3405		    val->type);
3406	    break;
3407    }
3408    return(ret);
3409}
3410
3411/**
3412 * xmlXPathFreeObject:
3413 * @obj:  the object to free
3414 *
3415 * Free up an xmlXPathObjectPtr object.
3416 */
3417void
3418xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3419    if (obj == NULL) return;
3420    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
3421	if (obj->boolval) {
3422#if 0
3423	    if (obj->user != NULL) {
3424                xmlXPathFreeNodeSet(obj->nodesetval);
3425		xmlFreeNodeList((xmlNodePtr) obj->user);
3426	    } else
3427#endif
3428	    if (obj->nodesetval != NULL)
3429		xmlXPathFreeValueTree(obj->nodesetval);
3430	} else {
3431	    if (obj->nodesetval != NULL)
3432		xmlXPathFreeNodeSet(obj->nodesetval);
3433	}
3434#ifdef LIBXML_XPTR_ENABLED
3435    } else if (obj->type == XPATH_LOCATIONSET) {
3436	if (obj->user != NULL)
3437	    xmlXPtrFreeLocationSet(obj->user);
3438#endif
3439    } else if (obj->type == XPATH_STRING) {
3440	if (obj->stringval != NULL)
3441	    xmlFree(obj->stringval);
3442    }
3443
3444    xmlFree(obj);
3445}
3446
3447
3448/************************************************************************
3449 *									*
3450 *			Type Casting Routines				*
3451 *									*
3452 ************************************************************************/
3453
3454/**
3455 * xmlXPathCastBooleanToString:
3456 * @val:  a boolean
3457 *
3458 * Converts a boolean to its string value.
3459 *
3460 * Returns a newly allocated string.
3461 */
3462xmlChar *
3463xmlXPathCastBooleanToString (int val) {
3464    xmlChar *ret;
3465    if (val)
3466	ret = xmlStrdup((const xmlChar *) "true");
3467    else
3468	ret = xmlStrdup((const xmlChar *) "false");
3469    return(ret);
3470}
3471
3472/**
3473 * xmlXPathCastNumberToString:
3474 * @val:  a number
3475 *
3476 * Converts a number to its string value.
3477 *
3478 * Returns a newly allocated string.
3479 */
3480xmlChar *
3481xmlXPathCastNumberToString (double val) {
3482    xmlChar *ret;
3483    switch (xmlXPathIsInf(val)) {
3484    case 1:
3485	ret = xmlStrdup((const xmlChar *) "Infinity");
3486	break;
3487    case -1:
3488	ret = xmlStrdup((const xmlChar *) "-Infinity");
3489	break;
3490    default:
3491	if (xmlXPathIsNaN(val)) {
3492	    ret = xmlStrdup((const xmlChar *) "NaN");
3493	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
3494	    ret = xmlStrdup((const xmlChar *) "0");
3495	} else {
3496	    /* could be improved */
3497	    char buf[100];
3498	    xmlXPathFormatNumber(val, buf, 100);
3499	    ret = xmlStrdup((const xmlChar *) buf);
3500	}
3501    }
3502    return(ret);
3503}
3504
3505/**
3506 * xmlXPathCastNodeToString:
3507 * @node:  a node
3508 *
3509 * Converts a node to its string value.
3510 *
3511 * Returns a newly allocated string.
3512 */
3513xmlChar *
3514xmlXPathCastNodeToString (xmlNodePtr node) {
3515    return(xmlNodeGetContent(node));
3516}
3517
3518/**
3519 * xmlXPathCastNodeSetToString:
3520 * @ns:  a node-set
3521 *
3522 * Converts a node-set to its string value.
3523 *
3524 * Returns a newly allocated string.
3525 */
3526xmlChar *
3527xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3528    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3529	return(xmlStrdup((const xmlChar *) ""));
3530
3531    xmlXPathNodeSetSort(ns);
3532    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3533}
3534
3535/**
3536 * xmlXPathCastToString:
3537 * @val:  an XPath object
3538 *
3539 * Converts an existing object to its string() equivalent
3540 *
3541 * Returns the string value of the object, NULL in case of error.
3542 *         A new string is allocated only if needed (@val isn't a
3543 *         string object).
3544 */
3545xmlChar *
3546xmlXPathCastToString(xmlXPathObjectPtr val) {
3547    xmlChar *ret = NULL;
3548
3549    if (val == NULL)
3550	return(xmlStrdup((const xmlChar *) ""));
3551    switch (val->type) {
3552	case XPATH_UNDEFINED:
3553#ifdef DEBUG_EXPR
3554	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3555#endif
3556	    ret = xmlStrdup((const xmlChar *) "");
3557	    break;
3558        case XPATH_NODESET:
3559        case XPATH_XSLT_TREE:
3560	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
3561	    break;
3562	case XPATH_STRING:
3563	    return(xmlStrdup(val->stringval));
3564        case XPATH_BOOLEAN:
3565	    ret = xmlXPathCastBooleanToString(val->boolval);
3566	    break;
3567	case XPATH_NUMBER: {
3568	    ret = xmlXPathCastNumberToString(val->floatval);
3569	    break;
3570	}
3571	case XPATH_USERS:
3572	case XPATH_POINT:
3573	case XPATH_RANGE:
3574	case XPATH_LOCATIONSET:
3575	    TODO
3576	    ret = xmlStrdup((const xmlChar *) "");
3577	    break;
3578    }
3579    return(ret);
3580}
3581
3582/**
3583 * xmlXPathConvertString:
3584 * @val:  an XPath object
3585 *
3586 * Converts an existing object to its string() equivalent
3587 *
3588 * Returns the new object, the old one is freed (or the operation
3589 *         is done directly on @val)
3590 */
3591xmlXPathObjectPtr
3592xmlXPathConvertString(xmlXPathObjectPtr val) {
3593    xmlChar *res = NULL;
3594
3595    if (val == NULL)
3596	return(xmlXPathNewCString(""));
3597
3598    switch (val->type) {
3599    case XPATH_UNDEFINED:
3600#ifdef DEBUG_EXPR
3601	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3602#endif
3603	break;
3604    case XPATH_NODESET:
3605    case XPATH_XSLT_TREE:
3606	res = xmlXPathCastNodeSetToString(val->nodesetval);
3607	break;
3608    case XPATH_STRING:
3609	return(val);
3610    case XPATH_BOOLEAN:
3611	res = xmlXPathCastBooleanToString(val->boolval);
3612	break;
3613    case XPATH_NUMBER:
3614	res = xmlXPathCastNumberToString(val->floatval);
3615	break;
3616    case XPATH_USERS:
3617    case XPATH_POINT:
3618    case XPATH_RANGE:
3619    case XPATH_LOCATIONSET:
3620	TODO;
3621	break;
3622    }
3623    xmlXPathFreeObject(val);
3624    if (res == NULL)
3625	return(xmlXPathNewCString(""));
3626    return(xmlXPathWrapString(res));
3627}
3628
3629/**
3630 * xmlXPathCastBooleanToNumber:
3631 * @val:  a boolean
3632 *
3633 * Converts a boolean to its number value
3634 *
3635 * Returns the number value
3636 */
3637double
3638xmlXPathCastBooleanToNumber(int val) {
3639    if (val)
3640	return(1.0);
3641    return(0.0);
3642}
3643
3644/**
3645 * xmlXPathCastStringToNumber:
3646 * @val:  a string
3647 *
3648 * Converts a string to its number value
3649 *
3650 * Returns the number value
3651 */
3652double
3653xmlXPathCastStringToNumber(const xmlChar * val) {
3654    return(xmlXPathStringEvalNumber(val));
3655}
3656
3657/**
3658 * xmlXPathCastNodeToNumber:
3659 * @node:  a node
3660 *
3661 * Converts a node to its number value
3662 *
3663 * Returns the number value
3664 */
3665double
3666xmlXPathCastNodeToNumber (xmlNodePtr node) {
3667    xmlChar *strval;
3668    double ret;
3669
3670    if (node == NULL)
3671	return(xmlXPathNAN);
3672    strval = xmlXPathCastNodeToString(node);
3673    if (strval == NULL)
3674	return(xmlXPathNAN);
3675    ret = xmlXPathCastStringToNumber(strval);
3676    xmlFree(strval);
3677
3678    return(ret);
3679}
3680
3681/**
3682 * xmlXPathCastNodeSetToNumber:
3683 * @ns:  a node-set
3684 *
3685 * Converts a node-set to its number value
3686 *
3687 * Returns the number value
3688 */
3689double
3690xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3691    xmlChar *str;
3692    double ret;
3693
3694    if (ns == NULL)
3695	return(xmlXPathNAN);
3696    str = xmlXPathCastNodeSetToString(ns);
3697    ret = xmlXPathCastStringToNumber(str);
3698    xmlFree(str);
3699    return(ret);
3700}
3701
3702/**
3703 * xmlXPathCastToNumber:
3704 * @val:  an XPath object
3705 *
3706 * Converts an XPath object to its number value
3707 *
3708 * Returns the number value
3709 */
3710double
3711xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3712    double ret = 0.0;
3713
3714    if (val == NULL)
3715	return(xmlXPathNAN);
3716    switch (val->type) {
3717    case XPATH_UNDEFINED:
3718#ifdef DEGUB_EXPR
3719	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3720#endif
3721	ret = xmlXPathNAN;
3722	break;
3723    case XPATH_NODESET:
3724    case XPATH_XSLT_TREE:
3725	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3726	break;
3727    case XPATH_STRING:
3728	ret = xmlXPathCastStringToNumber(val->stringval);
3729	break;
3730    case XPATH_NUMBER:
3731	ret = val->floatval;
3732	break;
3733    case XPATH_BOOLEAN:
3734	ret = xmlXPathCastBooleanToNumber(val->boolval);
3735	break;
3736    case XPATH_USERS:
3737    case XPATH_POINT:
3738    case XPATH_RANGE:
3739    case XPATH_LOCATIONSET:
3740	TODO;
3741	ret = xmlXPathNAN;
3742	break;
3743    }
3744    return(ret);
3745}
3746
3747/**
3748 * xmlXPathConvertNumber:
3749 * @val:  an XPath object
3750 *
3751 * Converts an existing object to its number() equivalent
3752 *
3753 * Returns the new object, the old one is freed (or the operation
3754 *         is done directly on @val)
3755 */
3756xmlXPathObjectPtr
3757xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3758    xmlXPathObjectPtr ret;
3759
3760    if (val == NULL)
3761	return(xmlXPathNewFloat(0.0));
3762    if (val->type == XPATH_NUMBER)
3763	return(val);
3764    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3765    xmlXPathFreeObject(val);
3766    return(ret);
3767}
3768
3769/**
3770 * xmlXPathCastNumberToBoolean:
3771 * @val:  a number
3772 *
3773 * Converts a number to its boolean value
3774 *
3775 * Returns the boolean value
3776 */
3777int
3778xmlXPathCastNumberToBoolean (double val) {
3779     if (xmlXPathIsNaN(val) || (val == 0.0))
3780	 return(0);
3781     return(1);
3782}
3783
3784/**
3785 * xmlXPathCastStringToBoolean:
3786 * @val:  a string
3787 *
3788 * Converts a string to its boolean value
3789 *
3790 * Returns the boolean value
3791 */
3792int
3793xmlXPathCastStringToBoolean (const xmlChar *val) {
3794    if ((val == NULL) || (xmlStrlen(val) == 0))
3795	return(0);
3796    return(1);
3797}
3798
3799/**
3800 * xmlXPathCastNodeSetToBoolean:
3801 * @ns:  a node-set
3802 *
3803 * Converts a node-set to its boolean value
3804 *
3805 * Returns the boolean value
3806 */
3807int
3808xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3809    if ((ns == NULL) || (ns->nodeNr == 0))
3810	return(0);
3811    return(1);
3812}
3813
3814/**
3815 * xmlXPathCastToBoolean:
3816 * @val:  an XPath object
3817 *
3818 * Converts an XPath object to its boolean value
3819 *
3820 * Returns the boolean value
3821 */
3822int
3823xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3824    int ret = 0;
3825
3826    if (val == NULL)
3827	return(0);
3828    switch (val->type) {
3829    case XPATH_UNDEFINED:
3830#ifdef DEBUG_EXPR
3831	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3832#endif
3833	ret = 0;
3834	break;
3835    case XPATH_NODESET:
3836    case XPATH_XSLT_TREE:
3837	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3838	break;
3839    case XPATH_STRING:
3840	ret = xmlXPathCastStringToBoolean(val->stringval);
3841	break;
3842    case XPATH_NUMBER:
3843	ret = xmlXPathCastNumberToBoolean(val->floatval);
3844	break;
3845    case XPATH_BOOLEAN:
3846	ret = val->boolval;
3847	break;
3848    case XPATH_USERS:
3849    case XPATH_POINT:
3850    case XPATH_RANGE:
3851    case XPATH_LOCATIONSET:
3852	TODO;
3853	ret = 0;
3854	break;
3855    }
3856    return(ret);
3857}
3858
3859
3860/**
3861 * xmlXPathConvertBoolean:
3862 * @val:  an XPath object
3863 *
3864 * Converts an existing object to its boolean() equivalent
3865 *
3866 * Returns the new object, the old one is freed (or the operation
3867 *         is done directly on @val)
3868 */
3869xmlXPathObjectPtr
3870xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3871    xmlXPathObjectPtr ret;
3872
3873    if (val == NULL)
3874	return(xmlXPathNewBoolean(0));
3875    if (val->type == XPATH_BOOLEAN)
3876	return(val);
3877    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3878    xmlXPathFreeObject(val);
3879    return(ret);
3880}
3881
3882/************************************************************************
3883 *									*
3884 *		Routines to handle XPath contexts			*
3885 *									*
3886 ************************************************************************/
3887
3888/**
3889 * xmlXPathNewContext:
3890 * @doc:  the XML document
3891 *
3892 * Create a new xmlXPathContext
3893 *
3894 * Returns the xmlXPathContext just allocated. The caller will need to free it.
3895 */
3896xmlXPathContextPtr
3897xmlXPathNewContext(xmlDocPtr doc) {
3898    xmlXPathContextPtr ret;
3899
3900    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3901    if (ret == NULL) {
3902        xmlXPathErrMemory(NULL, "creating context\n");
3903	return(NULL);
3904    }
3905    memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3906    ret->doc = doc;
3907    ret->node = NULL;
3908
3909    ret->varHash = NULL;
3910
3911    ret->nb_types = 0;
3912    ret->max_types = 0;
3913    ret->types = NULL;
3914
3915    ret->funcHash = xmlHashCreate(0);
3916
3917    ret->nb_axis = 0;
3918    ret->max_axis = 0;
3919    ret->axis = NULL;
3920
3921    ret->nsHash = NULL;
3922    ret->user = NULL;
3923
3924    ret->contextSize = -1;
3925    ret->proximityPosition = -1;
3926
3927    xmlXPathRegisterAllFunctions(ret);
3928
3929    return(ret);
3930}
3931
3932/**
3933 * xmlXPathFreeContext:
3934 * @ctxt:  the context to free
3935 *
3936 * Free up an xmlXPathContext
3937 */
3938void
3939xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3940    if (ctxt == NULL) return;
3941
3942    xmlXPathRegisteredNsCleanup(ctxt);
3943    xmlXPathRegisteredFuncsCleanup(ctxt);
3944    xmlXPathRegisteredVariablesCleanup(ctxt);
3945    xmlResetError(&ctxt->lastError);
3946    xmlFree(ctxt);
3947}
3948
3949/************************************************************************
3950 *									*
3951 *		Routines to handle XPath parser contexts		*
3952 *									*
3953 ************************************************************************/
3954
3955#define CHECK_CTXT(ctxt)						\
3956    if (ctxt == NULL) { 						\
3957	__xmlRaiseError(NULL, NULL, NULL,				\
3958		NULL, NULL, XML_FROM_XPATH,				\
3959		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
3960		__FILE__, __LINE__,					\
3961		NULL, NULL, NULL, 0, 0,					\
3962		"NULL context pointer\n");				\
3963	return(NULL);							\
3964    }									\
3965
3966
3967#define CHECK_CONTEXT(ctxt)						\
3968    if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
3969        (ctxt->doc->children == NULL)) { 				\
3970	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
3971	return(NULL);							\
3972    }
3973
3974
3975/**
3976 * xmlXPathNewParserContext:
3977 * @str:  the XPath expression
3978 * @ctxt:  the XPath context
3979 *
3980 * Create a new xmlXPathParserContext
3981 *
3982 * Returns the xmlXPathParserContext just allocated.
3983 */
3984xmlXPathParserContextPtr
3985xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3986    xmlXPathParserContextPtr ret;
3987
3988    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3989    if (ret == NULL) {
3990        xmlXPathErrMemory(ctxt, "creating parser context\n");
3991	return(NULL);
3992    }
3993    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3994    ret->cur = ret->base = str;
3995    ret->context = ctxt;
3996
3997    ret->comp = xmlXPathNewCompExpr();
3998    if (ret->comp == NULL) {
3999	xmlFree(ret->valueTab);
4000	xmlFree(ret);
4001	return(NULL);
4002    }
4003    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4004        ret->comp->dict = ctxt->dict;
4005	xmlDictReference(ret->comp->dict);
4006    }
4007
4008    return(ret);
4009}
4010
4011/**
4012 * xmlXPathCompParserContext:
4013 * @comp:  the XPath compiled expression
4014 * @ctxt:  the XPath context
4015 *
4016 * Create a new xmlXPathParserContext when processing a compiled expression
4017 *
4018 * Returns the xmlXPathParserContext just allocated.
4019 */
4020static xmlXPathParserContextPtr
4021xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4022    xmlXPathParserContextPtr ret;
4023
4024    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4025    if (ret == NULL) {
4026        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
4027	return(NULL);
4028    }
4029    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4030
4031    /* Allocate the value stack */
4032    ret->valueTab = (xmlXPathObjectPtr *)
4033                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
4034    if (ret->valueTab == NULL) {
4035	xmlFree(ret);
4036	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
4037	return(NULL);
4038    }
4039    ret->valueNr = 0;
4040    ret->valueMax = 10;
4041    ret->value = NULL;
4042
4043    ret->context = ctxt;
4044    ret->comp = comp;
4045
4046    return(ret);
4047}
4048
4049/**
4050 * xmlXPathFreeParserContext:
4051 * @ctxt:  the context to free
4052 *
4053 * Free up an xmlXPathParserContext
4054 */
4055void
4056xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4057    if (ctxt->valueTab != NULL) {
4058        xmlFree(ctxt->valueTab);
4059    }
4060    if (ctxt->comp != NULL) {
4061#ifdef XPATH_STREAMING
4062	if (ctxt->comp->stream != NULL) {
4063	    xmlFreePatternList(ctxt->comp->stream);
4064	    ctxt->comp->stream = NULL;
4065	}
4066#endif
4067	xmlXPathFreeCompExpr(ctxt->comp);
4068    }
4069    xmlFree(ctxt);
4070}
4071
4072/************************************************************************
4073 *									*
4074 *		The implicit core function library			*
4075 *									*
4076 ************************************************************************/
4077
4078/**
4079 * xmlXPathNodeValHash:
4080 * @node:  a node pointer
4081 *
4082 * Function computing the beginning of the string value of the node,
4083 * used to speed up comparisons
4084 *
4085 * Returns an int usable as a hash
4086 */
4087static unsigned int
4088xmlXPathNodeValHash(xmlNodePtr node) {
4089    int len = 2;
4090    const xmlChar * string = NULL;
4091    xmlNodePtr tmp = NULL;
4092    unsigned int ret = 0;
4093
4094    if (node == NULL)
4095	return(0);
4096
4097    if (node->type == XML_DOCUMENT_NODE) {
4098	tmp = xmlDocGetRootElement((xmlDocPtr) node);
4099	if (tmp == NULL)
4100	    node = node->children;
4101	else
4102	    node = tmp;
4103
4104	if (node == NULL)
4105	    return(0);
4106    }
4107
4108    switch (node->type) {
4109	case XML_COMMENT_NODE:
4110	case XML_PI_NODE:
4111	case XML_CDATA_SECTION_NODE:
4112	case XML_TEXT_NODE:
4113	    string = node->content;
4114	    if (string == NULL)
4115		return(0);
4116	    if (string[0] == 0)
4117		return(0);
4118	    return(((unsigned int) string[0]) +
4119		   (((unsigned int) string[1]) << 8));
4120	case XML_NAMESPACE_DECL:
4121	    string = ((xmlNsPtr)node)->href;
4122	    if (string == NULL)
4123		return(0);
4124	    if (string[0] == 0)
4125		return(0);
4126	    return(((unsigned int) string[0]) +
4127		   (((unsigned int) string[1]) << 8));
4128	case XML_ATTRIBUTE_NODE:
4129	    tmp = ((xmlAttrPtr) node)->children;
4130	    break;
4131	case XML_ELEMENT_NODE:
4132	    tmp = node->children;
4133	    break;
4134	default:
4135	    return(0);
4136    }
4137    while (tmp != NULL) {
4138	switch (tmp->type) {
4139	    case XML_COMMENT_NODE:
4140	    case XML_PI_NODE:
4141	    case XML_CDATA_SECTION_NODE:
4142	    case XML_TEXT_NODE:
4143		string = tmp->content;
4144		break;
4145	    case XML_NAMESPACE_DECL:
4146		string = ((xmlNsPtr)tmp)->href;
4147		break;
4148	    default:
4149		break;
4150	}
4151	if ((string != NULL) && (string[0] != 0)) {
4152	    if (len == 1) {
4153		return(ret + (((unsigned int) string[0]) << 8));
4154	    }
4155	    if (string[1] == 0) {
4156		len = 1;
4157		ret = (unsigned int) string[0];
4158	    } else {
4159		return(((unsigned int) string[0]) +
4160		       (((unsigned int) string[1]) << 8));
4161	    }
4162	}
4163	/*
4164	 * Skip to next node
4165	 */
4166	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4167	    if (tmp->children->type != XML_ENTITY_DECL) {
4168		tmp = tmp->children;
4169		continue;
4170	    }
4171	}
4172	if (tmp == node)
4173	    break;
4174
4175	if (tmp->next != NULL) {
4176	    tmp = tmp->next;
4177	    continue;
4178	}
4179
4180	do {
4181	    tmp = tmp->parent;
4182	    if (tmp == NULL)
4183		break;
4184	    if (tmp == node) {
4185		tmp = NULL;
4186		break;
4187	    }
4188	    if (tmp->next != NULL) {
4189		tmp = tmp->next;
4190		break;
4191	    }
4192	} while (tmp != NULL);
4193    }
4194    return(ret);
4195}
4196
4197/**
4198 * xmlXPathStringHash:
4199 * @string:  a string
4200 *
4201 * Function computing the beginning of the string value of the node,
4202 * used to speed up comparisons
4203 *
4204 * Returns an int usable as a hash
4205 */
4206static unsigned int
4207xmlXPathStringHash(const xmlChar * string) {
4208    if (string == NULL)
4209	return((unsigned int) 0);
4210    if (string[0] == 0)
4211	return(0);
4212    return(((unsigned int) string[0]) +
4213	   (((unsigned int) string[1]) << 8));
4214}
4215
4216/**
4217 * xmlXPathCompareNodeSetFloat:
4218 * @ctxt:  the XPath Parser context
4219 * @inf:  less than (1) or greater than (0)
4220 * @strict:  is the comparison strict
4221 * @arg:  the node set
4222 * @f:  the value
4223 *
4224 * Implement the compare operation between a nodeset and a number
4225 *     @ns < @val    (1, 1, ...
4226 *     @ns <= @val   (1, 0, ...
4227 *     @ns > @val    (0, 1, ...
4228 *     @ns >= @val   (0, 0, ...
4229 *
4230 * If one object to be compared is a node-set and the other is a number,
4231 * then the comparison will be true if and only if there is a node in the
4232 * node-set such that the result of performing the comparison on the number
4233 * to be compared and on the result of converting the string-value of that
4234 * node to a number using the number function is true.
4235 *
4236 * Returns 0 or 1 depending on the results of the test.
4237 */
4238static int
4239xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4240	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4241    int i, ret = 0;
4242    xmlNodeSetPtr ns;
4243    xmlChar *str2;
4244
4245    if ((f == NULL) || (arg == NULL) ||
4246	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4247	xmlXPathFreeObject(arg);
4248	xmlXPathFreeObject(f);
4249        return(0);
4250    }
4251    ns = arg->nodesetval;
4252    if (ns != NULL) {
4253	for (i = 0;i < ns->nodeNr;i++) {
4254	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4255	     if (str2 != NULL) {
4256		 valuePush(ctxt,
4257			   xmlXPathNewString(str2));
4258		 xmlFree(str2);
4259		 xmlXPathNumberFunction(ctxt, 1);
4260		 valuePush(ctxt, xmlXPathObjectCopy(f));
4261		 ret = xmlXPathCompareValues(ctxt, inf, strict);
4262		 if (ret)
4263		     break;
4264	     }
4265	}
4266    }
4267    xmlXPathFreeObject(arg);
4268    xmlXPathFreeObject(f);
4269    return(ret);
4270}
4271
4272/**
4273 * xmlXPathCompareNodeSetString:
4274 * @ctxt:  the XPath Parser context
4275 * @inf:  less than (1) or greater than (0)
4276 * @strict:  is the comparison strict
4277 * @arg:  the node set
4278 * @s:  the value
4279 *
4280 * Implement the compare operation between a nodeset and a string
4281 *     @ns < @val    (1, 1, ...
4282 *     @ns <= @val   (1, 0, ...
4283 *     @ns > @val    (0, 1, ...
4284 *     @ns >= @val   (0, 0, ...
4285 *
4286 * If one object to be compared is a node-set and the other is a string,
4287 * then the comparison will be true if and only if there is a node in
4288 * the node-set such that the result of performing the comparison on the
4289 * string-value of the node and the other string is true.
4290 *
4291 * Returns 0 or 1 depending on the results of the test.
4292 */
4293static int
4294xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4295	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4296    int i, ret = 0;
4297    xmlNodeSetPtr ns;
4298    xmlChar *str2;
4299
4300    if ((s == NULL) || (arg == NULL) ||
4301	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4302	xmlXPathFreeObject(arg);
4303	xmlXPathFreeObject(s);
4304        return(0);
4305    }
4306    ns = arg->nodesetval;
4307    if (ns != NULL) {
4308	for (i = 0;i < ns->nodeNr;i++) {
4309	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4310	     if (str2 != NULL) {
4311		 valuePush(ctxt,
4312			   xmlXPathNewString(str2));
4313		 xmlFree(str2);
4314		 valuePush(ctxt, xmlXPathObjectCopy(s));
4315		 ret = xmlXPathCompareValues(ctxt, inf, strict);
4316		 if (ret)
4317		     break;
4318	     }
4319	}
4320    }
4321    xmlXPathFreeObject(arg);
4322    xmlXPathFreeObject(s);
4323    return(ret);
4324}
4325
4326/**
4327 * xmlXPathCompareNodeSets:
4328 * @inf:  less than (1) or greater than (0)
4329 * @strict:  is the comparison strict
4330 * @arg1:  the first node set object
4331 * @arg2:  the second node set object
4332 *
4333 * Implement the compare operation on nodesets:
4334 *
4335 * If both objects to be compared are node-sets, then the comparison
4336 * will be true if and only if there is a node in the first node-set
4337 * and a node in the second node-set such that the result of performing
4338 * the comparison on the string-values of the two nodes is true.
4339 * ....
4340 * When neither object to be compared is a node-set and the operator
4341 * is <=, <, >= or >, then the objects are compared by converting both
4342 * objects to numbers and comparing the numbers according to IEEE 754.
4343 * ....
4344 * The number function converts its argument to a number as follows:
4345 *  - a string that consists of optional whitespace followed by an
4346 *    optional minus sign followed by a Number followed by whitespace
4347 *    is converted to the IEEE 754 number that is nearest (according
4348 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
4349 *    represented by the string; any other string is converted to NaN
4350 *
4351 * Conclusion all nodes need to be converted first to their string value
4352 * and then the comparison must be done when possible
4353 */
4354static int
4355xmlXPathCompareNodeSets(int inf, int strict,
4356	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4357    int i, j, init = 0;
4358    double val1;
4359    double *values2;
4360    int ret = 0;
4361    xmlNodeSetPtr ns1;
4362    xmlNodeSetPtr ns2;
4363
4364    if ((arg1 == NULL) ||
4365	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4366	xmlXPathFreeObject(arg2);
4367        return(0);
4368    }
4369    if ((arg2 == NULL) ||
4370	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4371	xmlXPathFreeObject(arg1);
4372	xmlXPathFreeObject(arg2);
4373        return(0);
4374    }
4375
4376    ns1 = arg1->nodesetval;
4377    ns2 = arg2->nodesetval;
4378
4379    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
4380	xmlXPathFreeObject(arg1);
4381	xmlXPathFreeObject(arg2);
4382	return(0);
4383    }
4384    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
4385	xmlXPathFreeObject(arg1);
4386	xmlXPathFreeObject(arg2);
4387	return(0);
4388    }
4389
4390    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4391    if (values2 == NULL) {
4392        xmlXPathErrMemory(NULL, "comparing nodesets\n");
4393	xmlXPathFreeObject(arg1);
4394	xmlXPathFreeObject(arg2);
4395	return(0);
4396    }
4397    for (i = 0;i < ns1->nodeNr;i++) {
4398	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
4399	if (xmlXPathIsNaN(val1))
4400	    continue;
4401	for (j = 0;j < ns2->nodeNr;j++) {
4402	    if (init == 0) {
4403		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
4404	    }
4405	    if (xmlXPathIsNaN(values2[j]))
4406		continue;
4407	    if (inf && strict)
4408		ret = (val1 < values2[j]);
4409	    else if (inf && !strict)
4410		ret = (val1 <= values2[j]);
4411	    else if (!inf && strict)
4412		ret = (val1 > values2[j]);
4413	    else if (!inf && !strict)
4414		ret = (val1 >= values2[j]);
4415	    if (ret)
4416		break;
4417	}
4418	if (ret)
4419	    break;
4420	init = 1;
4421    }
4422    xmlFree(values2);
4423    xmlXPathFreeObject(arg1);
4424    xmlXPathFreeObject(arg2);
4425    return(ret);
4426}
4427
4428/**
4429 * xmlXPathCompareNodeSetValue:
4430 * @ctxt:  the XPath Parser context
4431 * @inf:  less than (1) or greater than (0)
4432 * @strict:  is the comparison strict
4433 * @arg:  the node set
4434 * @val:  the value
4435 *
4436 * Implement the compare operation between a nodeset and a value
4437 *     @ns < @val    (1, 1, ...
4438 *     @ns <= @val   (1, 0, ...
4439 *     @ns > @val    (0, 1, ...
4440 *     @ns >= @val   (0, 0, ...
4441 *
4442 * If one object to be compared is a node-set and the other is a boolean,
4443 * then the comparison will be true if and only if the result of performing
4444 * the comparison on the boolean and on the result of converting
4445 * the node-set to a boolean using the boolean function is true.
4446 *
4447 * Returns 0 or 1 depending on the results of the test.
4448 */
4449static int
4450xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4451	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4452    if ((val == NULL) || (arg == NULL) ||
4453	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4454        return(0);
4455
4456    switch(val->type) {
4457        case XPATH_NUMBER:
4458	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4459        case XPATH_NODESET:
4460        case XPATH_XSLT_TREE:
4461	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
4462        case XPATH_STRING:
4463	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4464        case XPATH_BOOLEAN:
4465	    valuePush(ctxt, arg);
4466	    xmlXPathBooleanFunction(ctxt, 1);
4467	    valuePush(ctxt, val);
4468	    return(xmlXPathCompareValues(ctxt, inf, strict));
4469	default:
4470	    TODO
4471    }
4472    return(0);
4473}
4474
4475/**
4476 * xmlXPathEqualNodeSetString:
4477 * @arg:  the nodeset object argument
4478 * @str:  the string to compare to.
4479 * @neq:  flag to show whether for '=' (0) or '!=' (1)
4480 *
4481 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4482 * If one object to be compared is a node-set and the other is a string,
4483 * then the comparison will be true if and only if there is a node in
4484 * the node-set such that the result of performing the comparison on the
4485 * string-value of the node and the other string is true.
4486 *
4487 * Returns 0 or 1 depending on the results of the test.
4488 */
4489static int
4490xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
4491{
4492    int i;
4493    xmlNodeSetPtr ns;
4494    xmlChar *str2;
4495    unsigned int hash;
4496
4497    if ((str == NULL) || (arg == NULL) ||
4498        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4499        return (0);
4500    ns = arg->nodesetval;
4501    /*
4502     * A NULL nodeset compared with a string is always false
4503     * (since there is no node equal, and no node not equal)
4504     */
4505    if ((ns == NULL) || (ns->nodeNr <= 0) )
4506        return (0);
4507    hash = xmlXPathStringHash(str);
4508    for (i = 0; i < ns->nodeNr; i++) {
4509        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4510            str2 = xmlNodeGetContent(ns->nodeTab[i]);
4511            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4512                xmlFree(str2);
4513		if (neq)
4514		    continue;
4515                return (1);
4516	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4517		if (neq)
4518		    continue;
4519                return (1);
4520            } else if (neq) {
4521		if (str2 != NULL)
4522		    xmlFree(str2);
4523		return (1);
4524	    }
4525            if (str2 != NULL)
4526                xmlFree(str2);
4527        } else if (neq)
4528	    return (1);
4529    }
4530    return (0);
4531}
4532
4533/**
4534 * xmlXPathEqualNodeSetFloat:
4535 * @arg:  the nodeset object argument
4536 * @f:  the float to compare to
4537 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
4538 *
4539 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4540 * If one object to be compared is a node-set and the other is a number,
4541 * then the comparison will be true if and only if there is a node in
4542 * the node-set such that the result of performing the comparison on the
4543 * number to be compared and on the result of converting the string-value
4544 * of that node to a number using the number function is true.
4545 *
4546 * Returns 0 or 1 depending on the results of the test.
4547 */
4548static int
4549xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4550    xmlXPathObjectPtr arg, double f, int neq) {
4551  int i, ret=0;
4552  xmlNodeSetPtr ns;
4553  xmlChar *str2;
4554  xmlXPathObjectPtr val;
4555  double v;
4556
4557    if ((arg == NULL) ||
4558	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4559        return(0);
4560
4561    ns = arg->nodesetval;
4562    if (ns != NULL) {
4563	for (i=0;i<ns->nodeNr;i++) {
4564	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4565	    if (str2 != NULL) {
4566		valuePush(ctxt, xmlXPathNewString(str2));
4567		xmlFree(str2);
4568		xmlXPathNumberFunction(ctxt, 1);
4569		val = valuePop(ctxt);
4570		v = val->floatval;
4571		xmlXPathFreeObject(val);
4572		if (!xmlXPathIsNaN(v)) {
4573		    if ((!neq) && (v==f)) {
4574			ret = 1;
4575			break;
4576		    } else if ((neq) && (v!=f)) {
4577			ret = 1;
4578			break;
4579		    }
4580		}
4581	    }
4582	}
4583    }
4584
4585    return(ret);
4586}
4587
4588
4589/**
4590 * xmlXPathEqualNodeSets:
4591 * @arg1:  first nodeset object argument
4592 * @arg2:  second nodeset object argument
4593 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
4594 *
4595 * Implement the equal / not equal operation on XPath nodesets:
4596 * @arg1 == @arg2  or  @arg1 != @arg2
4597 * If both objects to be compared are node-sets, then the comparison
4598 * will be true if and only if there is a node in the first node-set and
4599 * a node in the second node-set such that the result of performing the
4600 * comparison on the string-values of the two nodes is true.
4601 *
4602 * (needless to say, this is a costly operation)
4603 *
4604 * Returns 0 or 1 depending on the results of the test.
4605 */
4606static int
4607xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
4608    int i, j;
4609    unsigned int *hashs1;
4610    unsigned int *hashs2;
4611    xmlChar **values1;
4612    xmlChar **values2;
4613    int ret = 0;
4614    xmlNodeSetPtr ns1;
4615    xmlNodeSetPtr ns2;
4616
4617    if ((arg1 == NULL) ||
4618	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4619        return(0);
4620    if ((arg2 == NULL) ||
4621	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4622        return(0);
4623
4624    ns1 = arg1->nodesetval;
4625    ns2 = arg2->nodesetval;
4626
4627    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
4628	return(0);
4629    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
4630	return(0);
4631
4632    /*
4633     * for equal, check if there is a node pertaining to both sets
4634     */
4635    if (neq == 0)
4636	for (i = 0;i < ns1->nodeNr;i++)
4637	    for (j = 0;j < ns2->nodeNr;j++)
4638		if (ns1->nodeTab[i] == ns2->nodeTab[j])
4639		    return(1);
4640
4641    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4642    if (values1 == NULL) {
4643        xmlXPathErrMemory(NULL, "comparing nodesets\n");
4644	return(0);
4645    }
4646    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4647    if (hashs1 == NULL) {
4648        xmlXPathErrMemory(NULL, "comparing nodesets\n");
4649	xmlFree(values1);
4650	return(0);
4651    }
4652    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4653    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4654    if (values2 == NULL) {
4655        xmlXPathErrMemory(NULL, "comparing nodesets\n");
4656	xmlFree(hashs1);
4657	xmlFree(values1);
4658	return(0);
4659    }
4660    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4661    if (hashs2 == NULL) {
4662        xmlXPathErrMemory(NULL, "comparing nodesets\n");
4663	xmlFree(hashs1);
4664	xmlFree(values1);
4665	xmlFree(values2);
4666	return(0);
4667    }
4668    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4669    for (i = 0;i < ns1->nodeNr;i++) {
4670	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
4671	for (j = 0;j < ns2->nodeNr;j++) {
4672	    if (i == 0)
4673		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4674	    if (hashs1[i] != hashs2[j]) {
4675		if (neq) {
4676		    ret = 1;
4677		    break;
4678		}
4679	    }
4680	    else {
4681		if (values1[i] == NULL)
4682		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4683		if (values2[j] == NULL)
4684		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4685		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
4686		if (ret)
4687		    break;
4688	    }
4689	}
4690	if (ret)
4691	    break;
4692    }
4693    for (i = 0;i < ns1->nodeNr;i++)
4694	if (values1[i] != NULL)
4695	    xmlFree(values1[i]);
4696    for (j = 0;j < ns2->nodeNr;j++)
4697	if (values2[j] != NULL)
4698	    xmlFree(values2[j]);
4699    xmlFree(values1);
4700    xmlFree(values2);
4701    xmlFree(hashs1);
4702    xmlFree(hashs2);
4703    return(ret);
4704}
4705
4706static int
4707xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4708  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4709    int ret = 0;
4710    /*
4711     *At this point we are assured neither arg1 nor arg2
4712     *is a nodeset, so we can just pick the appropriate routine.
4713     */
4714    switch (arg1->type) {
4715        case XPATH_UNDEFINED:
4716#ifdef DEBUG_EXPR
4717	    xmlGenericError(xmlGenericErrorContext,
4718		    "Equal: undefined\n");
4719#endif
4720	    break;
4721        case XPATH_BOOLEAN:
4722	    switch (arg2->type) {
4723	        case XPATH_UNDEFINED:
4724#ifdef DEBUG_EXPR
4725		    xmlGenericError(xmlGenericErrorContext,
4726			    "Equal: undefined\n");
4727#endif
4728		    break;
4729		case XPATH_BOOLEAN:
4730#ifdef DEBUG_EXPR
4731		    xmlGenericError(xmlGenericErrorContext,
4732			    "Equal: %d boolean %d \n",
4733			    arg1->boolval, arg2->boolval);
4734#endif
4735		    ret = (arg1->boolval == arg2->boolval);
4736		    break;
4737		case XPATH_NUMBER:
4738		    ret = (arg1->boolval ==
4739			   xmlXPathCastNumberToBoolean(arg2->floatval));
4740		    break;
4741		case XPATH_STRING:
4742		    if ((arg2->stringval == NULL) ||
4743			(arg2->stringval[0] == 0)) ret = 0;
4744		    else
4745			ret = 1;
4746		    ret = (arg1->boolval == ret);
4747		    break;
4748		case XPATH_USERS:
4749		case XPATH_POINT:
4750		case XPATH_RANGE:
4751		case XPATH_LOCATIONSET:
4752		    TODO
4753		    break;
4754		case XPATH_NODESET:
4755		case XPATH_XSLT_TREE:
4756		    break;
4757	    }
4758	    break;
4759        case XPATH_NUMBER:
4760	    switch (arg2->type) {
4761	        case XPATH_UNDEFINED:
4762#ifdef DEBUG_EXPR
4763		    xmlGenericError(xmlGenericErrorContext,
4764			    "Equal: undefined\n");
4765#endif
4766		    break;
4767		case XPATH_BOOLEAN:
4768		    ret = (arg2->boolval==
4769			   xmlXPathCastNumberToBoolean(arg1->floatval));
4770		    break;
4771		case XPATH_STRING:
4772		    valuePush(ctxt, arg2);
4773		    xmlXPathNumberFunction(ctxt, 1);
4774		    arg2 = valuePop(ctxt);
4775		    /* no break on purpose */
4776		case XPATH_NUMBER:
4777		    /* Hand check NaN and Infinity equalities */
4778		    if (xmlXPathIsNaN(arg1->floatval) ||
4779		    	    xmlXPathIsNaN(arg2->floatval)) {
4780		        ret = 0;
4781		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4782		        if (xmlXPathIsInf(arg2->floatval) == 1)
4783			    ret = 1;
4784			else
4785			    ret = 0;
4786		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4787			if (xmlXPathIsInf(arg2->floatval) == -1)
4788			    ret = 1;
4789			else
4790			    ret = 0;
4791		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4792			if (xmlXPathIsInf(arg1->floatval) == 1)
4793			    ret = 1;
4794			else
4795			    ret = 0;
4796		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4797			if (xmlXPathIsInf(arg1->floatval) == -1)
4798			    ret = 1;
4799			else
4800			    ret = 0;
4801		    } else {
4802		        ret = (arg1->floatval == arg2->floatval);
4803		    }
4804		    break;
4805		case XPATH_USERS:
4806		case XPATH_POINT:
4807		case XPATH_RANGE:
4808		case XPATH_LOCATIONSET:
4809		    TODO
4810		    break;
4811		case XPATH_NODESET:
4812		case XPATH_XSLT_TREE:
4813		    break;
4814	    }
4815	    break;
4816        case XPATH_STRING:
4817	    switch (arg2->type) {
4818	        case XPATH_UNDEFINED:
4819#ifdef DEBUG_EXPR
4820		    xmlGenericError(xmlGenericErrorContext,
4821			    "Equal: undefined\n");
4822#endif
4823		    break;
4824		case XPATH_BOOLEAN:
4825		    if ((arg1->stringval == NULL) ||
4826			(arg1->stringval[0] == 0)) ret = 0;
4827		    else
4828			ret = 1;
4829		    ret = (arg2->boolval == ret);
4830		    break;
4831		case XPATH_STRING:
4832		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4833		    break;
4834		case XPATH_NUMBER:
4835		    valuePush(ctxt, arg1);
4836		    xmlXPathNumberFunction(ctxt, 1);
4837		    arg1 = valuePop(ctxt);
4838		    /* Hand check NaN and Infinity equalities */
4839		    if (xmlXPathIsNaN(arg1->floatval) ||
4840		    	    xmlXPathIsNaN(arg2->floatval)) {
4841		        ret = 0;
4842		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4843			if (xmlXPathIsInf(arg2->floatval) == 1)
4844			    ret = 1;
4845			else
4846			    ret = 0;
4847		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4848			if (xmlXPathIsInf(arg2->floatval) == -1)
4849			    ret = 1;
4850			else
4851			    ret = 0;
4852		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4853			if (xmlXPathIsInf(arg1->floatval) == 1)
4854			    ret = 1;
4855			else
4856			    ret = 0;
4857		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4858			if (xmlXPathIsInf(arg1->floatval) == -1)
4859			    ret = 1;
4860			else
4861			    ret = 0;
4862		    } else {
4863		        ret = (arg1->floatval == arg2->floatval);
4864		    }
4865		    break;
4866		case XPATH_USERS:
4867		case XPATH_POINT:
4868		case XPATH_RANGE:
4869		case XPATH_LOCATIONSET:
4870		    TODO
4871		    break;
4872		case XPATH_NODESET:
4873		case XPATH_XSLT_TREE:
4874		    break;
4875	    }
4876	    break;
4877        case XPATH_USERS:
4878	case XPATH_POINT:
4879	case XPATH_RANGE:
4880	case XPATH_LOCATIONSET:
4881	    TODO
4882	    break;
4883	case XPATH_NODESET:
4884	case XPATH_XSLT_TREE:
4885	    break;
4886    }
4887    xmlXPathFreeObject(arg1);
4888    xmlXPathFreeObject(arg2);
4889    return(ret);
4890}
4891
4892/**
4893 * xmlXPathEqualValues:
4894 * @ctxt:  the XPath Parser context
4895 *
4896 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4897 *
4898 * Returns 0 or 1 depending on the results of the test.
4899 */
4900int
4901xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4902    xmlXPathObjectPtr arg1, arg2, argtmp;
4903    int ret = 0;
4904
4905    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
4906    arg2 = valuePop(ctxt);
4907    arg1 = valuePop(ctxt);
4908    if ((arg1 == NULL) || (arg2 == NULL)) {
4909	if (arg1 != NULL)
4910	    xmlXPathFreeObject(arg1);
4911	else
4912	    xmlXPathFreeObject(arg2);
4913	XP_ERROR0(XPATH_INVALID_OPERAND);
4914    }
4915
4916    if (arg1 == arg2) {
4917#ifdef DEBUG_EXPR
4918        xmlGenericError(xmlGenericErrorContext,
4919		"Equal: by pointer\n");
4920#endif
4921        return(1);
4922    }
4923
4924    /*
4925     *If either argument is a nodeset, it's a 'special case'
4926     */
4927    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4928      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4929	/*
4930	 *Hack it to assure arg1 is the nodeset
4931	 */
4932	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4933		argtmp = arg2;
4934		arg2 = arg1;
4935		arg1 = argtmp;
4936	}
4937	switch (arg2->type) {
4938	    case XPATH_UNDEFINED:
4939#ifdef DEBUG_EXPR
4940		xmlGenericError(xmlGenericErrorContext,
4941			"Equal: undefined\n");
4942#endif
4943		break;
4944	    case XPATH_NODESET:
4945	    case XPATH_XSLT_TREE:
4946		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4947		break;
4948	    case XPATH_BOOLEAN:
4949		if ((arg1->nodesetval == NULL) ||
4950		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
4951		else
4952		    ret = 1;
4953		ret = (ret == arg2->boolval);
4954		break;
4955	    case XPATH_NUMBER:
4956		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4957		break;
4958	    case XPATH_STRING:
4959		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4960		break;
4961	    case XPATH_USERS:
4962	    case XPATH_POINT:
4963	    case XPATH_RANGE:
4964	    case XPATH_LOCATIONSET:
4965		TODO
4966		break;
4967	}
4968	xmlXPathFreeObject(arg1);
4969	xmlXPathFreeObject(arg2);
4970	return(ret);
4971    }
4972
4973    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4974}
4975
4976/**
4977 * xmlXPathNotEqualValues:
4978 * @ctxt:  the XPath Parser context
4979 *
4980 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4981 *
4982 * Returns 0 or 1 depending on the results of the test.
4983 */
4984int
4985xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4986    xmlXPathObjectPtr arg1, arg2, argtmp;
4987    int ret = 0;
4988
4989    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
4990    arg2 = valuePop(ctxt);
4991    arg1 = valuePop(ctxt);
4992    if ((arg1 == NULL) || (arg2 == NULL)) {
4993	if (arg1 != NULL)
4994	    xmlXPathFreeObject(arg1);
4995	else
4996	    xmlXPathFreeObject(arg2);
4997	XP_ERROR0(XPATH_INVALID_OPERAND);
4998    }
4999
5000    if (arg1 == arg2) {
5001#ifdef DEBUG_EXPR
5002        xmlGenericError(xmlGenericErrorContext,
5003		"NotEqual: by pointer\n");
5004#endif
5005        return(0);
5006    }
5007
5008    /*
5009     *If either argument is a nodeset, it's a 'special case'
5010     */
5011    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5012      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5013	/*
5014	 *Hack it to assure arg1 is the nodeset
5015	 */
5016	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5017		argtmp = arg2;
5018		arg2 = arg1;
5019		arg1 = argtmp;
5020	}
5021	switch (arg2->type) {
5022	    case XPATH_UNDEFINED:
5023#ifdef DEBUG_EXPR
5024		xmlGenericError(xmlGenericErrorContext,
5025			"NotEqual: undefined\n");
5026#endif
5027		break;
5028	    case XPATH_NODESET:
5029	    case XPATH_XSLT_TREE:
5030		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
5031		break;
5032	    case XPATH_BOOLEAN:
5033		if ((arg1->nodesetval == NULL) ||
5034		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
5035		else
5036		    ret = 1;
5037		ret = (ret != arg2->boolval);
5038		break;
5039	    case XPATH_NUMBER:
5040		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5041		break;
5042	    case XPATH_STRING:
5043		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5044		break;
5045	    case XPATH_USERS:
5046	    case XPATH_POINT:
5047	    case XPATH_RANGE:
5048	    case XPATH_LOCATIONSET:
5049		TODO
5050		break;
5051	}
5052	xmlXPathFreeObject(arg1);
5053	xmlXPathFreeObject(arg2);
5054	return(ret);
5055    }
5056
5057    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5058}
5059
5060/**
5061 * xmlXPathCompareValues:
5062 * @ctxt:  the XPath Parser context
5063 * @inf:  less than (1) or greater than (0)
5064 * @strict:  is the comparison strict
5065 *
5066 * Implement the compare operation on XPath objects:
5067 *     @arg1 < @arg2    (1, 1, ...
5068 *     @arg1 <= @arg2   (1, 0, ...
5069 *     @arg1 > @arg2    (0, 1, ...
5070 *     @arg1 >= @arg2   (0, 0, ...
5071 *
5072 * When neither object to be compared is a node-set and the operator is
5073 * <=, <, >=, >, then the objects are compared by converted both objects
5074 * to numbers and comparing the numbers according to IEEE 754. The <
5075 * comparison will be true if and only if the first number is less than the
5076 * second number. The <= comparison will be true if and only if the first
5077 * number is less than or equal to the second number. The > comparison
5078 * will be true if and only if the first number is greater than the second
5079 * number. The >= comparison will be true if and only if the first number
5080 * is greater than or equal to the second number.
5081 *
5082 * Returns 1 if the comparison succeeded, 0 if it failed
5083 */
5084int
5085xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
5086    int ret = 0, arg1i = 0, arg2i = 0;
5087    xmlXPathObjectPtr arg1, arg2;
5088
5089    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5090    arg2 = valuePop(ctxt);
5091    arg1 = valuePop(ctxt);
5092    if ((arg1 == NULL) || (arg2 == NULL)) {
5093	if (arg1 != NULL)
5094	    xmlXPathFreeObject(arg1);
5095	else
5096	    xmlXPathFreeObject(arg2);
5097	XP_ERROR0(XPATH_INVALID_OPERAND);
5098    }
5099
5100    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5101      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5102	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5103	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
5104	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
5105	} else {
5106	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5107		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5108			                          arg1, arg2);
5109	    } else {
5110		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5111			                          arg2, arg1);
5112	    }
5113	}
5114	return(ret);
5115    }
5116
5117    if (arg1->type != XPATH_NUMBER) {
5118	valuePush(ctxt, arg1);
5119	xmlXPathNumberFunction(ctxt, 1);
5120	arg1 = valuePop(ctxt);
5121    }
5122    if (arg1->type != XPATH_NUMBER) {
5123	xmlXPathFreeObject(arg1);
5124	xmlXPathFreeObject(arg2);
5125	XP_ERROR0(XPATH_INVALID_OPERAND);
5126    }
5127    if (arg2->type != XPATH_NUMBER) {
5128	valuePush(ctxt, arg2);
5129	xmlXPathNumberFunction(ctxt, 1);
5130	arg2 = valuePop(ctxt);
5131    }
5132    if (arg2->type != XPATH_NUMBER) {
5133	xmlXPathFreeObject(arg1);
5134	xmlXPathFreeObject(arg2);
5135	XP_ERROR0(XPATH_INVALID_OPERAND);
5136    }
5137    /*
5138     * Add tests for infinity and nan
5139     * => feedback on 3.4 for Inf and NaN
5140     */
5141    /* Hand check NaN and Infinity comparisons */
5142    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
5143	ret=0;
5144    } else {
5145	arg1i=xmlXPathIsInf(arg1->floatval);
5146	arg2i=xmlXPathIsInf(arg2->floatval);
5147	if (inf && strict) {
5148	    if ((arg1i == -1 && arg2i != -1) ||
5149		(arg2i == 1 && arg1i != 1)) {
5150		ret = 1;
5151	    } else if (arg1i == 0 && arg2i == 0) {
5152		ret = (arg1->floatval < arg2->floatval);
5153	    } else {
5154		ret = 0;
5155	    }
5156	}
5157	else if (inf && !strict) {
5158	    if (arg1i == -1 || arg2i == 1) {
5159		ret = 1;
5160	    } else if (arg1i == 0 && arg2i == 0) {
5161		ret = (arg1->floatval <= arg2->floatval);
5162	    } else {
5163		ret = 0;
5164	    }
5165	}
5166	else if (!inf && strict) {
5167	    if ((arg1i == 1 && arg2i != 1) ||
5168		(arg2i == -1 && arg1i != -1)) {
5169		ret = 1;
5170	    } else if (arg1i == 0 && arg2i == 0) {
5171		ret = (arg1->floatval > arg2->floatval);
5172	    } else {
5173		ret = 0;
5174	    }
5175	}
5176	else if (!inf && !strict) {
5177	    if (arg1i == 1 || arg2i == -1) {
5178		ret = 1;
5179	    } else if (arg1i == 0 && arg2i == 0) {
5180		ret = (arg1->floatval >= arg2->floatval);
5181	    } else {
5182		ret = 0;
5183	    }
5184	}
5185    }
5186    xmlXPathFreeObject(arg1);
5187    xmlXPathFreeObject(arg2);
5188    return(ret);
5189}
5190
5191/**
5192 * xmlXPathValueFlipSign:
5193 * @ctxt:  the XPath Parser context
5194 *
5195 * Implement the unary - operation on an XPath object
5196 * The numeric operators convert their operands to numbers as if
5197 * by calling the number function.
5198 */
5199void
5200xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
5201    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
5202    CAST_TO_NUMBER;
5203    CHECK_TYPE(XPATH_NUMBER);
5204    if (xmlXPathIsNaN(ctxt->value->floatval))
5205        ctxt->value->floatval=xmlXPathNAN;
5206    else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5207        ctxt->value->floatval=xmlXPathNINF;
5208    else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5209        ctxt->value->floatval=xmlXPathPINF;
5210    else if (ctxt->value->floatval == 0) {
5211        if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5212	    ctxt->value->floatval = xmlXPathNZERO;
5213	else
5214	    ctxt->value->floatval = 0;
5215    }
5216    else
5217        ctxt->value->floatval = - ctxt->value->floatval;
5218}
5219
5220/**
5221 * xmlXPathAddValues:
5222 * @ctxt:  the XPath Parser context
5223 *
5224 * Implement the add operation on XPath objects:
5225 * The numeric operators convert their operands to numbers as if
5226 * by calling the number function.
5227 */
5228void
5229xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5230    xmlXPathObjectPtr arg;
5231    double val;
5232
5233    arg = valuePop(ctxt);
5234    if (arg == NULL)
5235	XP_ERROR(XPATH_INVALID_OPERAND);
5236    val = xmlXPathCastToNumber(arg);
5237    xmlXPathFreeObject(arg);
5238
5239    CAST_TO_NUMBER;
5240    CHECK_TYPE(XPATH_NUMBER);
5241    ctxt->value->floatval += val;
5242}
5243
5244/**
5245 * xmlXPathSubValues:
5246 * @ctxt:  the XPath Parser context
5247 *
5248 * Implement the subtraction operation on XPath objects:
5249 * The numeric operators convert their operands to numbers as if
5250 * by calling the number function.
5251 */
5252void
5253xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5254    xmlXPathObjectPtr arg;
5255    double val;
5256
5257    arg = valuePop(ctxt);
5258    if (arg == NULL)
5259	XP_ERROR(XPATH_INVALID_OPERAND);
5260    val = xmlXPathCastToNumber(arg);
5261    xmlXPathFreeObject(arg);
5262
5263    CAST_TO_NUMBER;
5264    CHECK_TYPE(XPATH_NUMBER);
5265    ctxt->value->floatval -= val;
5266}
5267
5268/**
5269 * xmlXPathMultValues:
5270 * @ctxt:  the XPath Parser context
5271 *
5272 * Implement the multiply operation on XPath objects:
5273 * The numeric operators convert their operands to numbers as if
5274 * by calling the number function.
5275 */
5276void
5277xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5278    xmlXPathObjectPtr arg;
5279    double val;
5280
5281    arg = valuePop(ctxt);
5282    if (arg == NULL)
5283	XP_ERROR(XPATH_INVALID_OPERAND);
5284    val = xmlXPathCastToNumber(arg);
5285    xmlXPathFreeObject(arg);
5286
5287    CAST_TO_NUMBER;
5288    CHECK_TYPE(XPATH_NUMBER);
5289    ctxt->value->floatval *= val;
5290}
5291
5292/**
5293 * xmlXPathDivValues:
5294 * @ctxt:  the XPath Parser context
5295 *
5296 * Implement the div operation on XPath objects @arg1 / @arg2:
5297 * The numeric operators convert their operands to numbers as if
5298 * by calling the number function.
5299 */
5300void
5301xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5302    xmlXPathObjectPtr arg;
5303    double val;
5304
5305    arg = valuePop(ctxt);
5306    if (arg == NULL)
5307	XP_ERROR(XPATH_INVALID_OPERAND);
5308    val = xmlXPathCastToNumber(arg);
5309    xmlXPathFreeObject(arg);
5310
5311    CAST_TO_NUMBER;
5312    CHECK_TYPE(XPATH_NUMBER);
5313    if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5314	ctxt->value->floatval = xmlXPathNAN;
5315    else if (val == 0 && xmlXPathGetSign(val) != 0) {
5316	if (ctxt->value->floatval == 0)
5317	    ctxt->value->floatval = xmlXPathNAN;
5318	else if (ctxt->value->floatval > 0)
5319	    ctxt->value->floatval = xmlXPathNINF;
5320	else if (ctxt->value->floatval < 0)
5321	    ctxt->value->floatval = xmlXPathPINF;
5322    }
5323    else if (val == 0) {
5324	if (ctxt->value->floatval == 0)
5325	    ctxt->value->floatval = xmlXPathNAN;
5326	else if (ctxt->value->floatval > 0)
5327	    ctxt->value->floatval = xmlXPathPINF;
5328	else if (ctxt->value->floatval < 0)
5329	    ctxt->value->floatval = xmlXPathNINF;
5330    } else
5331	ctxt->value->floatval /= val;
5332}
5333
5334/**
5335 * xmlXPathModValues:
5336 * @ctxt:  the XPath Parser context
5337 *
5338 * Implement the mod operation on XPath objects: @arg1 / @arg2
5339 * The numeric operators convert their operands to numbers as if
5340 * by calling the number function.
5341 */
5342void
5343xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5344    xmlXPathObjectPtr arg;
5345    double arg1, arg2;
5346
5347    arg = valuePop(ctxt);
5348    if (arg == NULL)
5349	XP_ERROR(XPATH_INVALID_OPERAND);
5350    arg2 = xmlXPathCastToNumber(arg);
5351    xmlXPathFreeObject(arg);
5352
5353    CAST_TO_NUMBER;
5354    CHECK_TYPE(XPATH_NUMBER);
5355    arg1 = ctxt->value->floatval;
5356    if (arg2 == 0)
5357	ctxt->value->floatval = xmlXPathNAN;
5358    else {
5359	ctxt->value->floatval = fmod(arg1, arg2);
5360    }
5361}
5362
5363/************************************************************************
5364 *									*
5365 *		The traversal functions					*
5366 *									*
5367 ************************************************************************/
5368
5369/*
5370 * A traversal function enumerates nodes along an axis.
5371 * Initially it must be called with NULL, and it indicates
5372 * termination on the axis by returning NULL.
5373 */
5374typedef xmlNodePtr (*xmlXPathTraversalFunction)
5375                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5376
5377/**
5378 * xmlXPathNextSelf:
5379 * @ctxt:  the XPath Parser context
5380 * @cur:  the current node in the traversal
5381 *
5382 * Traversal function for the "self" direction
5383 * The self axis contains just the context node itself
5384 *
5385 * Returns the next element following that axis
5386 */
5387xmlNodePtr
5388xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5389    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
5390    if (cur == NULL)
5391        return(ctxt->context->node);
5392    return(NULL);
5393}
5394
5395/**
5396 * xmlXPathNextChild:
5397 * @ctxt:  the XPath Parser context
5398 * @cur:  the current node in the traversal
5399 *
5400 * Traversal function for the "child" direction
5401 * The child axis contains the children of the context node in document order.
5402 *
5403 * Returns the next element following that axis
5404 */
5405xmlNodePtr
5406xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5407    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
5408    if (cur == NULL) {
5409	if (ctxt->context->node == NULL) return(NULL);
5410	switch (ctxt->context->node->type) {
5411            case XML_ELEMENT_NODE:
5412            case XML_TEXT_NODE:
5413            case XML_CDATA_SECTION_NODE:
5414            case XML_ENTITY_REF_NODE:
5415            case XML_ENTITY_NODE:
5416            case XML_PI_NODE:
5417            case XML_COMMENT_NODE:
5418            case XML_NOTATION_NODE:
5419            case XML_DTD_NODE:
5420		return(ctxt->context->node->children);
5421            case XML_DOCUMENT_NODE:
5422            case XML_DOCUMENT_TYPE_NODE:
5423            case XML_DOCUMENT_FRAG_NODE:
5424            case XML_HTML_DOCUMENT_NODE:
5425#ifdef LIBXML_DOCB_ENABLED
5426	    case XML_DOCB_DOCUMENT_NODE:
5427#endif
5428		return(((xmlDocPtr) ctxt->context->node)->children);
5429	    case XML_ELEMENT_DECL:
5430	    case XML_ATTRIBUTE_DECL:
5431	    case XML_ENTITY_DECL:
5432            case XML_ATTRIBUTE_NODE:
5433	    case XML_NAMESPACE_DECL:
5434	    case XML_XINCLUDE_START:
5435	    case XML_XINCLUDE_END:
5436		return(NULL);
5437	}
5438	return(NULL);
5439    }
5440    if ((cur->type == XML_DOCUMENT_NODE) ||
5441        (cur->type == XML_HTML_DOCUMENT_NODE))
5442	return(NULL);
5443    return(cur->next);
5444}
5445
5446/**
5447 * xmlXPathNextDescendant:
5448 * @ctxt:  the XPath Parser context
5449 * @cur:  the current node in the traversal
5450 *
5451 * Traversal function for the "descendant" direction
5452 * the descendant axis contains the descendants of the context node in document
5453 * order; a descendant is a child or a child of a child and so on.
5454 *
5455 * Returns the next element following that axis
5456 */
5457xmlNodePtr
5458xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5459    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
5460    if (cur == NULL) {
5461	if (ctxt->context->node == NULL)
5462	    return(NULL);
5463	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5464	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
5465	    return(NULL);
5466
5467        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5468	    return(ctxt->context->doc->children);
5469        return(ctxt->context->node->children);
5470    }
5471
5472    if (cur->children != NULL) {
5473	/*
5474	 * Do not descend on entities declarations
5475	 */
5476    	if (cur->children->type != XML_ENTITY_DECL) {
5477	    cur = cur->children;
5478	    /*
5479	     * Skip DTDs
5480	     */
5481	    if (cur->type != XML_DTD_NODE)
5482		return(cur);
5483	}
5484    }
5485
5486    if (cur == ctxt->context->node) return(NULL);
5487
5488    while (cur->next != NULL) {
5489	cur = cur->next;
5490	if ((cur->type != XML_ENTITY_DECL) &&
5491	    (cur->type != XML_DTD_NODE))
5492	    return(cur);
5493    }
5494
5495    do {
5496        cur = cur->parent;
5497	if (cur == NULL) return(NULL);
5498	if (cur == ctxt->context->node) return(NULL);
5499	if (cur->next != NULL) {
5500	    cur = cur->next;
5501	    return(cur);
5502	}
5503    } while (cur != NULL);
5504    return(cur);
5505}
5506
5507/**
5508 * xmlXPathNextDescendantOrSelf:
5509 * @ctxt:  the XPath Parser context
5510 * @cur:  the current node in the traversal
5511 *
5512 * Traversal function for the "descendant-or-self" direction
5513 * the descendant-or-self axis contains the context node and the descendants
5514 * of the context node in document order; thus the context node is the first
5515 * node on the axis, and the first child of the context node is the second node
5516 * on the axis
5517 *
5518 * Returns the next element following that axis
5519 */
5520xmlNodePtr
5521xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5522    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
5523    if (cur == NULL) {
5524	if (ctxt->context->node == NULL)
5525	    return(NULL);
5526	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5527	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
5528	    return(NULL);
5529        return(ctxt->context->node);
5530    }
5531
5532    return(xmlXPathNextDescendant(ctxt, cur));
5533}
5534
5535/**
5536 * xmlXPathNextParent:
5537 * @ctxt:  the XPath Parser context
5538 * @cur:  the current node in the traversal
5539 *
5540 * Traversal function for the "parent" direction
5541 * The parent axis contains the parent of the context node, if there is one.
5542 *
5543 * Returns the next element following that axis
5544 */
5545xmlNodePtr
5546xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5547    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
5548    /*
5549     * the parent of an attribute or namespace node is the element
5550     * to which the attribute or namespace node is attached
5551     * Namespace handling !!!
5552     */
5553    if (cur == NULL) {
5554	if (ctxt->context->node == NULL) return(NULL);
5555	switch (ctxt->context->node->type) {
5556            case XML_ELEMENT_NODE:
5557            case XML_TEXT_NODE:
5558            case XML_CDATA_SECTION_NODE:
5559            case XML_ENTITY_REF_NODE:
5560            case XML_ENTITY_NODE:
5561            case XML_PI_NODE:
5562            case XML_COMMENT_NODE:
5563            case XML_NOTATION_NODE:
5564            case XML_DTD_NODE:
5565	    case XML_ELEMENT_DECL:
5566	    case XML_ATTRIBUTE_DECL:
5567	    case XML_XINCLUDE_START:
5568	    case XML_XINCLUDE_END:
5569	    case XML_ENTITY_DECL:
5570		if (ctxt->context->node->parent == NULL)
5571		    return((xmlNodePtr) ctxt->context->doc);
5572		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
5573		    ((ctxt->context->node->parent->name[0] == ' ') ||
5574		     (xmlStrEqual(ctxt->context->node->parent->name,
5575				 BAD_CAST "fake node libxslt"))))
5576		    return(NULL);
5577		return(ctxt->context->node->parent);
5578            case XML_ATTRIBUTE_NODE: {
5579		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5580
5581		return(att->parent);
5582	    }
5583            case XML_DOCUMENT_NODE:
5584            case XML_DOCUMENT_TYPE_NODE:
5585            case XML_DOCUMENT_FRAG_NODE:
5586            case XML_HTML_DOCUMENT_NODE:
5587#ifdef LIBXML_DOCB_ENABLED
5588	    case XML_DOCB_DOCUMENT_NODE:
5589#endif
5590                return(NULL);
5591	    case XML_NAMESPACE_DECL: {
5592		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5593
5594		if ((ns->next != NULL) &&
5595		    (ns->next->type != XML_NAMESPACE_DECL))
5596		    return((xmlNodePtr) ns->next);
5597                return(NULL);
5598	    }
5599	}
5600    }
5601    return(NULL);
5602}
5603
5604/**
5605 * xmlXPathNextAncestor:
5606 * @ctxt:  the XPath Parser context
5607 * @cur:  the current node in the traversal
5608 *
5609 * Traversal function for the "ancestor" direction
5610 * the ancestor axis contains the ancestors of the context node; the ancestors
5611 * of the context node consist of the parent of context node and the parent's
5612 * parent and so on; the nodes are ordered in reverse document order; thus the
5613 * parent is the first node on the axis, and the parent's parent is the second
5614 * node on the axis
5615 *
5616 * Returns the next element following that axis
5617 */
5618xmlNodePtr
5619xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5620    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
5621    /*
5622     * the parent of an attribute or namespace node is the element
5623     * to which the attribute or namespace node is attached
5624     * !!!!!!!!!!!!!
5625     */
5626    if (cur == NULL) {
5627	if (ctxt->context->node == NULL) return(NULL);
5628	switch (ctxt->context->node->type) {
5629            case XML_ELEMENT_NODE:
5630            case XML_TEXT_NODE:
5631            case XML_CDATA_SECTION_NODE:
5632            case XML_ENTITY_REF_NODE:
5633            case XML_ENTITY_NODE:
5634            case XML_PI_NODE:
5635            case XML_COMMENT_NODE:
5636	    case XML_DTD_NODE:
5637	    case XML_ELEMENT_DECL:
5638	    case XML_ATTRIBUTE_DECL:
5639	    case XML_ENTITY_DECL:
5640            case XML_NOTATION_NODE:
5641	    case XML_XINCLUDE_START:
5642	    case XML_XINCLUDE_END:
5643		if (ctxt->context->node->parent == NULL)
5644		    return((xmlNodePtr) ctxt->context->doc);
5645		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
5646		    ((ctxt->context->node->parent->name[0] == ' ') ||
5647		     (xmlStrEqual(ctxt->context->node->parent->name,
5648				 BAD_CAST "fake node libxslt"))))
5649		    return(NULL);
5650		return(ctxt->context->node->parent);
5651            case XML_ATTRIBUTE_NODE: {
5652		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
5653
5654		return(tmp->parent);
5655	    }
5656            case XML_DOCUMENT_NODE:
5657            case XML_DOCUMENT_TYPE_NODE:
5658            case XML_DOCUMENT_FRAG_NODE:
5659            case XML_HTML_DOCUMENT_NODE:
5660#ifdef LIBXML_DOCB_ENABLED
5661	    case XML_DOCB_DOCUMENT_NODE:
5662#endif
5663                return(NULL);
5664	    case XML_NAMESPACE_DECL: {
5665		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5666
5667		if ((ns->next != NULL) &&
5668		    (ns->next->type != XML_NAMESPACE_DECL))
5669		    return((xmlNodePtr) ns->next);
5670		/* Bad, how did that namespace end up here ? */
5671                return(NULL);
5672	    }
5673	}
5674	return(NULL);
5675    }
5676    if (cur == ctxt->context->doc->children)
5677	return((xmlNodePtr) ctxt->context->doc);
5678    if (cur == (xmlNodePtr) ctxt->context->doc)
5679	return(NULL);
5680    switch (cur->type) {
5681	case XML_ELEMENT_NODE:
5682	case XML_TEXT_NODE:
5683	case XML_CDATA_SECTION_NODE:
5684	case XML_ENTITY_REF_NODE:
5685	case XML_ENTITY_NODE:
5686	case XML_PI_NODE:
5687	case XML_COMMENT_NODE:
5688	case XML_NOTATION_NODE:
5689	case XML_DTD_NODE:
5690        case XML_ELEMENT_DECL:
5691        case XML_ATTRIBUTE_DECL:
5692        case XML_ENTITY_DECL:
5693	case XML_XINCLUDE_START:
5694	case XML_XINCLUDE_END:
5695	    if (cur->parent == NULL)
5696		return(NULL);
5697	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
5698		((cur->parent->name[0] == ' ') ||
5699		 (xmlStrEqual(cur->parent->name,
5700			      BAD_CAST "fake node libxslt"))))
5701		return(NULL);
5702	    return(cur->parent);
5703	case XML_ATTRIBUTE_NODE: {
5704	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5705
5706	    return(att->parent);
5707	}
5708	case XML_NAMESPACE_DECL: {
5709	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5710
5711	    if ((ns->next != NULL) &&
5712	        (ns->next->type != XML_NAMESPACE_DECL))
5713	        return((xmlNodePtr) ns->next);
5714	    /* Bad, how did that namespace end up here ? */
5715            return(NULL);
5716	}
5717	case XML_DOCUMENT_NODE:
5718	case XML_DOCUMENT_TYPE_NODE:
5719	case XML_DOCUMENT_FRAG_NODE:
5720	case XML_HTML_DOCUMENT_NODE:
5721#ifdef LIBXML_DOCB_ENABLED
5722	case XML_DOCB_DOCUMENT_NODE:
5723#endif
5724	    return(NULL);
5725    }
5726    return(NULL);
5727}
5728
5729/**
5730 * xmlXPathNextAncestorOrSelf:
5731 * @ctxt:  the XPath Parser context
5732 * @cur:  the current node in the traversal
5733 *
5734 * Traversal function for the "ancestor-or-self" direction
5735 * he ancestor-or-self axis contains the context node and ancestors of
5736 * the context node in reverse document order; thus the context node is
5737 * the first node on the axis, and the context node's parent the second;
5738 * parent here is defined the same as with the parent axis.
5739 *
5740 * Returns the next element following that axis
5741 */
5742xmlNodePtr
5743xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5744    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
5745    if (cur == NULL)
5746        return(ctxt->context->node);
5747    return(xmlXPathNextAncestor(ctxt, cur));
5748}
5749
5750/**
5751 * xmlXPathNextFollowingSibling:
5752 * @ctxt:  the XPath Parser context
5753 * @cur:  the current node in the traversal
5754 *
5755 * Traversal function for the "following-sibling" direction
5756 * The following-sibling axis contains the following siblings of the context
5757 * node in document order.
5758 *
5759 * Returns the next element following that axis
5760 */
5761xmlNodePtr
5762xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5763    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
5764    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5765	(ctxt->context->node->type == XML_NAMESPACE_DECL))
5766	return(NULL);
5767    if (cur == (xmlNodePtr) ctxt->context->doc)
5768        return(NULL);
5769    if (cur == NULL)
5770        return(ctxt->context->node->next);
5771    return(cur->next);
5772}
5773
5774/**
5775 * xmlXPathNextPrecedingSibling:
5776 * @ctxt:  the XPath Parser context
5777 * @cur:  the current node in the traversal
5778 *
5779 * Traversal function for the "preceding-sibling" direction
5780 * The preceding-sibling axis contains the preceding siblings of the context
5781 * node in reverse document order; the first preceding sibling is first on the
5782 * axis; the sibling preceding that node is the second on the axis and so on.
5783 *
5784 * Returns the next element following that axis
5785 */
5786xmlNodePtr
5787xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5788    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
5789    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5790	(ctxt->context->node->type == XML_NAMESPACE_DECL))
5791	return(NULL);
5792    if (cur == (xmlNodePtr) ctxt->context->doc)
5793        return(NULL);
5794    if (cur == NULL)
5795        return(ctxt->context->node->prev);
5796    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5797	cur = cur->prev;
5798	if (cur == NULL)
5799	    return(ctxt->context->node->prev);
5800    }
5801    return(cur->prev);
5802}
5803
5804/**
5805 * xmlXPathNextFollowing:
5806 * @ctxt:  the XPath Parser context
5807 * @cur:  the current node in the traversal
5808 *
5809 * Traversal function for the "following" direction
5810 * The following axis contains all nodes in the same document as the context
5811 * node that are after the context node in document order, excluding any
5812 * descendants and excluding attribute nodes and namespace nodes; the nodes
5813 * are ordered in document order
5814 *
5815 * Returns the next element following that axis
5816 */
5817xmlNodePtr
5818xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5819    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
5820    if (cur != NULL && cur->children != NULL)
5821        return cur->children ;
5822    if (cur == NULL) cur = ctxt->context->node;
5823    if (cur == NULL) return(NULL) ; /* ERROR */
5824    if (cur->next != NULL) return(cur->next) ;
5825    do {
5826        cur = cur->parent;
5827        if (cur == NULL) return(NULL);
5828        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5829        if (cur->next != NULL) return(cur->next);
5830    } while (cur != NULL);
5831    return(cur);
5832}
5833
5834/*
5835 * xmlXPathIsAncestor:
5836 * @ancestor:  the ancestor node
5837 * @node:  the current node
5838 *
5839 * Check that @ancestor is a @node's ancestor
5840 *
5841 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5842 */
5843static int
5844xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5845    if ((ancestor == NULL) || (node == NULL)) return(0);
5846    /* nodes need to be in the same document */
5847    if (ancestor->doc != node->doc) return(0);
5848    /* avoid searching if ancestor or node is the root node */
5849    if (ancestor == (xmlNodePtr) node->doc) return(1);
5850    if (node == (xmlNodePtr) ancestor->doc) return(0);
5851    while (node->parent != NULL) {
5852        if (node->parent == ancestor)
5853            return(1);
5854	node = node->parent;
5855    }
5856    return(0);
5857}
5858
5859/**
5860 * xmlXPathNextPreceding:
5861 * @ctxt:  the XPath Parser context
5862 * @cur:  the current node in the traversal
5863 *
5864 * Traversal function for the "preceding" direction
5865 * the preceding axis contains all nodes in the same document as the context
5866 * node that are before the context node in document order, excluding any
5867 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5868 * ordered in reverse document order
5869 *
5870 * Returns the next element following that axis
5871 */
5872xmlNodePtr
5873xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5874{
5875    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
5876    if (cur == NULL)
5877        cur = ctxt->context->node;
5878    if (cur == NULL)
5879	return (NULL);
5880    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5881	cur = cur->prev;
5882    do {
5883        if (cur->prev != NULL) {
5884            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5885            return (cur);
5886        }
5887
5888        cur = cur->parent;
5889        if (cur == NULL)
5890            return (NULL);
5891        if (cur == ctxt->context->doc->children)
5892            return (NULL);
5893    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
5894    return (cur);
5895}
5896
5897/**
5898 * xmlXPathNextPrecedingInternal:
5899 * @ctxt:  the XPath Parser context
5900 * @cur:  the current node in the traversal
5901 *
5902 * Traversal function for the "preceding" direction
5903 * the preceding axis contains all nodes in the same document as the context
5904 * node that are before the context node in document order, excluding any
5905 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5906 * ordered in reverse document order
5907 * This is a faster implementation but internal only since it requires a
5908 * state kept in the parser context: ctxt->ancestor.
5909 *
5910 * Returns the next element following that axis
5911 */
5912static xmlNodePtr
5913xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5914                              xmlNodePtr cur)
5915{
5916    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
5917    if (cur == NULL) {
5918        cur = ctxt->context->node;
5919        if (cur == NULL)
5920            return (NULL);
5921	if (cur->type == XML_NAMESPACE_DECL)
5922	    cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
5923        ctxt->ancestor = cur->parent;
5924    }
5925    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5926	cur = cur->prev;
5927    while (cur->prev == NULL) {
5928        cur = cur->parent;
5929        if (cur == NULL)
5930            return (NULL);
5931        if (cur == ctxt->context->doc->children)
5932            return (NULL);
5933        if (cur != ctxt->ancestor)
5934            return (cur);
5935        ctxt->ancestor = cur->parent;
5936    }
5937    cur = cur->prev;
5938    while (cur->last != NULL)
5939        cur = cur->last;
5940    return (cur);
5941}
5942
5943/**
5944 * xmlXPathNextNamespace:
5945 * @ctxt:  the XPath Parser context
5946 * @cur:  the current attribute in the traversal
5947 *
5948 * Traversal function for the "namespace" direction
5949 * the namespace axis contains the namespace nodes of the context node;
5950 * the order of nodes on this axis is implementation-defined; the axis will
5951 * be empty unless the context node is an element
5952 *
5953 * We keep the XML namespace node at the end of the list.
5954 *
5955 * Returns the next element following that axis
5956 */
5957xmlNodePtr
5958xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5959    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
5960    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
5961    if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
5962        if (ctxt->context->tmpNsList != NULL)
5963	    xmlFree(ctxt->context->tmpNsList);
5964	ctxt->context->tmpNsList =
5965	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
5966	ctxt->context->tmpNsNr = 0;
5967	if (ctxt->context->tmpNsList != NULL) {
5968	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5969		ctxt->context->tmpNsNr++;
5970	    }
5971	}
5972	return((xmlNodePtr) xmlXPathXMLNamespace);
5973    }
5974    if (ctxt->context->tmpNsNr > 0) {
5975	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5976    } else {
5977	if (ctxt->context->tmpNsList != NULL)
5978	    xmlFree(ctxt->context->tmpNsList);
5979	ctxt->context->tmpNsList = NULL;
5980	return(NULL);
5981    }
5982}
5983
5984/**
5985 * xmlXPathNextAttribute:
5986 * @ctxt:  the XPath Parser context
5987 * @cur:  the current attribute in the traversal
5988 *
5989 * Traversal function for the "attribute" direction
5990 * TODO: support DTD inherited default attributes
5991 *
5992 * Returns the next element following that axis
5993 */
5994xmlNodePtr
5995xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5996    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
5997    if (ctxt->context->node == NULL)
5998	return(NULL);
5999    if (ctxt->context->node->type != XML_ELEMENT_NODE)
6000	return(NULL);
6001    if (cur == NULL) {
6002        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6003	    return(NULL);
6004        return((xmlNodePtr)ctxt->context->node->properties);
6005    }
6006    return((xmlNodePtr)cur->next);
6007}
6008
6009/************************************************************************
6010 *									*
6011 *		NodeTest Functions					*
6012 *									*
6013 ************************************************************************/
6014
6015#define IS_FUNCTION			200
6016
6017
6018/************************************************************************
6019 *									*
6020 *		Implicit tree core function library			*
6021 *									*
6022 ************************************************************************/
6023
6024/**
6025 * xmlXPathRoot:
6026 * @ctxt:  the XPath Parser context
6027 *
6028 * Initialize the context to the root of the document
6029 */
6030void
6031xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
6032    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
6033    ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
6034    valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6035}
6036
6037/************************************************************************
6038 *									*
6039 *		The explicit core function library			*
6040 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
6041 *									*
6042 ************************************************************************/
6043
6044
6045/**
6046 * xmlXPathLastFunction:
6047 * @ctxt:  the XPath Parser context
6048 * @nargs:  the number of arguments
6049 *
6050 * Implement the last() XPath function
6051 *    number last()
6052 * The last function returns the number of nodes in the context node list.
6053 */
6054void
6055xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6056    CHECK_ARITY(0);
6057    if (ctxt->context->contextSize >= 0) {
6058	valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
6059#ifdef DEBUG_EXPR
6060	xmlGenericError(xmlGenericErrorContext,
6061		"last() : %d\n", ctxt->context->contextSize);
6062#endif
6063    } else {
6064	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6065    }
6066}
6067
6068/**
6069 * xmlXPathPositionFunction:
6070 * @ctxt:  the XPath Parser context
6071 * @nargs:  the number of arguments
6072 *
6073 * Implement the position() XPath function
6074 *    number position()
6075 * The position function returns the position of the context node in the
6076 * context node list. The first position is 1, and so the last position
6077 * will be equal to last().
6078 */
6079void
6080xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6081    CHECK_ARITY(0);
6082    if (ctxt->context->proximityPosition >= 0) {
6083	valuePush(ctxt,
6084	      xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6085#ifdef DEBUG_EXPR
6086	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6087		ctxt->context->proximityPosition);
6088#endif
6089    } else {
6090	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6091    }
6092}
6093
6094/**
6095 * xmlXPathCountFunction:
6096 * @ctxt:  the XPath Parser context
6097 * @nargs:  the number of arguments
6098 *
6099 * Implement the count() XPath function
6100 *    number count(node-set)
6101 */
6102void
6103xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6104    xmlXPathObjectPtr cur;
6105
6106    CHECK_ARITY(1);
6107    if ((ctxt->value == NULL) ||
6108	((ctxt->value->type != XPATH_NODESET) &&
6109	 (ctxt->value->type != XPATH_XSLT_TREE)))
6110	XP_ERROR(XPATH_INVALID_TYPE);
6111    cur = valuePop(ctxt);
6112
6113    if ((cur == NULL) || (cur->nodesetval == NULL))
6114	valuePush(ctxt, xmlXPathNewFloat((double) 0));
6115    else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
6116	valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
6117    } else {
6118	if ((cur->nodesetval->nodeNr != 1) ||
6119	    (cur->nodesetval->nodeTab == NULL)) {
6120	    valuePush(ctxt, xmlXPathNewFloat((double) 0));
6121	} else {
6122	    xmlNodePtr tmp;
6123	    int i = 0;
6124
6125	    tmp = cur->nodesetval->nodeTab[0];
6126	    if (tmp != NULL) {
6127		tmp = tmp->children;
6128		while (tmp != NULL) {
6129		    tmp = tmp->next;
6130		    i++;
6131		}
6132	    }
6133	    valuePush(ctxt, xmlXPathNewFloat((double) i));
6134	}
6135    }
6136    xmlXPathFreeObject(cur);
6137}
6138
6139/**
6140 * xmlXPathGetElementsByIds:
6141 * @doc:  the document
6142 * @ids:  a whitespace separated list of IDs
6143 *
6144 * Selects elements by their unique ID.
6145 *
6146 * Returns a node-set of selected elements.
6147 */
6148static xmlNodeSetPtr
6149xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6150    xmlNodeSetPtr ret;
6151    const xmlChar *cur = ids;
6152    xmlChar *ID;
6153    xmlAttrPtr attr;
6154    xmlNodePtr elem = NULL;
6155
6156    if (ids == NULL) return(NULL);
6157
6158    ret = xmlXPathNodeSetCreate(NULL);
6159
6160    while (IS_BLANK_CH(*cur)) cur++;
6161    while (*cur != 0) {
6162	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
6163	    cur++;
6164
6165        ID = xmlStrndup(ids, cur - ids);
6166	if (ID != NULL) {
6167	    /*
6168	     * We used to check the fact that the value passed
6169	     * was an NCName, but this generated much troubles for
6170	     * me and Aleksey Sanin, people blatantly violated that
6171	     * constaint, like Visa3D spec.
6172	     * if (xmlValidateNCName(ID, 1) == 0)
6173	     */
6174	    attr = xmlGetID(doc, ID);
6175	    if (attr != NULL) {
6176		if (attr->type == XML_ATTRIBUTE_NODE)
6177		    elem = attr->parent;
6178		else if (attr->type == XML_ELEMENT_NODE)
6179		    elem = (xmlNodePtr) attr;
6180		else
6181		    elem = NULL;
6182		if (elem != NULL)
6183		    xmlXPathNodeSetAdd(ret, elem);
6184	    }
6185	    xmlFree(ID);
6186	}
6187
6188	while (IS_BLANK_CH(*cur)) cur++;
6189	ids = cur;
6190    }
6191    return(ret);
6192}
6193
6194/**
6195 * xmlXPathIdFunction:
6196 * @ctxt:  the XPath Parser context
6197 * @nargs:  the number of arguments
6198 *
6199 * Implement the id() XPath function
6200 *    node-set id(object)
6201 * The id function selects elements by their unique ID
6202 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6203 * then the result is the union of the result of applying id to the
6204 * string value of each of the nodes in the argument node-set. When the
6205 * argument to id is of any other type, the argument is converted to a
6206 * string as if by a call to the string function; the string is split
6207 * into a whitespace-separated list of tokens (whitespace is any sequence
6208 * of characters matching the production S); the result is a node-set
6209 * containing the elements in the same document as the context node that
6210 * have a unique ID equal to any of the tokens in the list.
6211 */
6212void
6213xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6214    xmlChar *tokens;
6215    xmlNodeSetPtr ret;
6216    xmlXPathObjectPtr obj;
6217
6218    CHECK_ARITY(1);
6219    obj = valuePop(ctxt);
6220    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
6221    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
6222	xmlNodeSetPtr ns;
6223	int i;
6224
6225	ret = xmlXPathNodeSetCreate(NULL);
6226
6227	if (obj->nodesetval != NULL) {
6228	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
6229		tokens =
6230		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6231		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6232		ret = xmlXPathNodeSetMerge(ret, ns);
6233		xmlXPathFreeNodeSet(ns);
6234		if (tokens != NULL)
6235		    xmlFree(tokens);
6236	    }
6237	}
6238
6239	xmlXPathFreeObject(obj);
6240	valuePush(ctxt, xmlXPathWrapNodeSet(ret));
6241	return;
6242    }
6243    obj = xmlXPathConvertString(obj);
6244
6245    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6246    valuePush(ctxt, xmlXPathWrapNodeSet(ret));
6247
6248    xmlXPathFreeObject(obj);
6249    return;
6250}
6251
6252/**
6253 * xmlXPathLocalNameFunction:
6254 * @ctxt:  the XPath Parser context
6255 * @nargs:  the number of arguments
6256 *
6257 * Implement the local-name() XPath function
6258 *    string local-name(node-set?)
6259 * The local-name function returns a string containing the local part
6260 * of the name of the node in the argument node-set that is first in
6261 * document order. If the node-set is empty or the first node has no
6262 * name, an empty string is returned. If the argument is omitted it
6263 * defaults to the context node.
6264 */
6265void
6266xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6267    xmlXPathObjectPtr cur;
6268
6269    if (ctxt == NULL) return;
6270
6271    if (nargs == 0) {
6272	valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6273	nargs = 1;
6274    }
6275
6276    CHECK_ARITY(1);
6277    if ((ctxt->value == NULL) ||
6278	((ctxt->value->type != XPATH_NODESET) &&
6279	 (ctxt->value->type != XPATH_XSLT_TREE)))
6280	XP_ERROR(XPATH_INVALID_TYPE);
6281    cur = valuePop(ctxt);
6282
6283    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
6284	valuePush(ctxt, xmlXPathNewCString(""));
6285    } else {
6286	int i = 0; /* Should be first in document order !!!!! */
6287	switch (cur->nodesetval->nodeTab[i]->type) {
6288	case XML_ELEMENT_NODE:
6289	case XML_ATTRIBUTE_NODE:
6290	case XML_PI_NODE:
6291	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6292		valuePush(ctxt, xmlXPathNewCString(""));
6293	    else
6294		valuePush(ctxt,
6295		      xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6296	    break;
6297	case XML_NAMESPACE_DECL:
6298	    valuePush(ctxt, xmlXPathNewString(
6299			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6300	    break;
6301	default:
6302	    valuePush(ctxt, xmlXPathNewCString(""));
6303	}
6304    }
6305    xmlXPathFreeObject(cur);
6306}
6307
6308/**
6309 * xmlXPathNamespaceURIFunction:
6310 * @ctxt:  the XPath Parser context
6311 * @nargs:  the number of arguments
6312 *
6313 * Implement the namespace-uri() XPath function
6314 *    string namespace-uri(node-set?)
6315 * The namespace-uri function returns a string containing the
6316 * namespace URI of the expanded name of the node in the argument
6317 * node-set that is first in document order. If the node-set is empty,
6318 * the first node has no name, or the expanded name has no namespace
6319 * URI, an empty string is returned. If the argument is omitted it
6320 * defaults to the context node.
6321 */
6322void
6323xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6324    xmlXPathObjectPtr cur;
6325
6326    if (ctxt == NULL) return;
6327
6328    if (nargs == 0) {
6329        valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6330	nargs = 1;
6331    }
6332    CHECK_ARITY(1);
6333    if ((ctxt->value == NULL) ||
6334	((ctxt->value->type != XPATH_NODESET) &&
6335	 (ctxt->value->type != XPATH_XSLT_TREE)))
6336	XP_ERROR(XPATH_INVALID_TYPE);
6337    cur = valuePop(ctxt);
6338
6339    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
6340	valuePush(ctxt, xmlXPathNewCString(""));
6341    } else {
6342	int i = 0; /* Should be first in document order !!!!! */
6343	switch (cur->nodesetval->nodeTab[i]->type) {
6344	case XML_ELEMENT_NODE:
6345	case XML_ATTRIBUTE_NODE:
6346	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
6347		valuePush(ctxt, xmlXPathNewCString(""));
6348	    else
6349		valuePush(ctxt, xmlXPathNewString(
6350			  cur->nodesetval->nodeTab[i]->ns->href));
6351	    break;
6352	default:
6353	    valuePush(ctxt, xmlXPathNewCString(""));
6354	}
6355    }
6356    xmlXPathFreeObject(cur);
6357}
6358
6359/**
6360 * xmlXPathNameFunction:
6361 * @ctxt:  the XPath Parser context
6362 * @nargs:  the number of arguments
6363 *
6364 * Implement the name() XPath function
6365 *    string name(node-set?)
6366 * The name function returns a string containing a QName representing
6367 * the name of the node in the argument node-set that is first in document
6368 * order. The QName must represent the name with respect to the namespace
6369 * declarations in effect on the node whose name is being represented.
6370 * Typically, this will be the form in which the name occurred in the XML
6371 * source. This need not be the case if there are namespace declarations
6372 * in effect on the node that associate multiple prefixes with the same
6373 * namespace. However, an implementation may include information about
6374 * the original prefix in its representation of nodes; in this case, an
6375 * implementation can ensure that the returned string is always the same
6376 * as the QName used in the XML source. If the argument it omitted it
6377 * defaults to the context node.
6378 * Libxml keep the original prefix so the "real qualified name" used is
6379 * returned.
6380 */
6381static void
6382xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6383{
6384    xmlXPathObjectPtr cur;
6385
6386    if (nargs == 0) {
6387        valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6388        nargs = 1;
6389    }
6390
6391    CHECK_ARITY(1);
6392    if ((ctxt->value == NULL) ||
6393        ((ctxt->value->type != XPATH_NODESET) &&
6394         (ctxt->value->type != XPATH_XSLT_TREE)))
6395        XP_ERROR(XPATH_INVALID_TYPE);
6396    cur = valuePop(ctxt);
6397
6398    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
6399        valuePush(ctxt, xmlXPathNewCString(""));
6400    } else {
6401        int i = 0;              /* Should be first in document order !!!!! */
6402
6403        switch (cur->nodesetval->nodeTab[i]->type) {
6404            case XML_ELEMENT_NODE:
6405            case XML_ATTRIBUTE_NODE:
6406		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6407		    valuePush(ctxt, xmlXPathNewCString(""));
6408		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6409                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
6410                    valuePush(ctxt,
6411		        xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6412
6413		} else {
6414		    xmlChar *fullname;
6415
6416		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6417				     cur->nodesetval->nodeTab[i]->ns->prefix,
6418				     NULL, 0);
6419		    if (fullname == cur->nodesetval->nodeTab[i]->name)
6420			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6421		    if (fullname == NULL) {
6422			XP_ERROR(XPATH_MEMORY_ERROR);
6423		    }
6424                    valuePush(ctxt, xmlXPathWrapString(fullname));
6425                }
6426                break;
6427            default:
6428                valuePush(ctxt,
6429                          xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6430                xmlXPathLocalNameFunction(ctxt, 1);
6431        }
6432    }
6433    xmlXPathFreeObject(cur);
6434}
6435
6436
6437/**
6438 * xmlXPathStringFunction:
6439 * @ctxt:  the XPath Parser context
6440 * @nargs:  the number of arguments
6441 *
6442 * Implement the string() XPath function
6443 *    string string(object?)
6444 * The string function converts an object to a string as follows:
6445 *    - A node-set is converted to a string by returning the value of
6446 *      the node in the node-set that is first in document order.
6447 *      If the node-set is empty, an empty string is returned.
6448 *    - A number is converted to a string as follows
6449 *      + NaN is converted to the string NaN
6450 *      + positive zero is converted to the string 0
6451 *      + negative zero is converted to the string 0
6452 *      + positive infinity is converted to the string Infinity
6453 *      + negative infinity is converted to the string -Infinity
6454 *      + if the number is an integer, the number is represented in
6455 *        decimal form as a Number with no decimal point and no leading
6456 *        zeros, preceded by a minus sign (-) if the number is negative
6457 *      + otherwise, the number is represented in decimal form as a
6458 *        Number including a decimal point with at least one digit
6459 *        before the decimal point and at least one digit after the
6460 *        decimal point, preceded by a minus sign (-) if the number
6461 *        is negative; there must be no leading zeros before the decimal
6462 *        point apart possibly from the one required digit immediately
6463 *        before the decimal point; beyond the one required digit
6464 *        after the decimal point there must be as many, but only as
6465 *        many, more digits as are needed to uniquely distinguish the
6466 *        number from all other IEEE 754 numeric values.
6467 *    - The boolean false value is converted to the string false.
6468 *      The boolean true value is converted to the string true.
6469 *
6470 * If the argument is omitted, it defaults to a node-set with the
6471 * context node as its only member.
6472 */
6473void
6474xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6475    xmlXPathObjectPtr cur;
6476
6477    if (ctxt == NULL) return;
6478    if (nargs == 0) {
6479	valuePush(ctxt,
6480		  xmlXPathWrapString(
6481			xmlXPathCastNodeToString(ctxt->context->node)));
6482	return;
6483    }
6484
6485    CHECK_ARITY(1);
6486    cur = valuePop(ctxt);
6487    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
6488    cur = xmlXPathConvertString(cur);
6489    valuePush(ctxt, cur);
6490}
6491
6492/**
6493 * xmlXPathStringLengthFunction:
6494 * @ctxt:  the XPath Parser context
6495 * @nargs:  the number of arguments
6496 *
6497 * Implement the string-length() XPath function
6498 *    number string-length(string?)
6499 * The string-length returns the number of characters in the string
6500 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6501 * the context node converted to a string, in other words the value
6502 * of the context node.
6503 */
6504void
6505xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6506    xmlXPathObjectPtr cur;
6507
6508    if (nargs == 0) {
6509        if ((ctxt == NULL) || (ctxt->context == NULL))
6510	    return;
6511	if (ctxt->context->node == NULL) {
6512	    valuePush(ctxt, xmlXPathNewFloat(0));
6513	} else {
6514	    xmlChar *content;
6515
6516	    content = xmlXPathCastNodeToString(ctxt->context->node);
6517	    valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
6518	    xmlFree(content);
6519	}
6520	return;
6521    }
6522    CHECK_ARITY(1);
6523    CAST_TO_STRING;
6524    CHECK_TYPE(XPATH_STRING);
6525    cur = valuePop(ctxt);
6526    valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
6527    xmlXPathFreeObject(cur);
6528}
6529
6530/**
6531 * xmlXPathConcatFunction:
6532 * @ctxt:  the XPath Parser context
6533 * @nargs:  the number of arguments
6534 *
6535 * Implement the concat() XPath function
6536 *    string concat(string, string, string*)
6537 * The concat function returns the concatenation of its arguments.
6538 */
6539void
6540xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6541    xmlXPathObjectPtr cur, newobj;
6542    xmlChar *tmp;
6543
6544    if (ctxt == NULL) return;
6545    if (nargs < 2) {
6546	CHECK_ARITY(2);
6547    }
6548
6549    CAST_TO_STRING;
6550    cur = valuePop(ctxt);
6551    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6552        xmlXPathFreeObject(cur);
6553	return;
6554    }
6555    nargs--;
6556
6557    while (nargs > 0) {
6558	CAST_TO_STRING;
6559	newobj = valuePop(ctxt);
6560	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6561	    xmlXPathFreeObject(newobj);
6562	    xmlXPathFreeObject(cur);
6563	    XP_ERROR(XPATH_INVALID_TYPE);
6564	}
6565	tmp = xmlStrcat(newobj->stringval, cur->stringval);
6566	newobj->stringval = cur->stringval;
6567	cur->stringval = tmp;
6568
6569	xmlXPathFreeObject(newobj);
6570	nargs--;
6571    }
6572    valuePush(ctxt, cur);
6573}
6574
6575/**
6576 * xmlXPathContainsFunction:
6577 * @ctxt:  the XPath Parser context
6578 * @nargs:  the number of arguments
6579 *
6580 * Implement the contains() XPath function
6581 *    boolean contains(string, string)
6582 * The contains function returns true if the first argument string
6583 * contains the second argument string, and otherwise returns false.
6584 */
6585void
6586xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6587    xmlXPathObjectPtr hay, needle;
6588
6589    CHECK_ARITY(2);
6590    CAST_TO_STRING;
6591    CHECK_TYPE(XPATH_STRING);
6592    needle = valuePop(ctxt);
6593    CAST_TO_STRING;
6594    hay = valuePop(ctxt);
6595    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6596        xmlXPathFreeObject(hay);
6597        xmlXPathFreeObject(needle);
6598	XP_ERROR(XPATH_INVALID_TYPE);
6599    }
6600    if (xmlStrstr(hay->stringval, needle->stringval))
6601        valuePush(ctxt, xmlXPathNewBoolean(1));
6602    else
6603        valuePush(ctxt, xmlXPathNewBoolean(0));
6604    xmlXPathFreeObject(hay);
6605    xmlXPathFreeObject(needle);
6606}
6607
6608/**
6609 * xmlXPathStartsWithFunction:
6610 * @ctxt:  the XPath Parser context
6611 * @nargs:  the number of arguments
6612 *
6613 * Implement the starts-with() XPath function
6614 *    boolean starts-with(string, string)
6615 * The starts-with function returns true if the first argument string
6616 * starts with the second argument string, and otherwise returns false.
6617 */
6618void
6619xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6620    xmlXPathObjectPtr hay, needle;
6621    int n;
6622
6623    CHECK_ARITY(2);
6624    CAST_TO_STRING;
6625    CHECK_TYPE(XPATH_STRING);
6626    needle = valuePop(ctxt);
6627    CAST_TO_STRING;
6628    hay = valuePop(ctxt);
6629    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6630        xmlXPathFreeObject(hay);
6631        xmlXPathFreeObject(needle);
6632	XP_ERROR(XPATH_INVALID_TYPE);
6633    }
6634    n = xmlStrlen(needle->stringval);
6635    if (xmlStrncmp(hay->stringval, needle->stringval, n))
6636        valuePush(ctxt, xmlXPathNewBoolean(0));
6637    else
6638        valuePush(ctxt, xmlXPathNewBoolean(1));
6639    xmlXPathFreeObject(hay);
6640    xmlXPathFreeObject(needle);
6641}
6642
6643/**
6644 * xmlXPathSubstringFunction:
6645 * @ctxt:  the XPath Parser context
6646 * @nargs:  the number of arguments
6647 *
6648 * Implement the substring() XPath function
6649 *    string substring(string, number, number?)
6650 * The substring function returns the substring of the first argument
6651 * starting at the position specified in the second argument with
6652 * length specified in the third argument. For example,
6653 * substring("12345",2,3) returns "234". If the third argument is not
6654 * specified, it returns the substring starting at the position specified
6655 * in the second argument and continuing to the end of the string. For
6656 * example, substring("12345",2) returns "2345".  More precisely, each
6657 * character in the string (see [3.6 Strings]) is considered to have a
6658 * numeric position: the position of the first character is 1, the position
6659 * of the second character is 2 and so on. The returned substring contains
6660 * those characters for which the position of the character is greater than
6661 * or equal to the second argument and, if the third argument is specified,
6662 * less than the sum of the second and third arguments; the comparisons
6663 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6664 *  - substring("12345", 1.5, 2.6) returns "234"
6665 *  - substring("12345", 0, 3) returns "12"
6666 *  - substring("12345", 0 div 0, 3) returns ""
6667 *  - substring("12345", 1, 0 div 0) returns ""
6668 *  - substring("12345", -42, 1 div 0) returns "12345"
6669 *  - substring("12345", -1 div 0, 1 div 0) returns ""
6670 */
6671void
6672xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6673    xmlXPathObjectPtr str, start, len;
6674    double le=0, in;
6675    int i, l, m;
6676    xmlChar *ret;
6677
6678    if (nargs < 2) {
6679	CHECK_ARITY(2);
6680    }
6681    if (nargs > 3) {
6682	CHECK_ARITY(3);
6683    }
6684    /*
6685     * take care of possible last (position) argument
6686    */
6687    if (nargs == 3) {
6688	CAST_TO_NUMBER;
6689	CHECK_TYPE(XPATH_NUMBER);
6690	len = valuePop(ctxt);
6691	le = len->floatval;
6692        xmlXPathFreeObject(len);
6693    }
6694
6695    CAST_TO_NUMBER;
6696    CHECK_TYPE(XPATH_NUMBER);
6697    start = valuePop(ctxt);
6698    in = start->floatval;
6699    xmlXPathFreeObject(start);
6700    CAST_TO_STRING;
6701    CHECK_TYPE(XPATH_STRING);
6702    str = valuePop(ctxt);
6703    m = xmlUTF8Strlen((const unsigned char *)str->stringval);
6704
6705    /*
6706     * If last pos not present, calculate last position
6707    */
6708    if (nargs != 3) {
6709	le = (double)m;
6710	if (in < 1.0)
6711	    in = 1.0;
6712    }
6713
6714    /* Need to check for the special cases where either
6715     * the index is NaN, the length is NaN, or both
6716     * arguments are infinity (relying on Inf + -Inf = NaN)
6717     */
6718    if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
6719        /*
6720         * To meet the requirements of the spec, the arguments
6721	 * must be converted to integer format before
6722	 * initial index calculations are done
6723         *
6724         * First we go to integer form, rounding up
6725	 * and checking for special cases
6726         */
6727        i = (int) in;
6728        if (((double)i)+0.5 <= in) i++;
6729
6730	if (xmlXPathIsInf(le) == 1) {
6731	    l = m;
6732	    if (i < 1)
6733		i = 1;
6734	}
6735	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6736	    l = 0;
6737	else {
6738	    l = (int) le;
6739	    if (((double)l)+0.5 <= le) l++;
6740	}
6741
6742	/* Now we normalize inidices */
6743        i -= 1;
6744        l += i;
6745        if (i < 0)
6746            i = 0;
6747        if (l > m)
6748            l = m;
6749
6750        /* number of chars to copy */
6751        l -= i;
6752
6753        ret = xmlUTF8Strsub(str->stringval, i, l);
6754    }
6755    else {
6756        ret = NULL;
6757    }
6758
6759    if (ret == NULL)
6760	valuePush(ctxt, xmlXPathNewCString(""));
6761    else {
6762	valuePush(ctxt, xmlXPathNewString(ret));
6763	xmlFree(ret);
6764    }
6765
6766    xmlXPathFreeObject(str);
6767}
6768
6769/**
6770 * xmlXPathSubstringBeforeFunction:
6771 * @ctxt:  the XPath Parser context
6772 * @nargs:  the number of arguments
6773 *
6774 * Implement the substring-before() XPath function
6775 *    string substring-before(string, string)
6776 * The substring-before function returns the substring of the first
6777 * argument string that precedes the first occurrence of the second
6778 * argument string in the first argument string, or the empty string
6779 * if the first argument string does not contain the second argument
6780 * string. For example, substring-before("1999/04/01","/") returns 1999.
6781 */
6782void
6783xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6784  xmlXPathObjectPtr str;
6785  xmlXPathObjectPtr find;
6786  xmlBufferPtr target;
6787  const xmlChar *point;
6788  int offset;
6789
6790  CHECK_ARITY(2);
6791  CAST_TO_STRING;
6792  find = valuePop(ctxt);
6793  CAST_TO_STRING;
6794  str = valuePop(ctxt);
6795
6796  target = xmlBufferCreate();
6797  if (target) {
6798    point = xmlStrstr(str->stringval, find->stringval);
6799    if (point) {
6800      offset = (int)(point - str->stringval);
6801      xmlBufferAdd(target, str->stringval, offset);
6802    }
6803    valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6804    xmlBufferFree(target);
6805  }
6806
6807  xmlXPathFreeObject(str);
6808  xmlXPathFreeObject(find);
6809}
6810
6811/**
6812 * xmlXPathSubstringAfterFunction:
6813 * @ctxt:  the XPath Parser context
6814 * @nargs:  the number of arguments
6815 *
6816 * Implement the substring-after() XPath function
6817 *    string substring-after(string, string)
6818 * The substring-after function returns the substring of the first
6819 * argument string that follows the first occurrence of the second
6820 * argument string in the first argument string, or the empty stringi
6821 * if the first argument string does not contain the second argument
6822 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6823 * and substring-after("1999/04/01","19") returns 99/04/01.
6824 */
6825void
6826xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6827  xmlXPathObjectPtr str;
6828  xmlXPathObjectPtr find;
6829  xmlBufferPtr target;
6830  const xmlChar *point;
6831  int offset;
6832
6833  CHECK_ARITY(2);
6834  CAST_TO_STRING;
6835  find = valuePop(ctxt);
6836  CAST_TO_STRING;
6837  str = valuePop(ctxt);
6838
6839  target = xmlBufferCreate();
6840  if (target) {
6841    point = xmlStrstr(str->stringval, find->stringval);
6842    if (point) {
6843      offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6844      xmlBufferAdd(target, &str->stringval[offset],
6845		   xmlStrlen(str->stringval) - offset);
6846    }
6847    valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6848    xmlBufferFree(target);
6849  }
6850
6851  xmlXPathFreeObject(str);
6852  xmlXPathFreeObject(find);
6853}
6854
6855/**
6856 * xmlXPathNormalizeFunction:
6857 * @ctxt:  the XPath Parser context
6858 * @nargs:  the number of arguments
6859 *
6860 * Implement the normalize-space() XPath function
6861 *    string normalize-space(string?)
6862 * The normalize-space function returns the argument string with white
6863 * space normalized by stripping leading and trailing whitespace
6864 * and replacing sequences of whitespace characters by a single
6865 * space. Whitespace characters are the same allowed by the S production
6866 * in XML. If the argument is omitted, it defaults to the context
6867 * node converted to a string, in other words the value of the context node.
6868 */
6869void
6870xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6871  xmlXPathObjectPtr obj = NULL;
6872  xmlChar *source = NULL;
6873  xmlBufferPtr target;
6874  xmlChar blank;
6875
6876  if (ctxt == NULL) return;
6877  if (nargs == 0) {
6878    /* Use current context node */
6879    valuePush(ctxt,
6880	      xmlXPathWrapString(
6881		  xmlXPathCastNodeToString(ctxt->context->node)));
6882    nargs = 1;
6883  }
6884
6885  CHECK_ARITY(1);
6886  CAST_TO_STRING;
6887  CHECK_TYPE(XPATH_STRING);
6888  obj = valuePop(ctxt);
6889  source = obj->stringval;
6890
6891  target = xmlBufferCreate();
6892  if (target && source) {
6893
6894    /* Skip leading whitespaces */
6895    while (IS_BLANK_CH(*source))
6896      source++;
6897
6898    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6899    blank = 0;
6900    while (*source) {
6901      if (IS_BLANK_CH(*source)) {
6902	blank = 0x20;
6903      } else {
6904	if (blank) {
6905	  xmlBufferAdd(target, &blank, 1);
6906	  blank = 0;
6907	}
6908	xmlBufferAdd(target, source, 1);
6909      }
6910      source++;
6911    }
6912
6913    valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6914    xmlBufferFree(target);
6915  }
6916  xmlXPathFreeObject(obj);
6917}
6918
6919/**
6920 * xmlXPathTranslateFunction:
6921 * @ctxt:  the XPath Parser context
6922 * @nargs:  the number of arguments
6923 *
6924 * Implement the translate() XPath function
6925 *    string translate(string, string, string)
6926 * The translate function returns the first argument string with
6927 * occurrences of characters in the second argument string replaced
6928 * by the character at the corresponding position in the third argument
6929 * string. For example, translate("bar","abc","ABC") returns the string
6930 * BAr. If there is a character in the second argument string with no
6931 * character at a corresponding position in the third argument string
6932 * (because the second argument string is longer than the third argument
6933 * string), then occurrences of that character in the first argument
6934 * string are removed. For example, translate("--aaa--","abc-","ABC")
6935 * returns "AAA". If a character occurs more than once in second
6936 * argument string, then the first occurrence determines the replacement
6937 * character. If the third argument string is longer than the second
6938 * argument string, then excess characters are ignored.
6939 */
6940void
6941xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6942    xmlXPathObjectPtr str;
6943    xmlXPathObjectPtr from;
6944    xmlXPathObjectPtr to;
6945    xmlBufferPtr target;
6946    int offset, max;
6947    xmlChar ch;
6948    const xmlChar *point;
6949    xmlChar *cptr;
6950
6951    CHECK_ARITY(3);
6952
6953    CAST_TO_STRING;
6954    to = valuePop(ctxt);
6955    CAST_TO_STRING;
6956    from = valuePop(ctxt);
6957    CAST_TO_STRING;
6958    str = valuePop(ctxt);
6959
6960    target = xmlBufferCreate();
6961    if (target) {
6962	max = xmlUTF8Strlen(to->stringval);
6963	for (cptr = str->stringval; (ch=*cptr); ) {
6964	    offset = xmlUTF8Strloc(from->stringval, cptr);
6965	    if (offset >= 0) {
6966		if (offset < max) {
6967		    point = xmlUTF8Strpos(to->stringval, offset);
6968		    if (point)
6969			xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6970		}
6971	    } else
6972		xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6973
6974	    /* Step to next character in input */
6975	    cptr++;
6976	    if ( ch & 0x80 ) {
6977		/* if not simple ascii, verify proper format */
6978		if ( (ch & 0xc0) != 0xc0 ) {
6979		    xmlGenericError(xmlGenericErrorContext,
6980			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
6981		    break;
6982		}
6983		/* then skip over remaining bytes for this char */
6984		while ( (ch <<= 1) & 0x80 )
6985		    if ( (*cptr++ & 0xc0) != 0x80 ) {
6986			xmlGenericError(xmlGenericErrorContext,
6987			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6988			break;
6989		    }
6990		if (ch & 0x80) /* must have had error encountered */
6991		    break;
6992	    }
6993	}
6994    }
6995    valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6996    xmlBufferFree(target);
6997    xmlXPathFreeObject(str);
6998    xmlXPathFreeObject(from);
6999    xmlXPathFreeObject(to);
7000}
7001
7002/**
7003 * xmlXPathBooleanFunction:
7004 * @ctxt:  the XPath Parser context
7005 * @nargs:  the number of arguments
7006 *
7007 * Implement the boolean() XPath function
7008 *    boolean boolean(object)
7009 * The boolean function converts its argument to a boolean as follows:
7010 *    - a number is true if and only if it is neither positive or
7011 *      negative zero nor NaN
7012 *    - a node-set is true if and only if it is non-empty
7013 *    - a string is true if and only if its length is non-zero
7014 */
7015void
7016xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7017    xmlXPathObjectPtr cur;
7018
7019    CHECK_ARITY(1);
7020    cur = valuePop(ctxt);
7021    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7022    cur = xmlXPathConvertBoolean(cur);
7023    valuePush(ctxt, cur);
7024}
7025
7026/**
7027 * xmlXPathNotFunction:
7028 * @ctxt:  the XPath Parser context
7029 * @nargs:  the number of arguments
7030 *
7031 * Implement the not() XPath function
7032 *    boolean not(boolean)
7033 * The not function returns true if its argument is false,
7034 * and false otherwise.
7035 */
7036void
7037xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7038    CHECK_ARITY(1);
7039    CAST_TO_BOOLEAN;
7040    CHECK_TYPE(XPATH_BOOLEAN);
7041    ctxt->value->boolval = ! ctxt->value->boolval;
7042}
7043
7044/**
7045 * xmlXPathTrueFunction:
7046 * @ctxt:  the XPath Parser context
7047 * @nargs:  the number of arguments
7048 *
7049 * Implement the true() XPath function
7050 *    boolean true()
7051 */
7052void
7053xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7054    CHECK_ARITY(0);
7055    valuePush(ctxt, xmlXPathNewBoolean(1));
7056}
7057
7058/**
7059 * xmlXPathFalseFunction:
7060 * @ctxt:  the XPath Parser context
7061 * @nargs:  the number of arguments
7062 *
7063 * Implement the false() XPath function
7064 *    boolean false()
7065 */
7066void
7067xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7068    CHECK_ARITY(0);
7069    valuePush(ctxt, xmlXPathNewBoolean(0));
7070}
7071
7072/**
7073 * xmlXPathLangFunction:
7074 * @ctxt:  the XPath Parser context
7075 * @nargs:  the number of arguments
7076 *
7077 * Implement the lang() XPath function
7078 *    boolean lang(string)
7079 * The lang function returns true or false depending on whether the
7080 * language of the context node as specified by xml:lang attributes
7081 * is the same as or is a sublanguage of the language specified by
7082 * the argument string. The language of the context node is determined
7083 * by the value of the xml:lang attribute on the context node, or, if
7084 * the context node has no xml:lang attribute, by the value of the
7085 * xml:lang attribute on the nearest ancestor of the context node that
7086 * has an xml:lang attribute. If there is no such attribute, then lang
7087 * returns false. If there is such an attribute, then lang returns
7088 * true if the attribute value is equal to the argument ignoring case,
7089 * or if there is some suffix starting with - such that the attribute
7090 * value is equal to the argument ignoring that suffix of the attribute
7091 * value and ignoring case.
7092 */
7093void
7094xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7095    xmlXPathObjectPtr val;
7096    const xmlChar *theLang;
7097    const xmlChar *lang;
7098    int ret = 0;
7099    int i;
7100
7101    CHECK_ARITY(1);
7102    CAST_TO_STRING;
7103    CHECK_TYPE(XPATH_STRING);
7104    val = valuePop(ctxt);
7105    lang = val->stringval;
7106    theLang = xmlNodeGetLang(ctxt->context->node);
7107    if ((theLang != NULL) && (lang != NULL)) {
7108        for (i = 0;lang[i] != 0;i++)
7109	    if (toupper(lang[i]) != toupper(theLang[i]))
7110	        goto not_equal;
7111        ret = 1;
7112    }
7113not_equal:
7114    xmlFree((void *)theLang);
7115    xmlXPathFreeObject(val);
7116    valuePush(ctxt, xmlXPathNewBoolean(ret));
7117}
7118
7119/**
7120 * xmlXPathNumberFunction:
7121 * @ctxt:  the XPath Parser context
7122 * @nargs:  the number of arguments
7123 *
7124 * Implement the number() XPath function
7125 *    number number(object?)
7126 */
7127void
7128xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7129    xmlXPathObjectPtr cur;
7130    double res;
7131
7132    if (ctxt == NULL) return;
7133    if (nargs == 0) {
7134	if (ctxt->context->node == NULL) {
7135	    valuePush(ctxt, xmlXPathNewFloat(0.0));
7136	} else {
7137	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7138
7139	    res = xmlXPathStringEvalNumber(content);
7140	    valuePush(ctxt, xmlXPathNewFloat(res));
7141	    xmlFree(content);
7142	}
7143	return;
7144    }
7145
7146    CHECK_ARITY(1);
7147    cur = valuePop(ctxt);
7148    cur = xmlXPathConvertNumber(cur);
7149    valuePush(ctxt, cur);
7150}
7151
7152/**
7153 * xmlXPathSumFunction:
7154 * @ctxt:  the XPath Parser context
7155 * @nargs:  the number of arguments
7156 *
7157 * Implement the sum() XPath function
7158 *    number sum(node-set)
7159 * The sum function returns the sum of the values of the nodes in
7160 * the argument node-set.
7161 */
7162void
7163xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7164    xmlXPathObjectPtr cur;
7165    int i;
7166    double res = 0.0;
7167
7168    CHECK_ARITY(1);
7169    if ((ctxt->value == NULL) ||
7170	((ctxt->value->type != XPATH_NODESET) &&
7171	 (ctxt->value->type != XPATH_XSLT_TREE)))
7172	XP_ERROR(XPATH_INVALID_TYPE);
7173    cur = valuePop(ctxt);
7174
7175    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
7176	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7177	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
7178	}
7179    }
7180    valuePush(ctxt, xmlXPathNewFloat(res));
7181    xmlXPathFreeObject(cur);
7182}
7183
7184/**
7185 * xmlXPathFloorFunction:
7186 * @ctxt:  the XPath Parser context
7187 * @nargs:  the number of arguments
7188 *
7189 * Implement the floor() XPath function
7190 *    number floor(number)
7191 * The floor function returns the largest (closest to positive infinity)
7192 * number that is not greater than the argument and that is an integer.
7193 */
7194void
7195xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7196    double f;
7197
7198    CHECK_ARITY(1);
7199    CAST_TO_NUMBER;
7200    CHECK_TYPE(XPATH_NUMBER);
7201
7202    f = (double)((int) ctxt->value->floatval);
7203    if (f != ctxt->value->floatval) {
7204	if (ctxt->value->floatval > 0)
7205	    ctxt->value->floatval = f;
7206	else
7207	    ctxt->value->floatval = f - 1;
7208    }
7209}
7210
7211/**
7212 * xmlXPathCeilingFunction:
7213 * @ctxt:  the XPath Parser context
7214 * @nargs:  the number of arguments
7215 *
7216 * Implement the ceiling() XPath function
7217 *    number ceiling(number)
7218 * The ceiling function returns the smallest (closest to negative infinity)
7219 * number that is not less than the argument and that is an integer.
7220 */
7221void
7222xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7223    double f;
7224
7225    CHECK_ARITY(1);
7226    CAST_TO_NUMBER;
7227    CHECK_TYPE(XPATH_NUMBER);
7228
7229#if 0
7230    ctxt->value->floatval = ceil(ctxt->value->floatval);
7231#else
7232    f = (double)((int) ctxt->value->floatval);
7233    if (f != ctxt->value->floatval) {
7234	if (ctxt->value->floatval > 0)
7235	    ctxt->value->floatval = f + 1;
7236	else {
7237	    if (ctxt->value->floatval < 0 && f == 0)
7238	        ctxt->value->floatval = xmlXPathNZERO;
7239	    else
7240	        ctxt->value->floatval = f;
7241	}
7242
7243    }
7244#endif
7245}
7246
7247/**
7248 * xmlXPathRoundFunction:
7249 * @ctxt:  the XPath Parser context
7250 * @nargs:  the number of arguments
7251 *
7252 * Implement the round() XPath function
7253 *    number round(number)
7254 * The round function returns the number that is closest to the
7255 * argument and that is an integer. If there are two such numbers,
7256 * then the one that is even is returned.
7257 */
7258void
7259xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7260    double f;
7261
7262    CHECK_ARITY(1);
7263    CAST_TO_NUMBER;
7264    CHECK_TYPE(XPATH_NUMBER);
7265
7266    if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7267	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7268	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
7269	(ctxt->value->floatval == 0.0))
7270	return;
7271
7272    f = (double)((int) ctxt->value->floatval);
7273    if (ctxt->value->floatval < 0) {
7274	if (ctxt->value->floatval < f - 0.5)
7275	    ctxt->value->floatval = f - 1;
7276	else
7277	    ctxt->value->floatval = f;
7278	if (ctxt->value->floatval == 0)
7279	    ctxt->value->floatval = xmlXPathNZERO;
7280    } else {
7281	if (ctxt->value->floatval < f + 0.5)
7282	    ctxt->value->floatval = f;
7283	else
7284	    ctxt->value->floatval = f + 1;
7285    }
7286}
7287
7288/************************************************************************
7289 *									*
7290 *			The Parser					*
7291 *									*
7292 ************************************************************************/
7293
7294/*
7295 * a few forward declarations since we use a recursive call based
7296 * implementation.
7297 */
7298static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
7299static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
7300static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
7301static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
7302static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7303	                                  int qualified);
7304
7305/**
7306 * xmlXPathCurrentChar:
7307 * @ctxt:  the XPath parser context
7308 * @cur:  pointer to the beginning of the char
7309 * @len:  pointer to the length of the char read
7310 *
7311 * The current char value, if using UTF-8 this may actually span multiple
7312 * bytes in the input buffer.
7313 *
7314 * Returns the current char value and its length
7315 */
7316
7317static int
7318xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7319    unsigned char c;
7320    unsigned int val;
7321    const xmlChar *cur;
7322
7323    if (ctxt == NULL)
7324	return(0);
7325    cur = ctxt->cur;
7326
7327    /*
7328     * We are supposed to handle UTF8, check it's valid
7329     * From rfc2044: encoding of the Unicode values on UTF-8:
7330     *
7331     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
7332     * 0000 0000-0000 007F   0xxxxxxx
7333     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
7334     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
7335     *
7336     * Check for the 0x110000 limit too
7337     */
7338    c = *cur;
7339    if (c & 0x80) {
7340	if ((cur[1] & 0xc0) != 0x80)
7341	    goto encoding_error;
7342	if ((c & 0xe0) == 0xe0) {
7343
7344	    if ((cur[2] & 0xc0) != 0x80)
7345		goto encoding_error;
7346	    if ((c & 0xf0) == 0xf0) {
7347		if (((c & 0xf8) != 0xf0) ||
7348		    ((cur[3] & 0xc0) != 0x80))
7349		    goto encoding_error;
7350		/* 4-byte code */
7351		*len = 4;
7352		val = (cur[0] & 0x7) << 18;
7353		val |= (cur[1] & 0x3f) << 12;
7354		val |= (cur[2] & 0x3f) << 6;
7355		val |= cur[3] & 0x3f;
7356	    } else {
7357	      /* 3-byte code */
7358		*len = 3;
7359		val = (cur[0] & 0xf) << 12;
7360		val |= (cur[1] & 0x3f) << 6;
7361		val |= cur[2] & 0x3f;
7362	    }
7363	} else {
7364	  /* 2-byte code */
7365	    *len = 2;
7366	    val = (cur[0] & 0x1f) << 6;
7367	    val |= cur[1] & 0x3f;
7368	}
7369	if (!IS_CHAR(val)) {
7370	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7371	}
7372	return(val);
7373    } else {
7374	/* 1-byte code */
7375	*len = 1;
7376	return((int) *cur);
7377    }
7378encoding_error:
7379    /*
7380     * If we detect an UTF8 error that probably means that the
7381     * input encoding didn't get properly advertised in the
7382     * declaration header. Report the error and switch the encoding
7383     * to ISO-Latin-1 (if you don't like this policy, just declare the
7384     * encoding !)
7385     */
7386    *len = 0;
7387    XP_ERROR0(XPATH_ENCODING_ERROR);
7388}
7389
7390/**
7391 * xmlXPathParseNCName:
7392 * @ctxt:  the XPath Parser context
7393 *
7394 * parse an XML namespace non qualified name.
7395 *
7396 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7397 *
7398 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7399 *                       CombiningChar | Extender
7400 *
7401 * Returns the namespace name or NULL
7402 */
7403
7404xmlChar *
7405xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
7406    const xmlChar *in;
7407    xmlChar *ret;
7408    int count = 0;
7409
7410    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
7411    /*
7412     * Accelerator for simple ASCII names
7413     */
7414    in = ctxt->cur;
7415    if (((*in >= 0x61) && (*in <= 0x7A)) ||
7416	((*in >= 0x41) && (*in <= 0x5A)) ||
7417	(*in == '_')) {
7418	in++;
7419	while (((*in >= 0x61) && (*in <= 0x7A)) ||
7420	       ((*in >= 0x41) && (*in <= 0x5A)) ||
7421	       ((*in >= 0x30) && (*in <= 0x39)) ||
7422	       (*in == '_') || (*in == '.') ||
7423	       (*in == '-'))
7424	    in++;
7425	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7426            (*in == '[') || (*in == ']') || (*in == ':') ||
7427            (*in == '@') || (*in == '*')) {
7428	    count = in - ctxt->cur;
7429	    if (count == 0)
7430		return(NULL);
7431	    ret = xmlStrndup(ctxt->cur, count);
7432	    ctxt->cur = in;
7433	    return(ret);
7434	}
7435    }
7436    return(xmlXPathParseNameComplex(ctxt, 0));
7437}
7438
7439
7440/**
7441 * xmlXPathParseQName:
7442 * @ctxt:  the XPath Parser context
7443 * @prefix:  a xmlChar **
7444 *
7445 * parse an XML qualified name
7446 *
7447 * [NS 5] QName ::= (Prefix ':')? LocalPart
7448 *
7449 * [NS 6] Prefix ::= NCName
7450 *
7451 * [NS 7] LocalPart ::= NCName
7452 *
7453 * Returns the function returns the local part, and prefix is updated
7454 *   to get the Prefix if any.
7455 */
7456
7457static xmlChar *
7458xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7459    xmlChar *ret = NULL;
7460
7461    *prefix = NULL;
7462    ret = xmlXPathParseNCName(ctxt);
7463    if (CUR == ':') {
7464        *prefix = ret;
7465	NEXT;
7466	ret = xmlXPathParseNCName(ctxt);
7467    }
7468    return(ret);
7469}
7470
7471/**
7472 * xmlXPathParseName:
7473 * @ctxt:  the XPath Parser context
7474 *
7475 * parse an XML name
7476 *
7477 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7478 *                  CombiningChar | Extender
7479 *
7480 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7481 *
7482 * Returns the namespace name or NULL
7483 */
7484
7485xmlChar *
7486xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
7487    const xmlChar *in;
7488    xmlChar *ret;
7489    int count = 0;
7490
7491    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
7492    /*
7493     * Accelerator for simple ASCII names
7494     */
7495    in = ctxt->cur;
7496    if (((*in >= 0x61) && (*in <= 0x7A)) ||
7497	((*in >= 0x41) && (*in <= 0x5A)) ||
7498	(*in == '_') || (*in == ':')) {
7499	in++;
7500	while (((*in >= 0x61) && (*in <= 0x7A)) ||
7501	       ((*in >= 0x41) && (*in <= 0x5A)) ||
7502	       ((*in >= 0x30) && (*in <= 0x39)) ||
7503	       (*in == '_') || (*in == '-') ||
7504	       (*in == ':') || (*in == '.'))
7505	    in++;
7506	if ((*in > 0) && (*in < 0x80)) {
7507	    count = in - ctxt->cur;
7508	    ret = xmlStrndup(ctxt->cur, count);
7509	    ctxt->cur = in;
7510	    return(ret);
7511	}
7512    }
7513    return(xmlXPathParseNameComplex(ctxt, 1));
7514}
7515
7516static xmlChar *
7517xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
7518    xmlChar buf[XML_MAX_NAMELEN + 5];
7519    int len = 0, l;
7520    int c;
7521
7522    /*
7523     * Handler for more complex cases
7524     */
7525    c = CUR_CHAR(l);
7526    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
7527        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7528        (c == '*') || /* accelerators */
7529	(!IS_LETTER(c) && (c != '_') &&
7530         ((qualified) && (c != ':')))) {
7531	return(NULL);
7532    }
7533
7534    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7535	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7536            (c == '.') || (c == '-') ||
7537	    (c == '_') || ((qualified) && (c == ':')) ||
7538	    (IS_COMBINING(c)) ||
7539	    (IS_EXTENDER(c)))) {
7540	COPY_BUF(l,buf,len,c);
7541	NEXTL(l);
7542	c = CUR_CHAR(l);
7543	if (len >= XML_MAX_NAMELEN) {
7544	    /*
7545	     * Okay someone managed to make a huge name, so he's ready to pay
7546	     * for the processing speed.
7547	     */
7548	    xmlChar *buffer;
7549	    int max = len * 2;
7550
7551	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
7552	    if (buffer == NULL) {
7553		XP_ERROR0(XPATH_MEMORY_ERROR);
7554	    }
7555	    memcpy(buffer, buf, len);
7556	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7557		   (c == '.') || (c == '-') ||
7558		   (c == '_') || ((qualified) && (c == ':')) ||
7559		   (IS_COMBINING(c)) ||
7560		   (IS_EXTENDER(c))) {
7561		if (len + 10 > max) {
7562		    max *= 2;
7563		    buffer = (xmlChar *) xmlRealloc(buffer,
7564			                            max * sizeof(xmlChar));
7565		    if (buffer == NULL) {
7566			XP_ERROR0(XPATH_MEMORY_ERROR);
7567		    }
7568		}
7569		COPY_BUF(l,buffer,len,c);
7570		NEXTL(l);
7571		c = CUR_CHAR(l);
7572	    }
7573	    buffer[len] = 0;
7574	    return(buffer);
7575	}
7576    }
7577    if (len == 0)
7578	return(NULL);
7579    return(xmlStrndup(buf, len));
7580}
7581
7582#define MAX_FRAC 20
7583
7584/*
7585 * These are used as divisors for the fractional part of a number.
7586 * Since the table includes 1.0 (representing '0' fractional digits),
7587 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7588 */
7589static double my_pow10[MAX_FRAC+1] = {
7590    1.0, 10.0, 100.0, 1000.0, 10000.0,
7591    100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7592    10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7593    100000000000000.0,
7594    1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7595    1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
7596};
7597
7598/**
7599 * xmlXPathStringEvalNumber:
7600 * @str:  A string to scan
7601 *
7602 *  [30a]  Float  ::= Number ('e' Digits?)?
7603 *
7604 *  [30]   Number ::=   Digits ('.' Digits?)?
7605 *                    | '.' Digits
7606 *  [31]   Digits ::=   [0-9]+
7607 *
7608 * Compile a Number in the string
7609 * In complement of the Number expression, this function also handles
7610 * negative values : '-' Number.
7611 *
7612 * Returns the double value.
7613 */
7614double
7615xmlXPathStringEvalNumber(const xmlChar *str) {
7616    const xmlChar *cur = str;
7617    double ret;
7618    int ok = 0;
7619    int isneg = 0;
7620    int exponent = 0;
7621    int is_exponent_negative = 0;
7622#ifdef __GNUC__
7623    unsigned long tmp = 0;
7624    double temp;
7625#endif
7626    if (cur == NULL) return(0);
7627    while (IS_BLANK_CH(*cur)) cur++;
7628    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7629        return(xmlXPathNAN);
7630    }
7631    if (*cur == '-') {
7632	isneg = 1;
7633	cur++;
7634    }
7635
7636#ifdef __GNUC__
7637    /*
7638     * tmp/temp is a workaround against a gcc compiler bug
7639     * http://veillard.com/gcc.bug
7640     */
7641    ret = 0;
7642    while ((*cur >= '0') && (*cur <= '9')) {
7643	ret = ret * 10;
7644	tmp = (*cur - '0');
7645	ok = 1;
7646	cur++;
7647	temp = (double) tmp;
7648	ret = ret + temp;
7649    }
7650#else
7651    ret = 0;
7652    while ((*cur >= '0') && (*cur <= '9')) {
7653	ret = ret * 10 + (*cur - '0');
7654	ok = 1;
7655	cur++;
7656    }
7657#endif
7658
7659    if (*cur == '.') {
7660	int v, frac = 0;
7661	double fraction = 0;
7662
7663        cur++;
7664	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7665	    return(xmlXPathNAN);
7666	}
7667	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7668	    v = (*cur - '0');
7669	    fraction = fraction * 10 + v;
7670	    frac = frac + 1;
7671	    cur++;
7672	}
7673	fraction /= my_pow10[frac];
7674	ret = ret + fraction;
7675	while ((*cur >= '0') && (*cur <= '9'))
7676	    cur++;
7677    }
7678    if ((*cur == 'e') || (*cur == 'E')) {
7679      cur++;
7680      if (*cur == '-') {
7681	is_exponent_negative = 1;
7682	cur++;
7683      } else if (*cur == '+') {
7684        cur++;
7685      }
7686      while ((*cur >= '0') && (*cur <= '9')) {
7687	exponent = exponent * 10 + (*cur - '0');
7688	cur++;
7689      }
7690    }
7691    while (IS_BLANK_CH(*cur)) cur++;
7692    if (*cur != 0) return(xmlXPathNAN);
7693    if (isneg) ret = -ret;
7694    if (is_exponent_negative) exponent = -exponent;
7695    ret *= pow(10.0, (double)exponent);
7696    return(ret);
7697}
7698
7699/**
7700 * xmlXPathCompNumber:
7701 * @ctxt:  the XPath Parser context
7702 *
7703 *  [30]   Number ::=   Digits ('.' Digits?)?
7704 *                    | '.' Digits
7705 *  [31]   Digits ::=   [0-9]+
7706 *
7707 * Compile a Number, then push it on the stack
7708 *
7709 */
7710static void
7711xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7712{
7713    double ret = 0.0;
7714    double mult = 1;
7715    int ok = 0;
7716    int exponent = 0;
7717    int is_exponent_negative = 0;
7718#ifdef __GNUC__
7719    unsigned long tmp = 0;
7720    double temp;
7721#endif
7722
7723    CHECK_ERROR;
7724    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7725        XP_ERROR(XPATH_NUMBER_ERROR);
7726    }
7727#ifdef __GNUC__
7728    /*
7729     * tmp/temp is a workaround against a gcc compiler bug
7730     * http://veillard.com/gcc.bug
7731     */
7732    ret = 0;
7733    while ((CUR >= '0') && (CUR <= '9')) {
7734	ret = ret * 10;
7735	tmp = (CUR - '0');
7736        ok = 1;
7737        NEXT;
7738	temp = (double) tmp;
7739	ret = ret + temp;
7740    }
7741#else
7742    ret = 0;
7743    while ((CUR >= '0') && (CUR <= '9')) {
7744	ret = ret * 10 + (CUR - '0');
7745	ok = 1;
7746	NEXT;
7747    }
7748#endif
7749    if (CUR == '.') {
7750        NEXT;
7751        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7752            XP_ERROR(XPATH_NUMBER_ERROR);
7753        }
7754        while ((CUR >= '0') && (CUR <= '9')) {
7755            mult /= 10;
7756            ret = ret + (CUR - '0') * mult;
7757            NEXT;
7758        }
7759    }
7760    if ((CUR == 'e') || (CUR == 'E')) {
7761        NEXT;
7762        if (CUR == '-') {
7763            is_exponent_negative = 1;
7764            NEXT;
7765        } else if (CUR == '+') {
7766	    NEXT;
7767	}
7768        while ((CUR >= '0') && (CUR <= '9')) {
7769            exponent = exponent * 10 + (CUR - '0');
7770            NEXT;
7771        }
7772        if (is_exponent_negative)
7773            exponent = -exponent;
7774        ret *= pow(10.0, (double) exponent);
7775    }
7776    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
7777                   xmlXPathNewFloat(ret), NULL);
7778}
7779
7780/**
7781 * xmlXPathParseLiteral:
7782 * @ctxt:  the XPath Parser context
7783 *
7784 * Parse a Literal
7785 *
7786 *  [29]   Literal ::=   '"' [^"]* '"'
7787 *                    | "'" [^']* "'"
7788 *
7789 * Returns the value found or NULL in case of error
7790 */
7791static xmlChar *
7792xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7793    const xmlChar *q;
7794    xmlChar *ret = NULL;
7795
7796    if (CUR == '"') {
7797        NEXT;
7798	q = CUR_PTR;
7799	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
7800	    NEXT;
7801	if (!IS_CHAR_CH(CUR)) {
7802	    XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7803	} else {
7804	    ret = xmlStrndup(q, CUR_PTR - q);
7805	    NEXT;
7806        }
7807    } else if (CUR == '\'') {
7808        NEXT;
7809	q = CUR_PTR;
7810	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
7811	    NEXT;
7812	if (!IS_CHAR_CH(CUR)) {
7813	    XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7814	} else {
7815	    ret = xmlStrndup(q, CUR_PTR - q);
7816	    NEXT;
7817        }
7818    } else {
7819	XP_ERROR0(XPATH_START_LITERAL_ERROR);
7820    }
7821    return(ret);
7822}
7823
7824/**
7825 * xmlXPathCompLiteral:
7826 * @ctxt:  the XPath Parser context
7827 *
7828 * Parse a Literal and push it on the stack.
7829 *
7830 *  [29]   Literal ::=   '"' [^"]* '"'
7831 *                    | "'" [^']* "'"
7832 *
7833 * TODO: xmlXPathCompLiteral memory allocation could be improved.
7834 */
7835static void
7836xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
7837    const xmlChar *q;
7838    xmlChar *ret = NULL;
7839
7840    if (CUR == '"') {
7841        NEXT;
7842	q = CUR_PTR;
7843	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
7844	    NEXT;
7845	if (!IS_CHAR_CH(CUR)) {
7846	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7847	} else {
7848	    ret = xmlStrndup(q, CUR_PTR - q);
7849	    NEXT;
7850        }
7851    } else if (CUR == '\'') {
7852        NEXT;
7853	q = CUR_PTR;
7854	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
7855	    NEXT;
7856	if (!IS_CHAR_CH(CUR)) {
7857	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7858	} else {
7859	    ret = xmlStrndup(q, CUR_PTR - q);
7860	    NEXT;
7861        }
7862    } else {
7863	XP_ERROR(XPATH_START_LITERAL_ERROR);
7864    }
7865    if (ret == NULL) return;
7866    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7867	           xmlXPathNewString(ret), NULL);
7868    xmlFree(ret);
7869}
7870
7871/**
7872 * xmlXPathCompVariableReference:
7873 * @ctxt:  the XPath Parser context
7874 *
7875 * Parse a VariableReference, evaluate it and push it on the stack.
7876 *
7877 * The variable bindings consist of a mapping from variable names
7878 * to variable values. The value of a variable is an object, which can be
7879 * of any of the types that are possible for the value of an expression,
7880 * and may also be of additional types not specified here.
7881 *
7882 * Early evaluation is possible since:
7883 * The variable bindings [...] used to evaluate a subexpression are
7884 * always the same as those used to evaluate the containing expression.
7885 *
7886 *  [36]   VariableReference ::=   '$' QName
7887 */
7888static void
7889xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
7890    xmlChar *name;
7891    xmlChar *prefix;
7892
7893    SKIP_BLANKS;
7894    if (CUR != '$') {
7895	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7896    }
7897    NEXT;
7898    name = xmlXPathParseQName(ctxt, &prefix);
7899    if (name == NULL) {
7900	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7901    }
7902    ctxt->comp->last = -1;
7903    PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7904	           name, prefix);
7905    SKIP_BLANKS;
7906}
7907
7908/**
7909 * xmlXPathIsNodeType:
7910 * @name:  a name string
7911 *
7912 * Is the name given a NodeType one.
7913 *
7914 *  [38]   NodeType ::=   'comment'
7915 *                    | 'text'
7916 *                    | 'processing-instruction'
7917 *                    | 'node'
7918 *
7919 * Returns 1 if true 0 otherwise
7920 */
7921int
7922xmlXPathIsNodeType(const xmlChar *name) {
7923    if (name == NULL)
7924	return(0);
7925
7926    if (xmlStrEqual(name, BAD_CAST "node"))
7927	return(1);
7928    if (xmlStrEqual(name, BAD_CAST "text"))
7929	return(1);
7930    if (xmlStrEqual(name, BAD_CAST "comment"))
7931	return(1);
7932    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7933	return(1);
7934    return(0);
7935}
7936
7937/**
7938 * xmlXPathCompFunctionCall:
7939 * @ctxt:  the XPath Parser context
7940 *
7941 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7942 *  [17]   Argument ::=   Expr
7943 *
7944 * Compile a function call, the evaluation of all arguments are
7945 * pushed on the stack
7946 */
7947static void
7948xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
7949    xmlChar *name;
7950    xmlChar *prefix;
7951    int nbargs = 0;
7952
7953    name = xmlXPathParseQName(ctxt, &prefix);
7954    if (name == NULL) {
7955	XP_ERROR(XPATH_EXPR_ERROR);
7956    }
7957    SKIP_BLANKS;
7958#ifdef DEBUG_EXPR
7959    if (prefix == NULL)
7960	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7961			name);
7962    else
7963	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7964			prefix, name);
7965#endif
7966
7967    if (CUR != '(') {
7968	XP_ERROR(XPATH_EXPR_ERROR);
7969    }
7970    NEXT;
7971    SKIP_BLANKS;
7972
7973    ctxt->comp->last = -1;
7974    if (CUR != ')') {
7975	while (CUR != 0) {
7976	    int op1 = ctxt->comp->last;
7977	    ctxt->comp->last = -1;
7978	    xmlXPathCompileExpr(ctxt);
7979	    CHECK_ERROR;
7980	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7981	    nbargs++;
7982	    if (CUR == ')') break;
7983	    if (CUR != ',') {
7984		XP_ERROR(XPATH_EXPR_ERROR);
7985	    }
7986	    NEXT;
7987	    SKIP_BLANKS;
7988	}
7989    }
7990    PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7991	           name, prefix);
7992    NEXT;
7993    SKIP_BLANKS;
7994}
7995
7996/**
7997 * xmlXPathCompPrimaryExpr:
7998 * @ctxt:  the XPath Parser context
7999 *
8000 *  [15]   PrimaryExpr ::=   VariableReference
8001 *                | '(' Expr ')'
8002 *                | Literal
8003 *                | Number
8004 *                | FunctionCall
8005 *
8006 * Compile a primary expression.
8007 */
8008static void
8009xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
8010    SKIP_BLANKS;
8011    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
8012    else if (CUR == '(') {
8013	NEXT;
8014	SKIP_BLANKS;
8015	xmlXPathCompileExpr(ctxt);
8016	CHECK_ERROR;
8017	if (CUR != ')') {
8018	    XP_ERROR(XPATH_EXPR_ERROR);
8019	}
8020	NEXT;
8021	SKIP_BLANKS;
8022    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8023	xmlXPathCompNumber(ctxt);
8024    } else if ((CUR == '\'') || (CUR == '"')) {
8025	xmlXPathCompLiteral(ctxt);
8026    } else {
8027	xmlXPathCompFunctionCall(ctxt);
8028    }
8029    SKIP_BLANKS;
8030}
8031
8032/**
8033 * xmlXPathCompFilterExpr:
8034 * @ctxt:  the XPath Parser context
8035 *
8036 *  [20]   FilterExpr ::=   PrimaryExpr
8037 *               | FilterExpr Predicate
8038 *
8039 * Compile a filter expression.
8040 * Square brackets are used to filter expressions in the same way that
8041 * they are used in location paths. It is an error if the expression to
8042 * be filtered does not evaluate to a node-set. The context node list
8043 * used for evaluating the expression in square brackets is the node-set
8044 * to be filtered listed in document order.
8045 */
8046
8047static void
8048xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8049    xmlXPathCompPrimaryExpr(ctxt);
8050    CHECK_ERROR;
8051    SKIP_BLANKS;
8052
8053    while (CUR == '[') {
8054	xmlXPathCompPredicate(ctxt, 1);
8055	SKIP_BLANKS;
8056    }
8057
8058
8059}
8060
8061/**
8062 * xmlXPathScanName:
8063 * @ctxt:  the XPath Parser context
8064 *
8065 * Trickery: parse an XML name but without consuming the input flow
8066 * Needed to avoid insanity in the parser state.
8067 *
8068 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8069 *                  CombiningChar | Extender
8070 *
8071 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8072 *
8073 * [6] Names ::= Name (S Name)*
8074 *
8075 * Returns the Name parsed or NULL
8076 */
8077
8078static xmlChar *
8079xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
8080    int len = 0, l;
8081    int c;
8082    const xmlChar *cur;
8083    xmlChar *ret;
8084
8085    cur = ctxt->cur;
8086
8087    c = CUR_CHAR(l);
8088    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8089	(!IS_LETTER(c) && (c != '_') &&
8090         (c != ':'))) {
8091	return(NULL);
8092    }
8093
8094    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8095	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8096            (c == '.') || (c == '-') ||
8097	    (c == '_') || (c == ':') ||
8098	    (IS_COMBINING(c)) ||
8099	    (IS_EXTENDER(c)))) {
8100	len += l;
8101	NEXTL(l);
8102	c = CUR_CHAR(l);
8103    }
8104    ret = xmlStrndup(cur, ctxt->cur - cur);
8105    ctxt->cur = cur;
8106    return(ret);
8107}
8108
8109/**
8110 * xmlXPathCompPathExpr:
8111 * @ctxt:  the XPath Parser context
8112 *
8113 *  [19]   PathExpr ::=   LocationPath
8114 *               | FilterExpr
8115 *               | FilterExpr '/' RelativeLocationPath
8116 *               | FilterExpr '//' RelativeLocationPath
8117 *
8118 * Compile a path expression.
8119 * The / operator and // operators combine an arbitrary expression
8120 * and a relative location path. It is an error if the expression
8121 * does not evaluate to a node-set.
8122 * The / operator does composition in the same way as when / is
8123 * used in a location path. As in location paths, // is short for
8124 * /descendant-or-self::node()/.
8125 */
8126
8127static void
8128xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
8129    int lc = 1;           /* Should we branch to LocationPath ?         */
8130    xmlChar *name = NULL; /* we may have to preparse a name to find out */
8131
8132    SKIP_BLANKS;
8133    if ((CUR == '$') || (CUR == '(') ||
8134    	(IS_ASCII_DIGIT(CUR)) ||
8135        (CUR == '\'') || (CUR == '"') ||
8136	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8137	lc = 0;
8138    } else if (CUR == '*') {
8139	/* relative or absolute location path */
8140	lc = 1;
8141    } else if (CUR == '/') {
8142	/* relative or absolute location path */
8143	lc = 1;
8144    } else if (CUR == '@') {
8145	/* relative abbreviated attribute location path */
8146	lc = 1;
8147    } else if (CUR == '.') {
8148	/* relative abbreviated attribute location path */
8149	lc = 1;
8150    } else {
8151	/*
8152	 * Problem is finding if we have a name here whether it's:
8153	 *   - a nodetype
8154	 *   - a function call in which case it's followed by '('
8155	 *   - an axis in which case it's followed by ':'
8156	 *   - a element name
8157	 * We do an a priori analysis here rather than having to
8158	 * maintain parsed token content through the recursive function
8159	 * calls. This looks uglier but makes the code easier to
8160	 * read/write/debug.
8161	 */
8162	SKIP_BLANKS;
8163	name = xmlXPathScanName(ctxt);
8164	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8165#ifdef DEBUG_STEP
8166	    xmlGenericError(xmlGenericErrorContext,
8167		    "PathExpr: Axis\n");
8168#endif
8169	    lc = 1;
8170	    xmlFree(name);
8171	} else if (name != NULL) {
8172	    int len =xmlStrlen(name);
8173
8174
8175	    while (NXT(len) != 0) {
8176		if (NXT(len) == '/') {
8177		    /* element name */
8178#ifdef DEBUG_STEP
8179		    xmlGenericError(xmlGenericErrorContext,
8180			    "PathExpr: AbbrRelLocation\n");
8181#endif
8182		    lc = 1;
8183		    break;
8184		} else if (IS_BLANK_CH(NXT(len))) {
8185		    /* ignore blanks */
8186		    ;
8187		} else if (NXT(len) == ':') {
8188#ifdef DEBUG_STEP
8189		    xmlGenericError(xmlGenericErrorContext,
8190			    "PathExpr: AbbrRelLocation\n");
8191#endif
8192		    lc = 1;
8193		    break;
8194		} else if ((NXT(len) == '(')) {
8195		    /* Note Type or Function */
8196		    if (xmlXPathIsNodeType(name)) {
8197#ifdef DEBUG_STEP
8198		        xmlGenericError(xmlGenericErrorContext,
8199				"PathExpr: Type search\n");
8200#endif
8201			lc = 1;
8202		    } else {
8203#ifdef DEBUG_STEP
8204		        xmlGenericError(xmlGenericErrorContext,
8205				"PathExpr: function call\n");
8206#endif
8207			lc = 0;
8208		    }
8209                    break;
8210		} else if ((NXT(len) == '[')) {
8211		    /* element name */
8212#ifdef DEBUG_STEP
8213		    xmlGenericError(xmlGenericErrorContext,
8214			    "PathExpr: AbbrRelLocation\n");
8215#endif
8216		    lc = 1;
8217		    break;
8218		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8219			   (NXT(len) == '=')) {
8220		    lc = 1;
8221		    break;
8222		} else {
8223		    lc = 1;
8224		    break;
8225		}
8226		len++;
8227	    }
8228	    if (NXT(len) == 0) {
8229#ifdef DEBUG_STEP
8230		xmlGenericError(xmlGenericErrorContext,
8231			"PathExpr: AbbrRelLocation\n");
8232#endif
8233		/* element name */
8234		lc = 1;
8235	    }
8236	    xmlFree(name);
8237	} else {
8238	    /* make sure all cases are covered explicitly */
8239	    XP_ERROR(XPATH_EXPR_ERROR);
8240	}
8241    }
8242
8243    if (lc) {
8244	if (CUR == '/') {
8245	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8246	} else {
8247	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8248	}
8249	xmlXPathCompLocationPath(ctxt);
8250    } else {
8251	xmlXPathCompFilterExpr(ctxt);
8252	CHECK_ERROR;
8253	if ((CUR == '/') && (NXT(1) == '/')) {
8254	    SKIP(2);
8255	    SKIP_BLANKS;
8256
8257	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8258		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8259	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8260
8261	    xmlXPathCompRelativeLocationPath(ctxt);
8262	} else if (CUR == '/') {
8263	    xmlXPathCompRelativeLocationPath(ctxt);
8264	}
8265    }
8266    SKIP_BLANKS;
8267}
8268
8269/**
8270 * xmlXPathCompUnionExpr:
8271 * @ctxt:  the XPath Parser context
8272 *
8273 *  [18]   UnionExpr ::=   PathExpr
8274 *               | UnionExpr '|' PathExpr
8275 *
8276 * Compile an union expression.
8277 */
8278
8279static void
8280xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8281    xmlXPathCompPathExpr(ctxt);
8282    CHECK_ERROR;
8283    SKIP_BLANKS;
8284    while (CUR == '|') {
8285	int op1 = ctxt->comp->last;
8286	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8287
8288	NEXT;
8289	SKIP_BLANKS;
8290	xmlXPathCompPathExpr(ctxt);
8291
8292	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8293
8294	SKIP_BLANKS;
8295    }
8296}
8297
8298/**
8299 * xmlXPathCompUnaryExpr:
8300 * @ctxt:  the XPath Parser context
8301 *
8302 *  [27]   UnaryExpr ::=   UnionExpr
8303 *                   | '-' UnaryExpr
8304 *
8305 * Compile an unary expression.
8306 */
8307
8308static void
8309xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
8310    int minus = 0;
8311    int found = 0;
8312
8313    SKIP_BLANKS;
8314    while (CUR == '-') {
8315        minus = 1 - minus;
8316	found = 1;
8317	NEXT;
8318	SKIP_BLANKS;
8319    }
8320
8321    xmlXPathCompUnionExpr(ctxt);
8322    CHECK_ERROR;
8323    if (found) {
8324	if (minus)
8325	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8326	else
8327	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
8328    }
8329}
8330
8331/**
8332 * xmlXPathCompMultiplicativeExpr:
8333 * @ctxt:  the XPath Parser context
8334 *
8335 *  [26]   MultiplicativeExpr ::=   UnaryExpr
8336 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
8337 *                   | MultiplicativeExpr 'div' UnaryExpr
8338 *                   | MultiplicativeExpr 'mod' UnaryExpr
8339 *  [34]   MultiplyOperator ::=   '*'
8340 *
8341 * Compile an Additive expression.
8342 */
8343
8344static void
8345xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8346    xmlXPathCompUnaryExpr(ctxt);
8347    CHECK_ERROR;
8348    SKIP_BLANKS;
8349    while ((CUR == '*') ||
8350           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8351           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8352	int op = -1;
8353	int op1 = ctxt->comp->last;
8354
8355        if (CUR == '*') {
8356	    op = 0;
8357	    NEXT;
8358	} else if (CUR == 'd') {
8359	    op = 1;
8360	    SKIP(3);
8361	} else if (CUR == 'm') {
8362	    op = 2;
8363	    SKIP(3);
8364	}
8365	SKIP_BLANKS;
8366        xmlXPathCompUnaryExpr(ctxt);
8367	CHECK_ERROR;
8368	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
8369	SKIP_BLANKS;
8370    }
8371}
8372
8373/**
8374 * xmlXPathCompAdditiveExpr:
8375 * @ctxt:  the XPath Parser context
8376 *
8377 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
8378 *                   | AdditiveExpr '+' MultiplicativeExpr
8379 *                   | AdditiveExpr '-' MultiplicativeExpr
8380 *
8381 * Compile an Additive expression.
8382 */
8383
8384static void
8385xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
8386
8387    xmlXPathCompMultiplicativeExpr(ctxt);
8388    CHECK_ERROR;
8389    SKIP_BLANKS;
8390    while ((CUR == '+') || (CUR == '-')) {
8391	int plus;
8392	int op1 = ctxt->comp->last;
8393
8394        if (CUR == '+') plus = 1;
8395	else plus = 0;
8396	NEXT;
8397	SKIP_BLANKS;
8398        xmlXPathCompMultiplicativeExpr(ctxt);
8399	CHECK_ERROR;
8400	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
8401	SKIP_BLANKS;
8402    }
8403}
8404
8405/**
8406 * xmlXPathCompRelationalExpr:
8407 * @ctxt:  the XPath Parser context
8408 *
8409 *  [24]   RelationalExpr ::=   AdditiveExpr
8410 *                 | RelationalExpr '<' AdditiveExpr
8411 *                 | RelationalExpr '>' AdditiveExpr
8412 *                 | RelationalExpr '<=' AdditiveExpr
8413 *                 | RelationalExpr '>=' AdditiveExpr
8414 *
8415 *  A <= B > C is allowed ? Answer from James, yes with
8416 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8417 *  which is basically what got implemented.
8418 *
8419 * Compile a Relational expression, then push the result
8420 * on the stack
8421 */
8422
8423static void
8424xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8425    xmlXPathCompAdditiveExpr(ctxt);
8426    CHECK_ERROR;
8427    SKIP_BLANKS;
8428    while ((CUR == '<') ||
8429           (CUR == '>') ||
8430           ((CUR == '<') && (NXT(1) == '=')) ||
8431           ((CUR == '>') && (NXT(1) == '='))) {
8432	int inf, strict;
8433	int op1 = ctxt->comp->last;
8434
8435        if (CUR == '<') inf = 1;
8436	else inf = 0;
8437	if (NXT(1) == '=') strict = 0;
8438	else strict = 1;
8439	NEXT;
8440	if (!strict) NEXT;
8441	SKIP_BLANKS;
8442        xmlXPathCompAdditiveExpr(ctxt);
8443	CHECK_ERROR;
8444	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
8445	SKIP_BLANKS;
8446    }
8447}
8448
8449/**
8450 * xmlXPathCompEqualityExpr:
8451 * @ctxt:  the XPath Parser context
8452 *
8453 *  [23]   EqualityExpr ::=   RelationalExpr
8454 *                 | EqualityExpr '=' RelationalExpr
8455 *                 | EqualityExpr '!=' RelationalExpr
8456 *
8457 *  A != B != C is allowed ? Answer from James, yes with
8458 *  (RelationalExpr = RelationalExpr) = RelationalExpr
8459 *  (RelationalExpr != RelationalExpr) != RelationalExpr
8460 *  which is basically what got implemented.
8461 *
8462 * Compile an Equality expression.
8463 *
8464 */
8465static void
8466xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8467    xmlXPathCompRelationalExpr(ctxt);
8468    CHECK_ERROR;
8469    SKIP_BLANKS;
8470    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
8471	int eq;
8472	int op1 = ctxt->comp->last;
8473
8474        if (CUR == '=') eq = 1;
8475	else eq = 0;
8476	NEXT;
8477	if (!eq) NEXT;
8478	SKIP_BLANKS;
8479        xmlXPathCompRelationalExpr(ctxt);
8480	CHECK_ERROR;
8481	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
8482	SKIP_BLANKS;
8483    }
8484}
8485
8486/**
8487 * xmlXPathCompAndExpr:
8488 * @ctxt:  the XPath Parser context
8489 *
8490 *  [22]   AndExpr ::=   EqualityExpr
8491 *                 | AndExpr 'and' EqualityExpr
8492 *
8493 * Compile an AND expression.
8494 *
8495 */
8496static void
8497xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8498    xmlXPathCompEqualityExpr(ctxt);
8499    CHECK_ERROR;
8500    SKIP_BLANKS;
8501    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
8502	int op1 = ctxt->comp->last;
8503        SKIP(3);
8504	SKIP_BLANKS;
8505        xmlXPathCompEqualityExpr(ctxt);
8506	CHECK_ERROR;
8507	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
8508	SKIP_BLANKS;
8509    }
8510}
8511
8512/**
8513 * xmlXPathCompileExpr:
8514 * @ctxt:  the XPath Parser context
8515 *
8516 *  [14]   Expr ::=   OrExpr
8517 *  [21]   OrExpr ::=   AndExpr
8518 *                 | OrExpr 'or' AndExpr
8519 *
8520 * Parse and compile an expression
8521 */
8522static void
8523xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8524    xmlXPathCompAndExpr(ctxt);
8525    CHECK_ERROR;
8526    SKIP_BLANKS;
8527    while ((CUR == 'o') && (NXT(1) == 'r')) {
8528	int op1 = ctxt->comp->last;
8529        SKIP(2);
8530	SKIP_BLANKS;
8531        xmlXPathCompAndExpr(ctxt);
8532	CHECK_ERROR;
8533	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8534	op1 = ctxt->comp->nbStep;
8535	SKIP_BLANKS;
8536    }
8537    if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8538	/* more ops could be optimized too */
8539	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8540    }
8541}
8542
8543/**
8544 * xmlXPathCompPredicate:
8545 * @ctxt:  the XPath Parser context
8546 * @filter:  act as a filter
8547 *
8548 *  [8]   Predicate ::=   '[' PredicateExpr ']'
8549 *  [9]   PredicateExpr ::=   Expr
8550 *
8551 * Compile a predicate expression
8552 */
8553static void
8554xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
8555    int op1 = ctxt->comp->last;
8556
8557    SKIP_BLANKS;
8558    if (CUR != '[') {
8559	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8560    }
8561    NEXT;
8562    SKIP_BLANKS;
8563
8564    ctxt->comp->last = -1;
8565    xmlXPathCompileExpr(ctxt);
8566    CHECK_ERROR;
8567
8568    if (CUR != ']') {
8569	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8570    }
8571
8572    if (filter)
8573	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8574    else
8575	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
8576
8577    NEXT;
8578    SKIP_BLANKS;
8579}
8580
8581/**
8582 * xmlXPathCompNodeTest:
8583 * @ctxt:  the XPath Parser context
8584 * @test:  pointer to a xmlXPathTestVal
8585 * @type:  pointer to a xmlXPathTypeVal
8586 * @prefix:  placeholder for a possible name prefix
8587 *
8588 * [7] NodeTest ::=   NameTest
8589 *		    | NodeType '(' ')'
8590 *		    | 'processing-instruction' '(' Literal ')'
8591 *
8592 * [37] NameTest ::=  '*'
8593 *		    | NCName ':' '*'
8594 *		    | QName
8595 * [38] NodeType ::= 'comment'
8596 *		   | 'text'
8597 *		   | 'processing-instruction'
8598 *		   | 'node'
8599 *
8600 * Returns the name found and updates @test, @type and @prefix appropriately
8601 */
8602static xmlChar *
8603xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8604	             xmlXPathTypeVal *type, const xmlChar **prefix,
8605		     xmlChar *name) {
8606    int blanks;
8607
8608    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8609	STRANGE;
8610	return(NULL);
8611    }
8612    *type = (xmlXPathTypeVal) 0;
8613    *test = (xmlXPathTestVal) 0;
8614    *prefix = NULL;
8615    SKIP_BLANKS;
8616
8617    if ((name == NULL) && (CUR == '*')) {
8618	/*
8619	 * All elements
8620	 */
8621	NEXT;
8622	*test = NODE_TEST_ALL;
8623	return(NULL);
8624    }
8625
8626    if (name == NULL)
8627	name = xmlXPathParseNCName(ctxt);
8628    if (name == NULL) {
8629	XP_ERROR0(XPATH_EXPR_ERROR);
8630    }
8631
8632    blanks = IS_BLANK_CH(CUR);
8633    SKIP_BLANKS;
8634    if (CUR == '(') {
8635	NEXT;
8636	/*
8637	 * NodeType or PI search
8638	 */
8639	if (xmlStrEqual(name, BAD_CAST "comment"))
8640	    *type = NODE_TYPE_COMMENT;
8641	else if (xmlStrEqual(name, BAD_CAST "node"))
8642	    *type = NODE_TYPE_NODE;
8643	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8644	    *type = NODE_TYPE_PI;
8645	else if (xmlStrEqual(name, BAD_CAST "text"))
8646	    *type = NODE_TYPE_TEXT;
8647	else {
8648	    if (name != NULL)
8649		xmlFree(name);
8650	    XP_ERROR0(XPATH_EXPR_ERROR);
8651	}
8652
8653	*test = NODE_TEST_TYPE;
8654
8655	SKIP_BLANKS;
8656	if (*type == NODE_TYPE_PI) {
8657	    /*
8658	     * Specific case: search a PI by name.
8659	     */
8660	    if (name != NULL)
8661		xmlFree(name);
8662	    name = NULL;
8663	    if (CUR != ')') {
8664		name = xmlXPathParseLiteral(ctxt);
8665		CHECK_ERROR 0;
8666		*test = NODE_TEST_PI;
8667		SKIP_BLANKS;
8668	    }
8669	}
8670	if (CUR != ')') {
8671	    if (name != NULL)
8672		xmlFree(name);
8673	    XP_ERROR0(XPATH_UNCLOSED_ERROR);
8674	}
8675	NEXT;
8676	return(name);
8677    }
8678    *test = NODE_TEST_NAME;
8679    if ((!blanks) && (CUR == ':')) {
8680	NEXT;
8681
8682	/*
8683	 * Since currently the parser context don't have a
8684	 * namespace list associated:
8685	 * The namespace name for this prefix can be computed
8686	 * only at evaluation time. The compilation is done
8687	 * outside of any context.
8688	 */
8689#if 0
8690	*prefix = xmlXPathNsLookup(ctxt->context, name);
8691	if (name != NULL)
8692	    xmlFree(name);
8693	if (*prefix == NULL) {
8694	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8695	}
8696#else
8697	*prefix = name;
8698#endif
8699
8700	if (CUR == '*') {
8701	    /*
8702	     * All elements
8703	     */
8704	    NEXT;
8705	    *test = NODE_TEST_ALL;
8706	    return(NULL);
8707	}
8708
8709	name = xmlXPathParseNCName(ctxt);
8710	if (name == NULL) {
8711	    XP_ERROR0(XPATH_EXPR_ERROR);
8712	}
8713    }
8714    return(name);
8715}
8716
8717/**
8718 * xmlXPathIsAxisName:
8719 * @name:  a preparsed name token
8720 *
8721 * [6] AxisName ::=   'ancestor'
8722 *                  | 'ancestor-or-self'
8723 *                  | 'attribute'
8724 *                  | 'child'
8725 *                  | 'descendant'
8726 *                  | 'descendant-or-self'
8727 *                  | 'following'
8728 *                  | 'following-sibling'
8729 *                  | 'namespace'
8730 *                  | 'parent'
8731 *                  | 'preceding'
8732 *                  | 'preceding-sibling'
8733 *                  | 'self'
8734 *
8735 * Returns the axis or 0
8736 */
8737static xmlXPathAxisVal
8738xmlXPathIsAxisName(const xmlChar *name) {
8739    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
8740    switch (name[0]) {
8741	case 'a':
8742	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
8743		ret = AXIS_ANCESTOR;
8744	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8745		ret = AXIS_ANCESTOR_OR_SELF;
8746	    if (xmlStrEqual(name, BAD_CAST "attribute"))
8747		ret = AXIS_ATTRIBUTE;
8748	    break;
8749	case 'c':
8750	    if (xmlStrEqual(name, BAD_CAST "child"))
8751		ret = AXIS_CHILD;
8752	    break;
8753	case 'd':
8754	    if (xmlStrEqual(name, BAD_CAST "descendant"))
8755		ret = AXIS_DESCENDANT;
8756	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8757		ret = AXIS_DESCENDANT_OR_SELF;
8758	    break;
8759	case 'f':
8760	    if (xmlStrEqual(name, BAD_CAST "following"))
8761		ret = AXIS_FOLLOWING;
8762	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8763		ret = AXIS_FOLLOWING_SIBLING;
8764	    break;
8765	case 'n':
8766	    if (xmlStrEqual(name, BAD_CAST "namespace"))
8767		ret = AXIS_NAMESPACE;
8768	    break;
8769	case 'p':
8770	    if (xmlStrEqual(name, BAD_CAST "parent"))
8771		ret = AXIS_PARENT;
8772	    if (xmlStrEqual(name, BAD_CAST "preceding"))
8773		ret = AXIS_PRECEDING;
8774	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8775		ret = AXIS_PRECEDING_SIBLING;
8776	    break;
8777	case 's':
8778	    if (xmlStrEqual(name, BAD_CAST "self"))
8779		ret = AXIS_SELF;
8780	    break;
8781    }
8782    return(ret);
8783}
8784
8785/**
8786 * xmlXPathCompStep:
8787 * @ctxt:  the XPath Parser context
8788 *
8789 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
8790 *                  | AbbreviatedStep
8791 *
8792 * [12] AbbreviatedStep ::=   '.' | '..'
8793 *
8794 * [5] AxisSpecifier ::= AxisName '::'
8795 *                  | AbbreviatedAxisSpecifier
8796 *
8797 * [13] AbbreviatedAxisSpecifier ::= '@'?
8798 *
8799 * Modified for XPtr range support as:
8800 *
8801 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8802 *                     | AbbreviatedStep
8803 *                     | 'range-to' '(' Expr ')' Predicate*
8804 *
8805 * Compile one step in a Location Path
8806 * A location step of . is short for self::node(). This is
8807 * particularly useful in conjunction with //. For example, the
8808 * location path .//para is short for
8809 * self::node()/descendant-or-self::node()/child::para
8810 * and so will select all para descendant elements of the context
8811 * node.
8812 * Similarly, a location step of .. is short for parent::node().
8813 * For example, ../title is short for parent::node()/child::title
8814 * and so will select the title children of the parent of the context
8815 * node.
8816 */
8817static void
8818xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
8819#ifdef LIBXML_XPTR_ENABLED
8820    int rangeto = 0;
8821    int op2 = -1;
8822#endif
8823
8824    SKIP_BLANKS;
8825    if ((CUR == '.') && (NXT(1) == '.')) {
8826	SKIP(2);
8827	SKIP_BLANKS;
8828	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8829		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8830    } else if (CUR == '.') {
8831	NEXT;
8832	SKIP_BLANKS;
8833    } else {
8834	xmlChar *name = NULL;
8835	const xmlChar *prefix = NULL;
8836	xmlXPathTestVal test;
8837	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
8838	xmlXPathTypeVal type;
8839	int op1;
8840
8841	/*
8842	 * The modification needed for XPointer change to the production
8843	 */
8844#ifdef LIBXML_XPTR_ENABLED
8845	if (ctxt->xptr) {
8846	    name = xmlXPathParseNCName(ctxt);
8847	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
8848                op2 = ctxt->comp->last;
8849		xmlFree(name);
8850		SKIP_BLANKS;
8851		if (CUR != '(') {
8852		    XP_ERROR(XPATH_EXPR_ERROR);
8853		}
8854		NEXT;
8855		SKIP_BLANKS;
8856
8857		xmlXPathCompileExpr(ctxt);
8858		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
8859		CHECK_ERROR;
8860
8861		SKIP_BLANKS;
8862		if (CUR != ')') {
8863		    XP_ERROR(XPATH_EXPR_ERROR);
8864		}
8865		NEXT;
8866		rangeto = 1;
8867		goto eval_predicates;
8868	    }
8869	}
8870#endif
8871	if (CUR == '*') {
8872	    axis = AXIS_CHILD;
8873	} else {
8874	    if (name == NULL)
8875		name = xmlXPathParseNCName(ctxt);
8876	    if (name != NULL) {
8877		axis = xmlXPathIsAxisName(name);
8878		if (axis != 0) {
8879		    SKIP_BLANKS;
8880		    if ((CUR == ':') && (NXT(1) == ':')) {
8881			SKIP(2);
8882			xmlFree(name);
8883			name = NULL;
8884		    } else {
8885			/* an element name can conflict with an axis one :-\ */
8886			axis = AXIS_CHILD;
8887		    }
8888		} else {
8889		    axis = AXIS_CHILD;
8890		}
8891	    } else if (CUR == '@') {
8892		NEXT;
8893		axis = AXIS_ATTRIBUTE;
8894	    } else {
8895		axis = AXIS_CHILD;
8896	    }
8897	}
8898
8899	CHECK_ERROR;
8900
8901	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
8902	if (test == 0)
8903	    return;
8904
8905#ifdef DEBUG_STEP
8906	xmlGenericError(xmlGenericErrorContext,
8907		"Basis : computing new set\n");
8908#endif
8909
8910#ifdef DEBUG_STEP
8911	xmlGenericError(xmlGenericErrorContext, "Basis : ");
8912	if (ctxt->value == NULL)
8913	    xmlGenericError(xmlGenericErrorContext, "no value\n");
8914	else if (ctxt->value->nodesetval == NULL)
8915	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
8916	else
8917	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
8918#endif
8919
8920#ifdef LIBXML_XPTR_ENABLED
8921eval_predicates:
8922#endif
8923	op1 = ctxt->comp->last;
8924	ctxt->comp->last = -1;
8925
8926	SKIP_BLANKS;
8927	while (CUR == '[') {
8928	    xmlXPathCompPredicate(ctxt, 0);
8929	}
8930
8931#ifdef LIBXML_XPTR_ENABLED
8932	if (rangeto) {
8933	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8934	} else
8935#endif
8936	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8937			   test, type, (void *)prefix, (void *)name);
8938
8939    }
8940#ifdef DEBUG_STEP
8941    xmlGenericError(xmlGenericErrorContext, "Step : ");
8942    if (ctxt->value == NULL)
8943	xmlGenericError(xmlGenericErrorContext, "no value\n");
8944    else if (ctxt->value->nodesetval == NULL)
8945	xmlGenericError(xmlGenericErrorContext, "Empty\n");
8946    else
8947	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8948		ctxt->value->nodesetval);
8949#endif
8950}
8951
8952/**
8953 * xmlXPathCompRelativeLocationPath:
8954 * @ctxt:  the XPath Parser context
8955 *
8956 *  [3]   RelativeLocationPath ::=   Step
8957 *                     | RelativeLocationPath '/' Step
8958 *                     | AbbreviatedRelativeLocationPath
8959 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
8960 *
8961 * Compile a relative location path.
8962 */
8963static void
8964xmlXPathCompRelativeLocationPath
8965(xmlXPathParserContextPtr ctxt) {
8966    SKIP_BLANKS;
8967    if ((CUR == '/') && (NXT(1) == '/')) {
8968	SKIP(2);
8969	SKIP_BLANKS;
8970	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8971		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8972    } else if (CUR == '/') {
8973	    NEXT;
8974	SKIP_BLANKS;
8975    }
8976    xmlXPathCompStep(ctxt);
8977    SKIP_BLANKS;
8978    while (CUR == '/') {
8979	if ((CUR == '/') && (NXT(1) == '/')) {
8980	    SKIP(2);
8981	    SKIP_BLANKS;
8982	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8983			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8984	    xmlXPathCompStep(ctxt);
8985	} else if (CUR == '/') {
8986	    NEXT;
8987	    SKIP_BLANKS;
8988	    xmlXPathCompStep(ctxt);
8989	}
8990	SKIP_BLANKS;
8991    }
8992}
8993
8994/**
8995 * xmlXPathCompLocationPath:
8996 * @ctxt:  the XPath Parser context
8997 *
8998 *  [1]   LocationPath ::=   RelativeLocationPath
8999 *                     | AbsoluteLocationPath
9000 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
9001 *                     | AbbreviatedAbsoluteLocationPath
9002 *  [10]   AbbreviatedAbsoluteLocationPath ::=
9003 *                           '//' RelativeLocationPath
9004 *
9005 * Compile a location path
9006 *
9007 * // is short for /descendant-or-self::node()/. For example,
9008 * //para is short for /descendant-or-self::node()/child::para and
9009 * so will select any para element in the document (even a para element
9010 * that is a document element will be selected by //para since the
9011 * document element node is a child of the root node); div//para is
9012 * short for div/descendant-or-self::node()/child::para and so will
9013 * select all para descendants of div children.
9014 */
9015static void
9016xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
9017    SKIP_BLANKS;
9018    if (CUR != '/') {
9019        xmlXPathCompRelativeLocationPath(ctxt);
9020    } else {
9021	while (CUR == '/') {
9022	    if ((CUR == '/') && (NXT(1) == '/')) {
9023		SKIP(2);
9024		SKIP_BLANKS;
9025		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9026			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9027		xmlXPathCompRelativeLocationPath(ctxt);
9028	    } else if (CUR == '/') {
9029		NEXT;
9030		SKIP_BLANKS;
9031		if ((CUR != 0 ) &&
9032		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
9033		     (CUR == '@') || (CUR == '*')))
9034		    xmlXPathCompRelativeLocationPath(ctxt);
9035	    }
9036	}
9037    }
9038}
9039
9040/************************************************************************
9041 *									*
9042 * 		XPath precompiled expression evaluation			*
9043 *									*
9044 ************************************************************************/
9045
9046static int
9047xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9048
9049/**
9050 * xmlXPathNodeCollectAndTest:
9051 * @ctxt:  the XPath Parser context
9052 * @op:  the XPath precompiled step operation
9053 * @first:  pointer to the first element in document order
9054 * @last:  pointer to the last element in document order
9055 *
9056 * This is the function implementing a step: based on the current list
9057 * of nodes, it builds up a new list, looking at all nodes under that
9058 * axis and selecting them. It also does the predicate filtering
9059 *
9060 * Pushes the new NodeSet resulting from the search.
9061 *
9062 * Returns the number of nodes traversed
9063 */
9064static int
9065xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
9066                           xmlXPathStepOpPtr op,
9067			   xmlNodePtr * first, xmlNodePtr * last)
9068{
9069    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9070    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9071    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
9072    const xmlChar *prefix = op->value4;
9073    const xmlChar *name = op->value5;
9074    const xmlChar *URI = NULL;
9075
9076#ifdef DEBUG_STEP
9077    int n = 0;
9078#endif
9079    int i, t = 0;
9080    xmlNodeSetPtr ret, list;
9081    xmlXPathTraversalFunction next = NULL;
9082    void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9083    xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
9084    xmlNodePtr cur = NULL;
9085    xmlXPathObjectPtr obj;
9086    xmlNodeSetPtr nodelist;
9087    xmlNodePtr tmp;
9088
9089    CHECK_TYPE0(XPATH_NODESET);
9090    obj = valuePop(ctxt);
9091    addNode = xmlXPathNodeSetAdd;
9092    mergeNodeSet = xmlXPathNodeSetMerge;
9093    if (prefix != NULL) {
9094        URI = xmlXPathNsLookup(ctxt->context, prefix);
9095        if (URI == NULL)
9096            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9097    }
9098#ifdef DEBUG_STEP
9099    xmlGenericError(xmlGenericErrorContext, "new step : ");
9100#endif
9101    switch (axis) {
9102        case AXIS_ANCESTOR:
9103#ifdef DEBUG_STEP
9104            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9105#endif
9106            first = NULL;
9107            next = xmlXPathNextAncestor;
9108            break;
9109        case AXIS_ANCESTOR_OR_SELF:
9110#ifdef DEBUG_STEP
9111            xmlGenericError(xmlGenericErrorContext,
9112                            "axis 'ancestors-or-self' ");
9113#endif
9114            first = NULL;
9115            next = xmlXPathNextAncestorOrSelf;
9116            break;
9117        case AXIS_ATTRIBUTE:
9118#ifdef DEBUG_STEP
9119            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9120#endif
9121            first = NULL;
9122	    last = NULL;
9123            next = xmlXPathNextAttribute;
9124	    mergeNodeSet = xmlXPathNodeSetMergeUnique;
9125            break;
9126        case AXIS_CHILD:
9127#ifdef DEBUG_STEP
9128            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9129#endif
9130	    last = NULL;
9131            next = xmlXPathNextChild;
9132	    mergeNodeSet = xmlXPathNodeSetMergeUnique;
9133            break;
9134        case AXIS_DESCENDANT:
9135#ifdef DEBUG_STEP
9136            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9137#endif
9138	    last = NULL;
9139            next = xmlXPathNextDescendant;
9140            break;
9141        case AXIS_DESCENDANT_OR_SELF:
9142#ifdef DEBUG_STEP
9143            xmlGenericError(xmlGenericErrorContext,
9144                            "axis 'descendant-or-self' ");
9145#endif
9146	    last = NULL;
9147            next = xmlXPathNextDescendantOrSelf;
9148            break;
9149        case AXIS_FOLLOWING:
9150#ifdef DEBUG_STEP
9151            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9152#endif
9153	    last = NULL;
9154            next = xmlXPathNextFollowing;
9155            break;
9156        case AXIS_FOLLOWING_SIBLING:
9157#ifdef DEBUG_STEP
9158            xmlGenericError(xmlGenericErrorContext,
9159                            "axis 'following-siblings' ");
9160#endif
9161	    last = NULL;
9162            next = xmlXPathNextFollowingSibling;
9163            break;
9164        case AXIS_NAMESPACE:
9165#ifdef DEBUG_STEP
9166            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9167#endif
9168            first = NULL;
9169	    last = NULL;
9170            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9171	    mergeNodeSet = xmlXPathNodeSetMergeUnique;
9172            break;
9173        case AXIS_PARENT:
9174#ifdef DEBUG_STEP
9175            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9176#endif
9177            first = NULL;
9178            next = xmlXPathNextParent;
9179            break;
9180        case AXIS_PRECEDING:
9181#ifdef DEBUG_STEP
9182            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9183#endif
9184            first = NULL;
9185            next = xmlXPathNextPrecedingInternal;
9186            break;
9187        case AXIS_PRECEDING_SIBLING:
9188#ifdef DEBUG_STEP
9189            xmlGenericError(xmlGenericErrorContext,
9190                            "axis 'preceding-sibling' ");
9191#endif
9192            first = NULL;
9193            next = xmlXPathNextPrecedingSibling;
9194            break;
9195        case AXIS_SELF:
9196#ifdef DEBUG_STEP
9197            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9198#endif
9199            first = NULL;
9200	    last = NULL;
9201            next = xmlXPathNextSelf;
9202	    mergeNodeSet = xmlXPathNodeSetMergeUnique;
9203            break;
9204    }
9205    if (next == NULL)
9206        return(0);
9207
9208    nodelist = obj->nodesetval;
9209    if (nodelist == NULL) {
9210        xmlXPathFreeObject(obj);
9211        valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9212        return(0);
9213    }
9214    addNode = xmlXPathNodeSetAddUnique;
9215    ret = NULL;
9216#ifdef DEBUG_STEP
9217    xmlGenericError(xmlGenericErrorContext,
9218                    " context contains %d nodes\n", nodelist->nodeNr);
9219    switch (test) {
9220        case NODE_TEST_NONE:
9221            xmlGenericError(xmlGenericErrorContext,
9222                            "           searching for none !!!\n");
9223            break;
9224        case NODE_TEST_TYPE:
9225            xmlGenericError(xmlGenericErrorContext,
9226                            "           searching for type %d\n", type);
9227            break;
9228        case NODE_TEST_PI:
9229            xmlGenericError(xmlGenericErrorContext,
9230                            "           searching for PI !!!\n");
9231            break;
9232        case NODE_TEST_ALL:
9233            xmlGenericError(xmlGenericErrorContext,
9234                            "           searching for *\n");
9235            break;
9236        case NODE_TEST_NS:
9237            xmlGenericError(xmlGenericErrorContext,
9238                            "           searching for namespace %s\n",
9239                            prefix);
9240            break;
9241        case NODE_TEST_NAME:
9242            xmlGenericError(xmlGenericErrorContext,
9243                            "           searching for name %s\n", name);
9244            if (prefix != NULL)
9245                xmlGenericError(xmlGenericErrorContext,
9246                                "           with namespace %s\n", prefix);
9247            break;
9248    }
9249    xmlGenericError(xmlGenericErrorContext, "Testing : ");
9250#endif
9251    /*
9252     * 2.3 Node Tests
9253     *  - For the attribute axis, the principal node type is attribute.
9254     *  - For the namespace axis, the principal node type is namespace.
9255     *  - For other axes, the principal node type is element.
9256     *
9257     * A node test * is true for any node of the
9258     * principal node type. For example, child::* will
9259     * select all element children of the context node
9260     */
9261    tmp = ctxt->context->node;
9262    for (i = 0; i < nodelist->nodeNr; i++) {
9263        ctxt->context->node = nodelist->nodeTab[i];
9264
9265        cur = NULL;
9266        list = xmlXPathNodeSetCreate(NULL);
9267        do {
9268            cur = next(ctxt, cur);
9269            if (cur == NULL)
9270                break;
9271            if ((first != NULL) && (*first == cur))
9272                break;
9273	    if (((t % 256) == 0) &&
9274	        (first != NULL) && (*first != NULL) &&
9275		(xmlXPathCmpNodes(*first, cur) >= 0))
9276		break;
9277	    if ((last != NULL) && (*last == cur))
9278		break;
9279	    if (((t % 256) == 0) &&
9280		(last != NULL) && (*last != NULL) &&
9281		(xmlXPathCmpNodes(cur, *last) >= 0))
9282		break;
9283            t++;
9284#ifdef DEBUG_STEP
9285            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9286#endif
9287            switch (test) {
9288                case NODE_TEST_NONE:
9289                    ctxt->context->node = tmp;
9290                    STRANGE return(t);
9291                case NODE_TEST_TYPE:
9292                    if ((cur->type == type) ||
9293                        ((type == NODE_TYPE_NODE) &&
9294                         ((cur->type == XML_DOCUMENT_NODE) ||
9295                          (cur->type == XML_HTML_DOCUMENT_NODE) ||
9296                          (cur->type == XML_ELEMENT_NODE) ||
9297                          (cur->type == XML_NAMESPACE_DECL) ||
9298                          (cur->type == XML_ATTRIBUTE_NODE) ||
9299                          (cur->type == XML_PI_NODE) ||
9300                          (cur->type == XML_COMMENT_NODE) ||
9301                          (cur->type == XML_CDATA_SECTION_NODE) ||
9302                          (cur->type == XML_TEXT_NODE))) ||
9303			((type == NODE_TYPE_TEXT) &&
9304			 (cur->type == XML_CDATA_SECTION_NODE))) {
9305#ifdef DEBUG_STEP
9306                        n++;
9307#endif
9308                        addNode(list, cur);
9309                    }
9310                    break;
9311                case NODE_TEST_PI:
9312                    if (cur->type == XML_PI_NODE) {
9313                        if ((name != NULL) &&
9314                            (!xmlStrEqual(name, cur->name)))
9315                            break;
9316#ifdef DEBUG_STEP
9317                        n++;
9318#endif
9319                        addNode(list, cur);
9320                    }
9321                    break;
9322                case NODE_TEST_ALL:
9323                    if (axis == AXIS_ATTRIBUTE) {
9324                        if (cur->type == XML_ATTRIBUTE_NODE) {
9325#ifdef DEBUG_STEP
9326                            n++;
9327#endif
9328                            addNode(list, cur);
9329                        }
9330                    } else if (axis == AXIS_NAMESPACE) {
9331                        if (cur->type == XML_NAMESPACE_DECL) {
9332#ifdef DEBUG_STEP
9333                            n++;
9334#endif
9335                            xmlXPathNodeSetAddNs(list, ctxt->context->node,
9336				                 (xmlNsPtr) cur);
9337                        }
9338                    } else {
9339                        if (cur->type == XML_ELEMENT_NODE) {
9340                            if (prefix == NULL) {
9341#ifdef DEBUG_STEP
9342                                n++;
9343#endif
9344                                addNode(list, cur);
9345                            } else if ((cur->ns != NULL) &&
9346                                       (xmlStrEqual(URI, cur->ns->href))) {
9347#ifdef DEBUG_STEP
9348                                n++;
9349#endif
9350                                addNode(list, cur);
9351                            }
9352                        }
9353                    }
9354                    break;
9355                case NODE_TEST_NS:{
9356                        TODO;
9357                        break;
9358                    }
9359                case NODE_TEST_NAME:
9360                    switch (cur->type) {
9361                        case XML_ELEMENT_NODE:
9362                            if (xmlStrEqual(name, cur->name)) {
9363                                if (prefix == NULL) {
9364                                    if (cur->ns == NULL) {
9365#ifdef DEBUG_STEP
9366                                        n++;
9367#endif
9368                                        addNode(list, cur);
9369                                    }
9370                                } else {
9371                                    if ((cur->ns != NULL) &&
9372                                        (xmlStrEqual(URI,
9373                                                     cur->ns->href))) {
9374#ifdef DEBUG_STEP
9375                                        n++;
9376#endif
9377                                        addNode(list, cur);
9378                                    }
9379                                }
9380                            }
9381                            break;
9382                        case XML_ATTRIBUTE_NODE:{
9383                                xmlAttrPtr attr = (xmlAttrPtr) cur;
9384
9385                                if (xmlStrEqual(name, attr->name)) {
9386                                    if (prefix == NULL) {
9387                                        if ((attr->ns == NULL) ||
9388                                            (attr->ns->prefix == NULL)) {
9389#ifdef DEBUG_STEP
9390                                            n++;
9391#endif
9392                                            addNode(list,
9393                                                    (xmlNodePtr) attr);
9394                                        }
9395                                    } else {
9396                                        if ((attr->ns != NULL) &&
9397                                            (xmlStrEqual(URI,
9398                                                         attr->ns->
9399                                                         href))) {
9400#ifdef DEBUG_STEP
9401                                            n++;
9402#endif
9403                                            addNode(list,
9404                                                    (xmlNodePtr) attr);
9405                                        }
9406                                    }
9407                                }
9408                                break;
9409                            }
9410                        case XML_NAMESPACE_DECL:
9411                            if (cur->type == XML_NAMESPACE_DECL) {
9412                                xmlNsPtr ns = (xmlNsPtr) cur;
9413
9414                                if ((ns->prefix != NULL) && (name != NULL)
9415                                    && (xmlStrEqual(ns->prefix, name))) {
9416#ifdef DEBUG_STEP
9417                                    n++;
9418#endif
9419				    xmlXPathNodeSetAddNs(list,
9420					ctxt->context->node, (xmlNsPtr) cur);
9421                                }
9422                            }
9423                            break;
9424                        default:
9425                            break;
9426                    }
9427                    break;
9428                    break;
9429            }
9430        } while (cur != NULL);
9431
9432        /*
9433         * If there is some predicate filtering do it now
9434         */
9435        if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
9436            xmlXPathObjectPtr obj2;
9437
9438            valuePush(ctxt, xmlXPathWrapNodeSet(list));
9439            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9440            CHECK_TYPE0(XPATH_NODESET);
9441            obj2 = valuePop(ctxt);
9442            list = obj2->nodesetval;
9443            obj2->nodesetval = NULL;
9444            xmlXPathFreeObject(obj2);
9445        }
9446        if (ret == NULL) {
9447            ret = list;
9448        } else {
9449            ret = mergeNodeSet(ret, list);
9450            xmlXPathFreeNodeSet(list);
9451        }
9452    }
9453    ctxt->context->node = tmp;
9454#ifdef DEBUG_STEP
9455    xmlGenericError(xmlGenericErrorContext,
9456                    "\nExamined %d nodes, found %d nodes at that step\n",
9457                    t, n);
9458#endif
9459    valuePush(ctxt, xmlXPathWrapNodeSet(ret));
9460    if ((obj->boolval) && (obj->user != NULL)) {
9461	ctxt->value->boolval = 1;
9462	ctxt->value->user = obj->user;
9463	obj->user = NULL;
9464	obj->boolval = 0;
9465    }
9466    xmlXPathFreeObject(obj);
9467    return(t);
9468}
9469
9470/**
9471 * xmlXPathNodeCollectAndTestNth:
9472 * @ctxt:  the XPath Parser context
9473 * @op:  the XPath precompiled step operation
9474 * @indx:  the index to collect
9475 * @first:  pointer to the first element in document order
9476 * @last:  pointer to the last element in document order
9477 *
9478 * This is the function implementing a step: based on the current list
9479 * of nodes, it builds up a new list, looking at all nodes under that
9480 * axis and selecting them. It also does the predicate filtering
9481 *
9482 * Pushes the new NodeSet resulting from the search.
9483 * Returns the number of node traversed
9484 */
9485static int
9486xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9487                              xmlXPathStepOpPtr op, int indx,
9488                              xmlNodePtr * first, xmlNodePtr * last)
9489{
9490    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9491    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9492    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
9493    const xmlChar *prefix = op->value4;
9494    const xmlChar *name = op->value5;
9495    const xmlChar *URI = NULL;
9496    int n = 0, t = 0;
9497
9498    int i;
9499    xmlNodeSetPtr list;
9500    xmlXPathTraversalFunction next = NULL;
9501    void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9502    xmlNodePtr cur = NULL;
9503    xmlXPathObjectPtr obj;
9504    xmlNodeSetPtr nodelist;
9505    xmlNodePtr tmp;
9506
9507    CHECK_TYPE0(XPATH_NODESET);
9508    obj = valuePop(ctxt);
9509    addNode = xmlXPathNodeSetAdd;
9510    if (prefix != NULL) {
9511        URI = xmlXPathNsLookup(ctxt->context, prefix);
9512        if (URI == NULL)
9513            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9514    }
9515#ifdef DEBUG_STEP_NTH
9516    xmlGenericError(xmlGenericErrorContext, "new step : ");
9517    if (first != NULL) {
9518	if (*first != NULL)
9519	    xmlGenericError(xmlGenericErrorContext, "first = %s ",
9520		    (*first)->name);
9521	else
9522	    xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9523    }
9524    if (last != NULL) {
9525	if (*last != NULL)
9526	    xmlGenericError(xmlGenericErrorContext, "last = %s ",
9527		    (*last)->name);
9528	else
9529	    xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9530    }
9531#endif
9532    switch (axis) {
9533        case AXIS_ANCESTOR:
9534#ifdef DEBUG_STEP_NTH
9535            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9536#endif
9537            first = NULL;
9538            next = xmlXPathNextAncestor;
9539            break;
9540        case AXIS_ANCESTOR_OR_SELF:
9541#ifdef DEBUG_STEP_NTH
9542            xmlGenericError(xmlGenericErrorContext,
9543                            "axis 'ancestors-or-self' ");
9544#endif
9545            first = NULL;
9546            next = xmlXPathNextAncestorOrSelf;
9547            break;
9548        case AXIS_ATTRIBUTE:
9549#ifdef DEBUG_STEP_NTH
9550            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9551#endif
9552            first = NULL;
9553	    last = NULL;
9554            next = xmlXPathNextAttribute;
9555            break;
9556        case AXIS_CHILD:
9557#ifdef DEBUG_STEP_NTH
9558            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9559#endif
9560	    last = NULL;
9561            next = xmlXPathNextChild;
9562            break;
9563        case AXIS_DESCENDANT:
9564#ifdef DEBUG_STEP_NTH
9565            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9566#endif
9567	    last = NULL;
9568            next = xmlXPathNextDescendant;
9569            break;
9570        case AXIS_DESCENDANT_OR_SELF:
9571#ifdef DEBUG_STEP_NTH
9572            xmlGenericError(xmlGenericErrorContext,
9573                            "axis 'descendant-or-self' ");
9574#endif
9575	    last = NULL;
9576            next = xmlXPathNextDescendantOrSelf;
9577            break;
9578        case AXIS_FOLLOWING:
9579#ifdef DEBUG_STEP_NTH
9580            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9581#endif
9582	    last = NULL;
9583            next = xmlXPathNextFollowing;
9584            break;
9585        case AXIS_FOLLOWING_SIBLING:
9586#ifdef DEBUG_STEP_NTH
9587            xmlGenericError(xmlGenericErrorContext,
9588                            "axis 'following-siblings' ");
9589#endif
9590	    last = NULL;
9591            next = xmlXPathNextFollowingSibling;
9592            break;
9593        case AXIS_NAMESPACE:
9594#ifdef DEBUG_STEP_NTH
9595            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9596#endif
9597	    last = NULL;
9598            first = NULL;
9599            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9600            break;
9601        case AXIS_PARENT:
9602#ifdef DEBUG_STEP_NTH
9603            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9604#endif
9605            first = NULL;
9606            next = xmlXPathNextParent;
9607            break;
9608        case AXIS_PRECEDING:
9609#ifdef DEBUG_STEP_NTH
9610            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9611#endif
9612            first = NULL;
9613            next = xmlXPathNextPrecedingInternal;
9614            break;
9615        case AXIS_PRECEDING_SIBLING:
9616#ifdef DEBUG_STEP_NTH
9617            xmlGenericError(xmlGenericErrorContext,
9618                            "axis 'preceding-sibling' ");
9619#endif
9620            first = NULL;
9621            next = xmlXPathNextPrecedingSibling;
9622            break;
9623        case AXIS_SELF:
9624#ifdef DEBUG_STEP_NTH
9625            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9626#endif
9627            first = NULL;
9628	    last = NULL;
9629            next = xmlXPathNextSelf;
9630            break;
9631    }
9632    if (next == NULL)
9633        return(0);
9634
9635    nodelist = obj->nodesetval;
9636    if (nodelist == NULL) {
9637        xmlXPathFreeObject(obj);
9638        valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9639        return(0);
9640    }
9641    addNode = xmlXPathNodeSetAddUnique;
9642#ifdef DEBUG_STEP_NTH
9643    xmlGenericError(xmlGenericErrorContext,
9644                    " context contains %d nodes\n", nodelist->nodeNr);
9645    switch (test) {
9646        case NODE_TEST_NONE:
9647            xmlGenericError(xmlGenericErrorContext,
9648                            "           searching for none !!!\n");
9649            break;
9650        case NODE_TEST_TYPE:
9651            xmlGenericError(xmlGenericErrorContext,
9652                            "           searching for type %d\n", type);
9653            break;
9654        case NODE_TEST_PI:
9655            xmlGenericError(xmlGenericErrorContext,
9656                            "           searching for PI !!!\n");
9657            break;
9658        case NODE_TEST_ALL:
9659            xmlGenericError(xmlGenericErrorContext,
9660                            "           searching for *\n");
9661            break;
9662        case NODE_TEST_NS:
9663            xmlGenericError(xmlGenericErrorContext,
9664                            "           searching for namespace %s\n",
9665                            prefix);
9666            break;
9667        case NODE_TEST_NAME:
9668            xmlGenericError(xmlGenericErrorContext,
9669                            "           searching for name %s\n", name);
9670            if (prefix != NULL)
9671                xmlGenericError(xmlGenericErrorContext,
9672                                "           with namespace %s\n", prefix);
9673            break;
9674    }
9675    xmlGenericError(xmlGenericErrorContext, "Testing : ");
9676#endif
9677    /*
9678     * 2.3 Node Tests
9679     *  - For the attribute axis, the principal node type is attribute.
9680     *  - For the namespace axis, the principal node type is namespace.
9681     *  - For other axes, the principal node type is element.
9682     *
9683     * A node test * is true for any node of the
9684     * principal node type. For example, child::* will
9685     * select all element children of the context node
9686     */
9687    tmp = ctxt->context->node;
9688    list = xmlXPathNodeSetCreate(NULL);
9689    for (i = 0; i < nodelist->nodeNr; i++) {
9690        ctxt->context->node = nodelist->nodeTab[i];
9691
9692        cur = NULL;
9693        n = 0;
9694        do {
9695            cur = next(ctxt, cur);
9696            if (cur == NULL)
9697                break;
9698	    if ((first != NULL) && (*first == cur))
9699		break;
9700	    if (((t % 256) == 0) &&
9701	        (first != NULL) && (*first != NULL) &&
9702		(xmlXPathCmpNodes(*first, cur) >= 0))
9703		break;
9704	    if ((last != NULL) && (*last == cur))
9705		break;
9706	    if (((t % 256) == 0) &&
9707	        (last != NULL) && (*last != NULL) &&
9708		(xmlXPathCmpNodes(cur, *last) >= 0))
9709		break;
9710            t++;
9711            switch (test) {
9712                case NODE_TEST_NONE:
9713                    ctxt->context->node = tmp;
9714                    STRANGE return(0);
9715                case NODE_TEST_TYPE:
9716                    if ((cur->type == type) ||
9717                        ((type == NODE_TYPE_NODE) &&
9718                         ((cur->type == XML_DOCUMENT_NODE) ||
9719                          (cur->type == XML_HTML_DOCUMENT_NODE) ||
9720                          (cur->type == XML_ELEMENT_NODE) ||
9721                          (cur->type == XML_PI_NODE) ||
9722                          (cur->type == XML_COMMENT_NODE) ||
9723                          (cur->type == XML_CDATA_SECTION_NODE) ||
9724                          (cur->type == XML_TEXT_NODE))) ||
9725			((type == NODE_TYPE_TEXT) &&
9726			 (cur->type == XML_CDATA_SECTION_NODE))) {
9727                        n++;
9728                        if (n == indx)
9729                            addNode(list, cur);
9730                    }
9731                    break;
9732                case NODE_TEST_PI:
9733                    if (cur->type == XML_PI_NODE) {
9734                        if ((name != NULL) &&
9735                            (!xmlStrEqual(name, cur->name)))
9736                            break;
9737                        n++;
9738                        if (n == indx)
9739                            addNode(list, cur);
9740                    }
9741                    break;
9742                case NODE_TEST_ALL:
9743                    if (axis == AXIS_ATTRIBUTE) {
9744                        if (cur->type == XML_ATTRIBUTE_NODE) {
9745                            n++;
9746                            if (n == indx)
9747                                addNode(list, cur);
9748                        }
9749                    } else if (axis == AXIS_NAMESPACE) {
9750                        if (cur->type == XML_NAMESPACE_DECL) {
9751                            n++;
9752                            if (n == indx)
9753				xmlXPathNodeSetAddNs(list, ctxt->context->node,
9754						     (xmlNsPtr) cur);
9755                        }
9756                    } else {
9757                        if (cur->type == XML_ELEMENT_NODE) {
9758                            if (prefix == NULL) {
9759                                n++;
9760                                if (n == indx)
9761                                    addNode(list, cur);
9762                            } else if ((cur->ns != NULL) &&
9763                                       (xmlStrEqual(URI, cur->ns->href))) {
9764                                n++;
9765                                if (n == indx)
9766                                    addNode(list, cur);
9767                            }
9768                        }
9769                    }
9770                    break;
9771                case NODE_TEST_NS:{
9772                        TODO;
9773                        break;
9774                    }
9775                case NODE_TEST_NAME:
9776                    switch (cur->type) {
9777                        case XML_ELEMENT_NODE:
9778                            if (xmlStrEqual(name, cur->name)) {
9779                                if (prefix == NULL) {
9780                                    if (cur->ns == NULL) {
9781                                        n++;
9782                                        if (n == indx)
9783                                            addNode(list, cur);
9784                                    }
9785                                } else {
9786                                    if ((cur->ns != NULL) &&
9787                                        (xmlStrEqual(URI,
9788                                                     cur->ns->href))) {
9789                                        n++;
9790                                        if (n == indx)
9791                                            addNode(list, cur);
9792                                    }
9793                                }
9794                            }
9795                            break;
9796                        case XML_ATTRIBUTE_NODE:{
9797                                xmlAttrPtr attr = (xmlAttrPtr) cur;
9798
9799                                if (xmlStrEqual(name, attr->name)) {
9800                                    if (prefix == NULL) {
9801                                        if ((attr->ns == NULL) ||
9802                                            (attr->ns->prefix == NULL)) {
9803                                            n++;
9804                                            if (n == indx)
9805                                                addNode(list, cur);
9806                                        }
9807                                    } else {
9808                                        if ((attr->ns != NULL) &&
9809                                            (xmlStrEqual(URI,
9810                                                         attr->ns->
9811                                                         href))) {
9812                                            n++;
9813                                            if (n == indx)
9814                                                addNode(list, cur);
9815                                        }
9816                                    }
9817                                }
9818                                break;
9819                            }
9820                        case XML_NAMESPACE_DECL:
9821                            if (cur->type == XML_NAMESPACE_DECL) {
9822                                xmlNsPtr ns = (xmlNsPtr) cur;
9823
9824                                if ((ns->prefix != NULL) && (name != NULL)
9825                                    && (xmlStrEqual(ns->prefix, name))) {
9826                                    n++;
9827                                    if (n == indx)
9828					xmlXPathNodeSetAddNs(list,
9829					   ctxt->context->node, (xmlNsPtr) cur);
9830                                }
9831                            }
9832                            break;
9833                        default:
9834                            break;
9835                    }
9836                    break;
9837                    break;
9838            }
9839        } while (n < indx);
9840    }
9841    ctxt->context->node = tmp;
9842#ifdef DEBUG_STEP_NTH
9843    xmlGenericError(xmlGenericErrorContext,
9844                    "\nExamined %d nodes, found %d nodes at that step\n",
9845                    t, list->nodeNr);
9846#endif
9847    valuePush(ctxt, xmlXPathWrapNodeSet(list));
9848    if ((obj->boolval) && (obj->user != NULL)) {
9849	ctxt->value->boolval = 1;
9850	ctxt->value->user = obj->user;
9851	obj->user = NULL;
9852	obj->boolval = 0;
9853    }
9854    xmlXPathFreeObject(obj);
9855    return(t);
9856}
9857
9858/**
9859 * xmlXPathCompOpEvalFirst:
9860 * @ctxt:  the XPath parser context with the compiled expression
9861 * @op:  an XPath compiled operation
9862 * @first:  the first elem found so far
9863 *
9864 * Evaluate the Precompiled XPath operation searching only the first
9865 * element in document order
9866 *
9867 * Returns the number of examined objects.
9868 */
9869static int
9870xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9871                        xmlXPathStepOpPtr op, xmlNodePtr * first)
9872{
9873    int total = 0, cur;
9874    xmlXPathCompExprPtr comp;
9875    xmlXPathObjectPtr arg1, arg2;
9876
9877    CHECK_ERROR0;
9878    comp = ctxt->comp;
9879    switch (op->op) {
9880        case XPATH_OP_END:
9881            return (0);
9882        case XPATH_OP_UNION:
9883            total =
9884                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9885                                        first);
9886	    CHECK_ERROR0;
9887            if ((ctxt->value != NULL)
9888                && (ctxt->value->type == XPATH_NODESET)
9889                && (ctxt->value->nodesetval != NULL)
9890                && (ctxt->value->nodesetval->nodeNr >= 1)) {
9891                /*
9892                 * limit tree traversing to first node in the result
9893                 */
9894                xmlXPathNodeSetSort(ctxt->value->nodesetval);
9895                *first = ctxt->value->nodesetval->nodeTab[0];
9896            }
9897            cur =
9898                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9899                                        first);
9900	    CHECK_ERROR0;
9901            CHECK_TYPE0(XPATH_NODESET);
9902            arg2 = valuePop(ctxt);
9903
9904            CHECK_TYPE0(XPATH_NODESET);
9905            arg1 = valuePop(ctxt);
9906
9907            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9908                                                    arg2->nodesetval);
9909            valuePush(ctxt, arg1);
9910            xmlXPathFreeObject(arg2);
9911            /* optimizer */
9912	    if (total > cur)
9913		xmlXPathCompSwap(op);
9914            return (total + cur);
9915        case XPATH_OP_ROOT:
9916            xmlXPathRoot(ctxt);
9917            return (0);
9918        case XPATH_OP_NODE:
9919            if (op->ch1 != -1)
9920                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9921	    CHECK_ERROR0;
9922            if (op->ch2 != -1)
9923                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9924	    CHECK_ERROR0;
9925            valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9926            return (total);
9927        case XPATH_OP_RESET:
9928            if (op->ch1 != -1)
9929                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9930	    CHECK_ERROR0;
9931            if (op->ch2 != -1)
9932                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9933	    CHECK_ERROR0;
9934            ctxt->context->node = NULL;
9935            return (total);
9936        case XPATH_OP_COLLECT:{
9937                if (op->ch1 == -1)
9938                    return (total);
9939
9940                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9941		CHECK_ERROR0;
9942
9943                /*
9944                 * Optimization for [n] selection where n is a number
9945                 */
9946                if ((op->ch2 != -1) &&
9947                    (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9948                    (comp->steps[op->ch2].ch1 == -1) &&
9949                    (comp->steps[op->ch2].ch2 != -1) &&
9950                    (comp->steps[comp->steps[op->ch2].ch2].op ==
9951                     XPATH_OP_VALUE)) {
9952                    xmlXPathObjectPtr val;
9953
9954                    val = comp->steps[comp->steps[op->ch2].ch2].value4;
9955                    if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9956                        int indx = (int) val->floatval;
9957
9958                        if (val->floatval == (float) indx) {
9959                            xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9960                                                          first, NULL);
9961                            return (total);
9962                        }
9963                    }
9964                }
9965                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9966                return (total);
9967            }
9968        case XPATH_OP_VALUE:
9969            valuePush(ctxt,
9970                      xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9971            return (0);
9972        case XPATH_OP_SORT:
9973            if (op->ch1 != -1)
9974                total +=
9975                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9976                                            first);
9977	    CHECK_ERROR0;
9978            if ((ctxt->value != NULL)
9979                && (ctxt->value->type == XPATH_NODESET)
9980                && (ctxt->value->nodesetval != NULL))
9981                xmlXPathNodeSetSort(ctxt->value->nodesetval);
9982            return (total);
9983        default:
9984            return (xmlXPathCompOpEval(ctxt, op));
9985    }
9986}
9987
9988/**
9989 * xmlXPathCompOpEvalLast:
9990 * @ctxt:  the XPath parser context with the compiled expression
9991 * @op:  an XPath compiled operation
9992 * @last:  the last elem found so far
9993 *
9994 * Evaluate the Precompiled XPath operation searching only the last
9995 * element in document order
9996 *
9997 * Returns the number of nodes traversed
9998 */
9999static int
10000xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
10001                       xmlNodePtr * last)
10002{
10003    int total = 0, cur;
10004    xmlXPathCompExprPtr comp;
10005    xmlXPathObjectPtr arg1, arg2;
10006    xmlNodePtr bak;
10007    xmlDocPtr bakd;
10008    int pp;
10009    int cs;
10010
10011    CHECK_ERROR0;
10012    comp = ctxt->comp;
10013    switch (op->op) {
10014        case XPATH_OP_END:
10015            return (0);
10016        case XPATH_OP_UNION:
10017	    bakd = ctxt->context->doc;
10018	    bak = ctxt->context->node;
10019	    pp = ctxt->context->proximityPosition;
10020	    cs = ctxt->context->contextSize;
10021            total =
10022                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
10023	    CHECK_ERROR0;
10024            if ((ctxt->value != NULL)
10025                && (ctxt->value->type == XPATH_NODESET)
10026                && (ctxt->value->nodesetval != NULL)
10027                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10028                /*
10029                 * limit tree traversing to first node in the result
10030                 */
10031                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10032                *last =
10033                    ctxt->value->nodesetval->nodeTab[ctxt->value->
10034                                                     nodesetval->nodeNr -
10035                                                     1];
10036            }
10037	    ctxt->context->doc = bakd;
10038	    ctxt->context->node = bak;
10039	    ctxt->context->proximityPosition = pp;
10040	    ctxt->context->contextSize = cs;
10041            cur =
10042                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
10043	    CHECK_ERROR0;
10044            if ((ctxt->value != NULL)
10045                && (ctxt->value->type == XPATH_NODESET)
10046                && (ctxt->value->nodesetval != NULL)
10047                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10048            }
10049            CHECK_TYPE0(XPATH_NODESET);
10050            arg2 = valuePop(ctxt);
10051
10052            CHECK_TYPE0(XPATH_NODESET);
10053            arg1 = valuePop(ctxt);
10054
10055            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10056                                                    arg2->nodesetval);
10057            valuePush(ctxt, arg1);
10058            xmlXPathFreeObject(arg2);
10059            /* optimizer */
10060	    if (total > cur)
10061		xmlXPathCompSwap(op);
10062            return (total + cur);
10063        case XPATH_OP_ROOT:
10064            xmlXPathRoot(ctxt);
10065            return (0);
10066        case XPATH_OP_NODE:
10067            if (op->ch1 != -1)
10068                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10069	    CHECK_ERROR0;
10070            if (op->ch2 != -1)
10071                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10072	    CHECK_ERROR0;
10073            valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10074            return (total);
10075        case XPATH_OP_RESET:
10076            if (op->ch1 != -1)
10077                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10078	    CHECK_ERROR0;
10079            if (op->ch2 != -1)
10080                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10081	    CHECK_ERROR0;
10082            ctxt->context->node = NULL;
10083            return (total);
10084        case XPATH_OP_COLLECT:{
10085                if (op->ch1 == -1)
10086                    return (0);
10087
10088                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10089		CHECK_ERROR0;
10090
10091                /*
10092                 * Optimization for [n] selection where n is a number
10093                 */
10094                if ((op->ch2 != -1) &&
10095                    (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10096                    (comp->steps[op->ch2].ch1 == -1) &&
10097                    (comp->steps[op->ch2].ch2 != -1) &&
10098                    (comp->steps[comp->steps[op->ch2].ch2].op ==
10099                     XPATH_OP_VALUE)) {
10100                    xmlXPathObjectPtr val;
10101
10102                    val = comp->steps[comp->steps[op->ch2].ch2].value4;
10103                    if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10104                        int indx = (int) val->floatval;
10105
10106                        if (val->floatval == (float) indx) {
10107                            total +=
10108                                xmlXPathNodeCollectAndTestNth(ctxt, op,
10109                                                              indx, NULL,
10110                                                              last);
10111                            return (total);
10112                        }
10113                    }
10114                }
10115                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10116                return (total);
10117            }
10118        case XPATH_OP_VALUE:
10119            valuePush(ctxt,
10120                      xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10121            return (0);
10122        case XPATH_OP_SORT:
10123            if (op->ch1 != -1)
10124                total +=
10125                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10126                                           last);
10127	    CHECK_ERROR0;
10128            if ((ctxt->value != NULL)
10129                && (ctxt->value->type == XPATH_NODESET)
10130                && (ctxt->value->nodesetval != NULL))
10131                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10132            return (total);
10133        default:
10134            return (xmlXPathCompOpEval(ctxt, op));
10135    }
10136}
10137
10138/**
10139 * xmlXPathCompOpEval:
10140 * @ctxt:  the XPath parser context with the compiled expression
10141 * @op:  an XPath compiled operation
10142 *
10143 * Evaluate the Precompiled XPath operation
10144 * Returns the number of nodes traversed
10145 */
10146static int
10147xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10148{
10149    int total = 0;
10150    int equal, ret;
10151    xmlXPathCompExprPtr comp;
10152    xmlXPathObjectPtr arg1, arg2;
10153    xmlNodePtr bak;
10154    xmlDocPtr bakd;
10155    int pp;
10156    int cs;
10157
10158    CHECK_ERROR0;
10159    comp = ctxt->comp;
10160    switch (op->op) {
10161        case XPATH_OP_END:
10162            return (0);
10163        case XPATH_OP_AND:
10164	    bakd = ctxt->context->doc;
10165	    bak = ctxt->context->node;
10166	    pp = ctxt->context->proximityPosition;
10167	    cs = ctxt->context->contextSize;
10168            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10169	    CHECK_ERROR0;
10170            xmlXPathBooleanFunction(ctxt, 1);
10171            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10172                return (total);
10173            arg2 = valuePop(ctxt);
10174	    ctxt->context->doc = bakd;
10175	    ctxt->context->node = bak;
10176	    ctxt->context->proximityPosition = pp;
10177	    ctxt->context->contextSize = cs;
10178            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10179	    if (ctxt->error) {
10180		xmlXPathFreeObject(arg2);
10181		return(0);
10182	    }
10183            xmlXPathBooleanFunction(ctxt, 1);
10184            arg1 = valuePop(ctxt);
10185            arg1->boolval &= arg2->boolval;
10186            valuePush(ctxt, arg1);
10187            xmlXPathFreeObject(arg2);
10188            return (total);
10189        case XPATH_OP_OR:
10190	    bakd = ctxt->context->doc;
10191	    bak = ctxt->context->node;
10192	    pp = ctxt->context->proximityPosition;
10193	    cs = ctxt->context->contextSize;
10194            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10195	    CHECK_ERROR0;
10196            xmlXPathBooleanFunction(ctxt, 1);
10197            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10198                return (total);
10199            arg2 = valuePop(ctxt);
10200	    ctxt->context->doc = bakd;
10201	    ctxt->context->node = bak;
10202	    ctxt->context->proximityPosition = pp;
10203	    ctxt->context->contextSize = cs;
10204            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10205	    if (ctxt->error) {
10206		xmlXPathFreeObject(arg2);
10207		return(0);
10208	    }
10209            xmlXPathBooleanFunction(ctxt, 1);
10210            arg1 = valuePop(ctxt);
10211            arg1->boolval |= arg2->boolval;
10212            valuePush(ctxt, arg1);
10213            xmlXPathFreeObject(arg2);
10214            return (total);
10215        case XPATH_OP_EQUAL:
10216	    bakd = ctxt->context->doc;
10217	    bak = ctxt->context->node;
10218	    pp = ctxt->context->proximityPosition;
10219	    cs = ctxt->context->contextSize;
10220            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10221	    CHECK_ERROR0;
10222	    ctxt->context->doc = bakd;
10223	    ctxt->context->node = bak;
10224	    ctxt->context->proximityPosition = pp;
10225	    ctxt->context->contextSize = cs;
10226            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10227	    CHECK_ERROR0;
10228	    if (op->value)
10229        	equal = xmlXPathEqualValues(ctxt);
10230	    else
10231		equal = xmlXPathNotEqualValues(ctxt);
10232	    valuePush(ctxt, xmlXPathNewBoolean(equal));
10233            return (total);
10234        case XPATH_OP_CMP:
10235	    bakd = ctxt->context->doc;
10236	    bak = ctxt->context->node;
10237	    pp = ctxt->context->proximityPosition;
10238	    cs = ctxt->context->contextSize;
10239            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10240	    CHECK_ERROR0;
10241	    ctxt->context->doc = bakd;
10242	    ctxt->context->node = bak;
10243	    ctxt->context->proximityPosition = pp;
10244	    ctxt->context->contextSize = cs;
10245            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10246	    CHECK_ERROR0;
10247            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10248            valuePush(ctxt, xmlXPathNewBoolean(ret));
10249            return (total);
10250        case XPATH_OP_PLUS:
10251	    bakd = ctxt->context->doc;
10252	    bak = ctxt->context->node;
10253	    pp = ctxt->context->proximityPosition;
10254	    cs = ctxt->context->contextSize;
10255            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10256	    CHECK_ERROR0;
10257            if (op->ch2 != -1) {
10258		ctxt->context->doc = bakd;
10259		ctxt->context->node = bak;
10260		ctxt->context->proximityPosition = pp;
10261		ctxt->context->contextSize = cs;
10262                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10263	    }
10264	    CHECK_ERROR0;
10265            if (op->value == 0)
10266                xmlXPathSubValues(ctxt);
10267            else if (op->value == 1)
10268                xmlXPathAddValues(ctxt);
10269            else if (op->value == 2)
10270                xmlXPathValueFlipSign(ctxt);
10271            else if (op->value == 3) {
10272                CAST_TO_NUMBER;
10273                CHECK_TYPE0(XPATH_NUMBER);
10274            }
10275            return (total);
10276        case XPATH_OP_MULT:
10277	    bakd = ctxt->context->doc;
10278	    bak = ctxt->context->node;
10279	    pp = ctxt->context->proximityPosition;
10280	    cs = ctxt->context->contextSize;
10281            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10282	    CHECK_ERROR0;
10283	    ctxt->context->doc = bakd;
10284	    ctxt->context->node = bak;
10285	    ctxt->context->proximityPosition = pp;
10286	    ctxt->context->contextSize = cs;
10287            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10288	    CHECK_ERROR0;
10289            if (op->value == 0)
10290                xmlXPathMultValues(ctxt);
10291            else if (op->value == 1)
10292                xmlXPathDivValues(ctxt);
10293            else if (op->value == 2)
10294                xmlXPathModValues(ctxt);
10295            return (total);
10296        case XPATH_OP_UNION:
10297	    bakd = ctxt->context->doc;
10298	    bak = ctxt->context->node;
10299	    pp = ctxt->context->proximityPosition;
10300	    cs = ctxt->context->contextSize;
10301            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10302	    CHECK_ERROR0;
10303	    ctxt->context->doc = bakd;
10304	    ctxt->context->node = bak;
10305	    ctxt->context->proximityPosition = pp;
10306	    ctxt->context->contextSize = cs;
10307            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10308	    CHECK_ERROR0;
10309            CHECK_TYPE0(XPATH_NODESET);
10310            arg2 = valuePop(ctxt);
10311
10312            CHECK_TYPE0(XPATH_NODESET);
10313            arg1 = valuePop(ctxt);
10314
10315            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10316                                                    arg2->nodesetval);
10317            valuePush(ctxt, arg1);
10318            xmlXPathFreeObject(arg2);
10319            return (total);
10320        case XPATH_OP_ROOT:
10321            xmlXPathRoot(ctxt);
10322            return (total);
10323        case XPATH_OP_NODE:
10324            if (op->ch1 != -1)
10325                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10326	    CHECK_ERROR0;
10327            if (op->ch2 != -1)
10328                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10329	    CHECK_ERROR0;
10330            valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10331            return (total);
10332        case XPATH_OP_RESET:
10333            if (op->ch1 != -1)
10334                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10335	    CHECK_ERROR0;
10336            if (op->ch2 != -1)
10337                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10338	    CHECK_ERROR0;
10339            ctxt->context->node = NULL;
10340            return (total);
10341        case XPATH_OP_COLLECT:{
10342                if (op->ch1 == -1)
10343                    return (total);
10344
10345                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10346		CHECK_ERROR0;
10347
10348                /*
10349                 * Optimization for [n] selection where n is a number
10350                 */
10351                if ((op->ch2 != -1) &&
10352                    (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10353                    (comp->steps[op->ch2].ch1 == -1) &&
10354                    (comp->steps[op->ch2].ch2 != -1) &&
10355                    (comp->steps[comp->steps[op->ch2].ch2].op ==
10356                     XPATH_OP_VALUE)) {
10357                    xmlXPathObjectPtr val;
10358
10359                    val = comp->steps[comp->steps[op->ch2].ch2].value4;
10360                    if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10361                        int indx = (int) val->floatval;
10362
10363                        if (val->floatval == (float) indx) {
10364                            total +=
10365                                xmlXPathNodeCollectAndTestNth(ctxt, op,
10366                                                              indx, NULL,
10367                                                              NULL);
10368                            return (total);
10369                        }
10370                    }
10371                }
10372                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10373                return (total);
10374            }
10375        case XPATH_OP_VALUE:
10376            valuePush(ctxt,
10377                      xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10378            return (total);
10379        case XPATH_OP_VARIABLE:{
10380		xmlXPathObjectPtr val;
10381
10382                if (op->ch1 != -1)
10383                    total +=
10384                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10385                if (op->value5 == NULL) {
10386		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
10387		    if (val == NULL) {
10388			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10389			return(0);
10390		    }
10391                    valuePush(ctxt, val);
10392		} else {
10393                    const xmlChar *URI;
10394
10395                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
10396                    if (URI == NULL) {
10397                        xmlGenericError(xmlGenericErrorContext,
10398                                        "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
10399                                        op->value4, op->value5);
10400                        return (total);
10401                    }
10402		    val = xmlXPathVariableLookupNS(ctxt->context,
10403                                                       op->value4, URI);
10404		    if (val == NULL) {
10405			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10406			return(0);
10407		    }
10408                    valuePush(ctxt, val);
10409                }
10410                return (total);
10411            }
10412        case XPATH_OP_FUNCTION:{
10413                xmlXPathFunction func;
10414                const xmlChar *oldFunc, *oldFuncURI;
10415		int i;
10416
10417                if (op->ch1 != -1)
10418                    total +=
10419                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10420		if (ctxt->valueNr < op->value) {
10421		    xmlGenericError(xmlGenericErrorContext,
10422			    "xmlXPathCompOpEval: parameter error\n");
10423		    ctxt->error = XPATH_INVALID_OPERAND;
10424		    return (total);
10425		}
10426		for (i = 0; i < op->value; i++)
10427		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10428			xmlGenericError(xmlGenericErrorContext,
10429				"xmlXPathCompOpEval: parameter error\n");
10430			ctxt->error = XPATH_INVALID_OPERAND;
10431			return (total);
10432		    }
10433                if (op->cache != NULL)
10434                    XML_CAST_FPTR(func) = op->cache;
10435                else {
10436                    const xmlChar *URI = NULL;
10437
10438                    if (op->value5 == NULL)
10439                        func =
10440                            xmlXPathFunctionLookup(ctxt->context,
10441                                                   op->value4);
10442                    else {
10443                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
10444                        if (URI == NULL) {
10445                            xmlGenericError(xmlGenericErrorContext,
10446                                            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
10447                                            op->value4, op->value5);
10448                            return (total);
10449                        }
10450                        func = xmlXPathFunctionLookupNS(ctxt->context,
10451                                                        op->value4, URI);
10452                    }
10453                    if (func == NULL) {
10454                        xmlGenericError(xmlGenericErrorContext,
10455                                        "xmlXPathCompOpEval: function %s not found\n",
10456                                        op->value4);
10457                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
10458                    }
10459                    op->cache = XML_CAST_FPTR(func);
10460                    op->cacheURI = (void *) URI;
10461                }
10462                oldFunc = ctxt->context->function;
10463                oldFuncURI = ctxt->context->functionURI;
10464                ctxt->context->function = op->value4;
10465                ctxt->context->functionURI = op->cacheURI;
10466                func(ctxt, op->value);
10467                ctxt->context->function = oldFunc;
10468                ctxt->context->functionURI = oldFuncURI;
10469                return (total);
10470            }
10471        case XPATH_OP_ARG:
10472	    bakd = ctxt->context->doc;
10473	    bak = ctxt->context->node;
10474	    pp = ctxt->context->proximityPosition;
10475	    cs = ctxt->context->contextSize;
10476            if (op->ch1 != -1)
10477                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10478	    ctxt->context->contextSize = cs;
10479	    ctxt->context->proximityPosition = pp;
10480	    ctxt->context->node = bak;
10481	    ctxt->context->doc = bakd;
10482	    CHECK_ERROR0;
10483            if (op->ch2 != -1) {
10484                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10485	        ctxt->context->doc = bakd;
10486	        ctxt->context->node = bak;
10487	        CHECK_ERROR0;
10488	    }
10489            return (total);
10490        case XPATH_OP_PREDICATE:
10491        case XPATH_OP_FILTER:{
10492                xmlXPathObjectPtr res;
10493                xmlXPathObjectPtr obj, tmp;
10494                xmlNodeSetPtr newset = NULL;
10495                xmlNodeSetPtr oldset;
10496                xmlNodePtr oldnode;
10497		xmlDocPtr oldDoc;
10498                int i;
10499
10500                /*
10501                 * Optimization for ()[1] selection i.e. the first elem
10502                 */
10503                if ((op->ch1 != -1) && (op->ch2 != -1) &&
10504                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10505                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10506                    xmlXPathObjectPtr val;
10507
10508                    val = comp->steps[op->ch2].value4;
10509                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10510                        (val->floatval == 1.0)) {
10511                        xmlNodePtr first = NULL;
10512
10513                        total +=
10514                            xmlXPathCompOpEvalFirst(ctxt,
10515                                                    &comp->steps[op->ch1],
10516                                                    &first);
10517			CHECK_ERROR0;
10518                        /*
10519                         * The nodeset should be in document order,
10520                         * Keep only the first value
10521                         */
10522                        if ((ctxt->value != NULL) &&
10523                            (ctxt->value->type == XPATH_NODESET) &&
10524                            (ctxt->value->nodesetval != NULL) &&
10525                            (ctxt->value->nodesetval->nodeNr > 1))
10526                            ctxt->value->nodesetval->nodeNr = 1;
10527                        return (total);
10528                    }
10529                }
10530                /*
10531                 * Optimization for ()[last()] selection i.e. the last elem
10532                 */
10533                if ((op->ch1 != -1) && (op->ch2 != -1) &&
10534                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10535                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10536                    int f = comp->steps[op->ch2].ch1;
10537
10538                    if ((f != -1) &&
10539                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10540                        (comp->steps[f].value5 == NULL) &&
10541                        (comp->steps[f].value == 0) &&
10542                        (comp->steps[f].value4 != NULL) &&
10543                        (xmlStrEqual
10544                         (comp->steps[f].value4, BAD_CAST "last"))) {
10545                        xmlNodePtr last = NULL;
10546
10547                        total +=
10548                            xmlXPathCompOpEvalLast(ctxt,
10549                                                   &comp->steps[op->ch1],
10550                                                   &last);
10551			CHECK_ERROR0;
10552                        /*
10553                         * The nodeset should be in document order,
10554                         * Keep only the last value
10555                         */
10556                        if ((ctxt->value != NULL) &&
10557                            (ctxt->value->type == XPATH_NODESET) &&
10558                            (ctxt->value->nodesetval != NULL) &&
10559                            (ctxt->value->nodesetval->nodeTab != NULL) &&
10560                            (ctxt->value->nodesetval->nodeNr > 1)) {
10561                            ctxt->value->nodesetval->nodeTab[0] =
10562                                ctxt->value->nodesetval->nodeTab[ctxt->
10563                                                                 value->
10564                                                                 nodesetval->
10565                                                                 nodeNr -
10566                                                                 1];
10567                            ctxt->value->nodesetval->nodeNr = 1;
10568                        }
10569                        return (total);
10570                    }
10571                }
10572
10573                if (op->ch1 != -1)
10574                    total +=
10575                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10576		CHECK_ERROR0;
10577                if (op->ch2 == -1)
10578                    return (total);
10579                if (ctxt->value == NULL)
10580                    return (total);
10581
10582                oldnode = ctxt->context->node;
10583
10584#ifdef LIBXML_XPTR_ENABLED
10585                /*
10586                 * Hum are we filtering the result of an XPointer expression
10587                 */
10588                if (ctxt->value->type == XPATH_LOCATIONSET) {
10589                    xmlLocationSetPtr newlocset = NULL;
10590                    xmlLocationSetPtr oldlocset;
10591
10592                    /*
10593                     * Extract the old locset, and then evaluate the result of the
10594                     * expression for all the element in the locset. use it to grow
10595                     * up a new locset.
10596                     */
10597                    CHECK_TYPE0(XPATH_LOCATIONSET);
10598                    obj = valuePop(ctxt);
10599                    oldlocset = obj->user;
10600                    ctxt->context->node = NULL;
10601
10602                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10603                        ctxt->context->contextSize = 0;
10604                        ctxt->context->proximityPosition = 0;
10605                        if (op->ch2 != -1)
10606                            total +=
10607                                xmlXPathCompOpEval(ctxt,
10608                                                   &comp->steps[op->ch2]);
10609                        res = valuePop(ctxt);
10610                        if (res != NULL)
10611                            xmlXPathFreeObject(res);
10612                        valuePush(ctxt, obj);
10613                        CHECK_ERROR0;
10614                        return (total);
10615                    }
10616                    newlocset = xmlXPtrLocationSetCreate(NULL);
10617
10618                    for (i = 0; i < oldlocset->locNr; i++) {
10619                        /*
10620                         * Run the evaluation with a node list made of a
10621                         * single item in the nodelocset.
10622                         */
10623                        ctxt->context->node = oldlocset->locTab[i]->user;
10624                        ctxt->context->contextSize = oldlocset->locNr;
10625                        ctxt->context->proximityPosition = i + 1;
10626                        tmp = xmlXPathNewNodeSet(ctxt->context->node);
10627                        valuePush(ctxt, tmp);
10628
10629                        if (op->ch2 != -1)
10630                            total +=
10631                                xmlXPathCompOpEval(ctxt,
10632                                                   &comp->steps[op->ch2]);
10633                        CHECK_ERROR0;
10634
10635                        /*
10636                         * The result of the evaluation need to be tested to
10637                         * decided whether the filter succeeded or not
10638                         */
10639                        res = valuePop(ctxt);
10640                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10641                            xmlXPtrLocationSetAdd(newlocset,
10642                                                  xmlXPathObjectCopy
10643                                                  (oldlocset->locTab[i]));
10644                        }
10645
10646                        /*
10647                         * Cleanup
10648                         */
10649                        if (res != NULL)
10650                            xmlXPathFreeObject(res);
10651                        if (ctxt->value == tmp) {
10652                            res = valuePop(ctxt);
10653                            xmlXPathFreeObject(res);
10654                        }
10655
10656                        ctxt->context->node = NULL;
10657                    }
10658
10659                    /*
10660                     * The result is used as the new evaluation locset.
10661                     */
10662                    xmlXPathFreeObject(obj);
10663                    ctxt->context->node = NULL;
10664                    ctxt->context->contextSize = -1;
10665                    ctxt->context->proximityPosition = -1;
10666                    valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10667                    ctxt->context->node = oldnode;
10668                    return (total);
10669                }
10670#endif /* LIBXML_XPTR_ENABLED */
10671
10672                /*
10673                 * Extract the old set, and then evaluate the result of the
10674                 * expression for all the element in the set. use it to grow
10675                 * up a new set.
10676                 */
10677                CHECK_TYPE0(XPATH_NODESET);
10678                obj = valuePop(ctxt);
10679                oldset = obj->nodesetval;
10680
10681                oldnode = ctxt->context->node;
10682		oldDoc = ctxt->context->doc;
10683                ctxt->context->node = NULL;
10684
10685                if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10686                    ctxt->context->contextSize = 0;
10687                    ctxt->context->proximityPosition = 0;
10688/*
10689                    if (op->ch2 != -1)
10690                        total +=
10691                            xmlXPathCompOpEval(ctxt,
10692                                               &comp->steps[op->ch2]);
10693		    CHECK_ERROR0;
10694                    res = valuePop(ctxt);
10695                    if (res != NULL)
10696                        xmlXPathFreeObject(res);
10697*/
10698                    valuePush(ctxt, obj);
10699                    ctxt->context->node = oldnode;
10700                    CHECK_ERROR0;
10701                } else {
10702                    /*
10703                     * Initialize the new set.
10704		     * Also set the xpath document in case things like
10705		     * key() evaluation are attempted on the predicate
10706                     */
10707                    newset = xmlXPathNodeSetCreate(NULL);
10708
10709                    for (i = 0; i < oldset->nodeNr; i++) {
10710                        /*
10711                         * Run the evaluation with a node list made of
10712                         * a single item in the nodeset.
10713                         */
10714                        ctxt->context->node = oldset->nodeTab[i];
10715			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10716			    (oldset->nodeTab[i]->doc != NULL))
10717		            ctxt->context->doc = oldset->nodeTab[i]->doc;
10718                        tmp = xmlXPathNewNodeSet(ctxt->context->node);
10719                        valuePush(ctxt, tmp);
10720                        ctxt->context->contextSize = oldset->nodeNr;
10721                        ctxt->context->proximityPosition = i + 1;
10722
10723                        if (op->ch2 != -1)
10724                            total +=
10725                                xmlXPathCompOpEval(ctxt,
10726                                                   &comp->steps[op->ch2]);
10727                        CHECK_ERROR0;
10728
10729                        /*
10730                         * The result of the evaluation needs to be tested to
10731                         * decide whether the filter succeeded or not
10732                         */
10733                        res = valuePop(ctxt);
10734                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10735                            xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10736                        }
10737
10738                        /*
10739                         * Cleanup
10740                         */
10741                        if (res != NULL)
10742                            xmlXPathFreeObject(res);
10743                        if (ctxt->value == tmp) {
10744                            res = valuePop(ctxt);
10745                            xmlXPathFreeObject(res);
10746                        }
10747
10748                        ctxt->context->node = NULL;
10749                    }
10750
10751                    /*
10752                     * The result is used as the new evaluation set.
10753                     */
10754                    xmlXPathFreeObject(obj);
10755                    ctxt->context->node = NULL;
10756                    ctxt->context->contextSize = -1;
10757                    ctxt->context->proximityPosition = -1;
10758		    /* may want to move this past the '}' later */
10759		    ctxt->context->doc = oldDoc;
10760                    valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10761                }
10762                ctxt->context->node = oldnode;
10763                return (total);
10764            }
10765        case XPATH_OP_SORT:
10766            if (op->ch1 != -1)
10767                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10768	    CHECK_ERROR0;
10769            if ((ctxt->value != NULL) &&
10770                (ctxt->value->type == XPATH_NODESET) &&
10771                (ctxt->value->nodesetval != NULL))
10772                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10773            return (total);
10774#ifdef LIBXML_XPTR_ENABLED
10775        case XPATH_OP_RANGETO:{
10776                xmlXPathObjectPtr range;
10777                xmlXPathObjectPtr res, obj;
10778                xmlXPathObjectPtr tmp;
10779                xmlLocationSetPtr newlocset = NULL;
10780		    xmlLocationSetPtr oldlocset;
10781                xmlNodeSetPtr oldset;
10782                int i, j;
10783
10784                if (op->ch1 != -1)
10785                    total +=
10786                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10787                if (op->ch2 == -1)
10788                    return (total);
10789
10790                if (ctxt->value->type == XPATH_LOCATIONSET) {
10791                    /*
10792                     * Extract the old locset, and then evaluate the result of the
10793                     * expression for all the element in the locset. use it to grow
10794                     * up a new locset.
10795                     */
10796                    CHECK_TYPE0(XPATH_LOCATIONSET);
10797                    obj = valuePop(ctxt);
10798                    oldlocset = obj->user;
10799
10800                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10801		        ctxt->context->node = NULL;
10802                        ctxt->context->contextSize = 0;
10803                        ctxt->context->proximityPosition = 0;
10804                        total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10805                        res = valuePop(ctxt);
10806                        if (res != NULL)
10807                            xmlXPathFreeObject(res);
10808                        valuePush(ctxt, obj);
10809                        CHECK_ERROR0;
10810                        return (total);
10811                    }
10812                    newlocset = xmlXPtrLocationSetCreate(NULL);
10813
10814                    for (i = 0; i < oldlocset->locNr; i++) {
10815                        /*
10816                         * Run the evaluation with a node list made of a
10817                         * single item in the nodelocset.
10818                         */
10819                        ctxt->context->node = oldlocset->locTab[i]->user;
10820                        ctxt->context->contextSize = oldlocset->locNr;
10821                        ctxt->context->proximityPosition = i + 1;
10822                        tmp = xmlXPathNewNodeSet(ctxt->context->node);
10823                        valuePush(ctxt, tmp);
10824
10825                        if (op->ch2 != -1)
10826                            total +=
10827                                xmlXPathCompOpEval(ctxt,
10828                                                   &comp->steps[op->ch2]);
10829                        CHECK_ERROR0;
10830
10831                        res = valuePop(ctxt);
10832			if (res->type == XPATH_LOCATIONSET) {
10833			    xmlLocationSetPtr rloc =
10834			        (xmlLocationSetPtr)res->user;
10835			    for (j=0; j<rloc->locNr; j++) {
10836			        range = xmlXPtrNewRange(
10837				  oldlocset->locTab[i]->user,
10838				  oldlocset->locTab[i]->index,
10839				  rloc->locTab[j]->user2,
10840				  rloc->locTab[j]->index2);
10841				if (range != NULL) {
10842				    xmlXPtrLocationSetAdd(newlocset, range);
10843				}
10844			    }
10845			} else {
10846			    range = xmlXPtrNewRangeNodeObject(
10847				(xmlNodePtr)oldlocset->locTab[i]->user, res);
10848                            if (range != NULL) {
10849                                xmlXPtrLocationSetAdd(newlocset,range);
10850			    }
10851                        }
10852
10853                        /*
10854                         * Cleanup
10855                         */
10856                        if (res != NULL)
10857                            xmlXPathFreeObject(res);
10858                        if (ctxt->value == tmp) {
10859                            res = valuePop(ctxt);
10860                            xmlXPathFreeObject(res);
10861                        }
10862
10863                        ctxt->context->node = NULL;
10864                    }
10865		} else {	/* Not a location set */
10866                    CHECK_TYPE0(XPATH_NODESET);
10867                    obj = valuePop(ctxt);
10868                    oldset = obj->nodesetval;
10869                    ctxt->context->node = NULL;
10870
10871                    newlocset = xmlXPtrLocationSetCreate(NULL);
10872
10873                    if (oldset != NULL) {
10874                        for (i = 0; i < oldset->nodeNr; i++) {
10875                            /*
10876                             * Run the evaluation with a node list made of a single item
10877                             * in the nodeset.
10878                             */
10879                            ctxt->context->node = oldset->nodeTab[i];
10880                            tmp = xmlXPathNewNodeSet(ctxt->context->node);
10881                            valuePush(ctxt, tmp);
10882
10883                            if (op->ch2 != -1)
10884                                total +=
10885                                    xmlXPathCompOpEval(ctxt,
10886                                                   &comp->steps[op->ch2]);
10887                            CHECK_ERROR0;
10888
10889                            res = valuePop(ctxt);
10890                            range =
10891                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10892                                                      res);
10893                            if (range != NULL) {
10894                                xmlXPtrLocationSetAdd(newlocset, range);
10895                            }
10896
10897                            /*
10898                             * Cleanup
10899                             */
10900                            if (res != NULL)
10901                                xmlXPathFreeObject(res);
10902                            if (ctxt->value == tmp) {
10903                                res = valuePop(ctxt);
10904                                xmlXPathFreeObject(res);
10905                            }
10906
10907                            ctxt->context->node = NULL;
10908                        }
10909                    }
10910                }
10911
10912                /*
10913                 * The result is used as the new evaluation set.
10914                 */
10915                xmlXPathFreeObject(obj);
10916                ctxt->context->node = NULL;
10917                ctxt->context->contextSize = -1;
10918                ctxt->context->proximityPosition = -1;
10919                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10920                return (total);
10921            }
10922#endif /* LIBXML_XPTR_ENABLED */
10923    }
10924    xmlGenericError(xmlGenericErrorContext,
10925                    "XPath: unknown precompiled operation %d\n", op->op);
10926    return (total);
10927}
10928
10929#ifdef XPATH_STREAMING
10930/**
10931 * xmlXPathRunStreamEval:
10932 * @ctxt:  the XPath parser context with the compiled expression
10933 *
10934 * Evaluate the Precompiled Streamable XPath expression in the given context.
10935 */
10936static xmlXPathObjectPtr
10937xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
10938    int max_depth;
10939    int from_root;
10940    int ret, depth;
10941    xmlNodePtr cur = NULL, limit = NULL;
10942    xmlXPathObjectPtr retval;
10943    xmlStreamCtxtPtr patstream;
10944
10945    int nb_nodes = 0;
10946
10947    if ((ctxt == NULL) || (comp == NULL))
10948        return(NULL);
10949    max_depth = xmlPatternMaxDepth(comp);
10950    if (max_depth == -1)
10951        return(NULL);
10952    if (max_depth == -2)
10953        max_depth = 10000;
10954    from_root = xmlPatternFromRoot(comp);
10955    if (from_root < 0)
10956        return(NULL);
10957#if 0
10958    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
10959#endif
10960
10961    retval = xmlXPathNewNodeSet(NULL);
10962    if (retval == NULL)
10963        return(NULL);
10964
10965    if ((from_root) && (max_depth == 0)) {
10966	xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
10967	return(retval);
10968    } else if (max_depth == 0) {
10969	xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
10970	return(retval);
10971    }
10972    if (from_root) {
10973        cur = (xmlNodePtr)ctxt->doc;
10974    } else if (ctxt->node != NULL) {
10975        switch (ctxt->node->type) {
10976            case XML_ELEMENT_NODE:
10977            case XML_DOCUMENT_NODE:
10978            case XML_DOCUMENT_FRAG_NODE:
10979            case XML_HTML_DOCUMENT_NODE:
10980#ifdef LIBXML_DOCB_ENABLED
10981            case XML_DOCB_DOCUMENT_NODE:
10982#endif
10983	        cur = ctxt->node;
10984		break;
10985            case XML_ATTRIBUTE_NODE:
10986            case XML_TEXT_NODE:
10987            case XML_CDATA_SECTION_NODE:
10988            case XML_ENTITY_REF_NODE:
10989            case XML_ENTITY_NODE:
10990            case XML_PI_NODE:
10991            case XML_COMMENT_NODE:
10992            case XML_NOTATION_NODE:
10993            case XML_DTD_NODE:
10994            case XML_DOCUMENT_TYPE_NODE:
10995            case XML_ELEMENT_DECL:
10996            case XML_ATTRIBUTE_DECL:
10997            case XML_ENTITY_DECL:
10998            case XML_NAMESPACE_DECL:
10999            case XML_XINCLUDE_START:
11000            case XML_XINCLUDE_END:
11001		break;
11002	}
11003	limit = cur;
11004    }
11005    if (cur == NULL)
11006        return(retval);
11007
11008    patstream = xmlPatternGetStreamCtxt(comp);
11009    if (patstream == NULL) {
11010        return(retval);
11011    }
11012
11013    if (from_root) {
11014	ret = xmlStreamPush(patstream, NULL, NULL);
11015	if (ret < 0) {
11016	} else if (ret == 1) {
11017	    xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11018	}
11019    }
11020
11021    depth = 0;
11022    goto scan_children;
11023    do {
11024next_node:
11025        nb_nodes++;
11026	if (cur->type == XML_ELEMENT_NODE) {
11027	    ret = xmlStreamPush(patstream, cur->name,
11028				(cur->ns ? cur->ns->href : NULL));
11029	    if (ret < 0) {
11030	    } else if (ret == 1) {
11031		xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11032	    }
11033	    if ((cur->children == NULL) || (depth >= max_depth)) {
11034		ret = xmlStreamPop(patstream);
11035	    }
11036	}
11037
11038scan_children:
11039	if ((cur->children != NULL) && (depth < max_depth)) {
11040	    /*
11041	     * Do not descend on entities declarations
11042	     */
11043	    if (cur->children->type != XML_ENTITY_DECL) {
11044		cur = cur->children;
11045		depth++;
11046		/*
11047		 * Skip DTDs
11048		 */
11049		if (cur->type != XML_DTD_NODE)
11050		    continue;
11051	    }
11052	}
11053
11054	if (cur == limit)
11055	    break;
11056
11057	while (cur->next != NULL) {
11058	    cur = cur->next;
11059	    if ((cur->type != XML_ENTITY_DECL) &&
11060		(cur->type != XML_DTD_NODE))
11061		goto next_node;
11062	}
11063
11064	do {
11065	    ret = xmlStreamPop(patstream);
11066	    cur = cur->parent;
11067	    depth--;
11068	    if ((cur == NULL) || (cur == limit))
11069	        goto done;
11070	    if (cur->next != NULL) {
11071		cur = cur->next;
11072		break;
11073	    }
11074	} while (cur != NULL);
11075
11076    } while ((cur != NULL) && (depth >= 0));
11077done:
11078#if 0
11079    printf("stream eval: checked %d nodes selected %d\n",
11080           nb_nodes, retval->nodesetval->nodeNr);
11081#endif
11082    xmlFreeStreamCtxt(patstream);
11083    return(retval);
11084}
11085#endif /* XPATH_STREAMING */
11086
11087/**
11088 * xmlXPathRunEval:
11089 * @ctxt:  the XPath parser context with the compiled expression
11090 *
11091 * Evaluate the Precompiled XPath expression in the given context.
11092 */
11093static void
11094xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
11095    xmlXPathCompExprPtr comp;
11096
11097    if ((ctxt == NULL) || (ctxt->comp == NULL))
11098	return;
11099
11100    if (ctxt->valueTab == NULL) {
11101	/* Allocate the value stack */
11102	ctxt->valueTab = (xmlXPathObjectPtr *)
11103			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
11104	if (ctxt->valueTab == NULL) {
11105	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
11106	    xmlFree(ctxt);
11107	}
11108	ctxt->valueNr = 0;
11109	ctxt->valueMax = 10;
11110	ctxt->value = NULL;
11111    }
11112#ifdef XPATH_STREAMING
11113    if (ctxt->comp->stream) {
11114        xmlXPathObjectPtr ret;
11115        ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
11116	if (ret != NULL) {
11117	    valuePush(ctxt, ret);
11118	    return;
11119	}
11120    }
11121#endif
11122    comp = ctxt->comp;
11123    if(comp->last < 0) {
11124	xmlGenericError(xmlGenericErrorContext,
11125	    "xmlXPathRunEval: last is less than zero\n");
11126	return;
11127    }
11128    xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11129}
11130
11131/************************************************************************
11132 *									*
11133 * 			Public interfaces				*
11134 *									*
11135 ************************************************************************/
11136
11137/**
11138 * xmlXPathEvalPredicate:
11139 * @ctxt:  the XPath context
11140 * @res:  the Predicate Expression evaluation result
11141 *
11142 * Evaluate a predicate result for the current node.
11143 * A PredicateExpr is evaluated by evaluating the Expr and converting
11144 * the result to a boolean. If the result is a number, the result will
11145 * be converted to true if the number is equal to the position of the
11146 * context node in the context node list (as returned by the position
11147 * function) and will be converted to false otherwise; if the result
11148 * is not a number, then the result will be converted as if by a call
11149 * to the boolean function.
11150 *
11151 * Returns 1 if predicate is true, 0 otherwise
11152 */
11153int
11154xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
11155    if ((ctxt == NULL) || (res == NULL)) return(0);
11156    switch (res->type) {
11157        case XPATH_BOOLEAN:
11158	    return(res->boolval);
11159        case XPATH_NUMBER:
11160	    return(res->floatval == ctxt->proximityPosition);
11161        case XPATH_NODESET:
11162        case XPATH_XSLT_TREE:
11163	    if (res->nodesetval == NULL)
11164		return(0);
11165	    return(res->nodesetval->nodeNr != 0);
11166        case XPATH_STRING:
11167	    return((res->stringval != NULL) &&
11168	           (xmlStrlen(res->stringval) != 0));
11169        default:
11170	    STRANGE
11171    }
11172    return(0);
11173}
11174
11175/**
11176 * xmlXPathEvaluatePredicateResult:
11177 * @ctxt:  the XPath Parser context
11178 * @res:  the Predicate Expression evaluation result
11179 *
11180 * Evaluate a predicate result for the current node.
11181 * A PredicateExpr is evaluated by evaluating the Expr and converting
11182 * the result to a boolean. If the result is a number, the result will
11183 * be converted to true if the number is equal to the position of the
11184 * context node in the context node list (as returned by the position
11185 * function) and will be converted to false otherwise; if the result
11186 * is not a number, then the result will be converted as if by a call
11187 * to the boolean function.
11188 *
11189 * Returns 1 if predicate is true, 0 otherwise
11190 */
11191int
11192xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
11193                                xmlXPathObjectPtr res) {
11194    if ((ctxt == NULL) || (res == NULL)) return(0);
11195    switch (res->type) {
11196        case XPATH_BOOLEAN:
11197	    return(res->boolval);
11198        case XPATH_NUMBER:
11199#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
11200	    return((res->floatval == ctxt->context->proximityPosition) &&
11201	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
11202#else
11203	    return(res->floatval == ctxt->context->proximityPosition);
11204#endif
11205        case XPATH_NODESET:
11206        case XPATH_XSLT_TREE:
11207	    if (res->nodesetval == NULL)
11208		return(0);
11209	    return(res->nodesetval->nodeNr != 0);
11210        case XPATH_STRING:
11211	    return((res->stringval != NULL) &&
11212	           (xmlStrlen(res->stringval) != 0));
11213#ifdef LIBXML_XPTR_ENABLED
11214	case XPATH_LOCATIONSET:{
11215	    xmlLocationSetPtr ptr = res->user;
11216	    if (ptr == NULL)
11217	        return(0);
11218	    return (ptr->locNr != 0);
11219	    }
11220#endif
11221        default:
11222	    STRANGE
11223    }
11224    return(0);
11225}
11226
11227#ifdef XPATH_STREAMING
11228/**
11229 * xmlXPathTryStreamCompile:
11230 * @ctxt: an XPath context
11231 * @str:  the XPath expression
11232 *
11233 * Try to compile the XPath expression as a streamable subset.
11234 *
11235 * Returns the compiled expression or NULL if failed to compile.
11236 */
11237static xmlXPathCompExprPtr
11238xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11239    /*
11240     * Optimization: use streaming patterns when the XPath expression can
11241     * be compiled to a stream lookup
11242     */
11243    xmlPatternPtr stream;
11244    xmlXPathCompExprPtr comp;
11245    xmlDictPtr dict = NULL;
11246    const xmlChar **namespaces = NULL;
11247    xmlNsPtr ns;
11248    int i, j;
11249
11250    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
11251        (!xmlStrchr(str, '@'))) {
11252	if (ctxt != NULL) {
11253	    dict = ctxt->dict;
11254	    if (ctxt->nsNr > 0) {
11255		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1));
11256		if (namespaces == NULL) {
11257		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
11258		    return(NULL);
11259		}
11260		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
11261		    ns = ctxt->namespaces[j];
11262		    namespaces[i++] = ns->href;
11263		    namespaces[i++] = ns->prefix;
11264		}
11265		namespaces[i++] = NULL;
11266		namespaces[i++] = NULL;
11267	    }
11268	}
11269
11270	stream = xmlPatterncompile(str, dict, 0, &namespaces[0]);
11271	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
11272	    comp = xmlXPathNewCompExpr();
11273	    if (comp == NULL) {
11274		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
11275		return(NULL);
11276	    }
11277	    comp->stream = stream;
11278	    comp->dict = dict;
11279	    if (comp->dict)
11280		xmlDictReference(comp->dict);
11281	    return(comp);
11282	}
11283	xmlFreePattern(stream);
11284    }
11285    return(NULL);
11286}
11287#endif /* XPATH_STREAMING */
11288
11289/**
11290 * xmlXPathCtxtCompile:
11291 * @ctxt: an XPath context
11292 * @str:  the XPath expression
11293 *
11294 * Compile an XPath expression
11295 *
11296 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
11297 *         the caller has to free the object.
11298 */
11299xmlXPathCompExprPtr
11300xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11301    xmlXPathParserContextPtr pctxt;
11302    xmlXPathCompExprPtr comp;
11303
11304#ifdef XPATH_STREAMING
11305    comp = xmlXPathTryStreamCompile(ctxt, str);
11306    if (comp != NULL)
11307        return(comp);
11308#endif
11309
11310    xmlXPathInit();
11311
11312    pctxt = xmlXPathNewParserContext(str, ctxt);
11313    xmlXPathCompileExpr(pctxt);
11314
11315    if( pctxt->error != XPATH_EXPRESSION_OK )
11316    {
11317        xmlXPathFreeParserContext(pctxt);
11318        return (0);
11319    }
11320
11321    if (*pctxt->cur != 0) {
11322	/*
11323	 * aleksey: in some cases this line prints *second* error message
11324	 * (see bug #78858) and probably this should be fixed.
11325	 * However, we are not sure that all error messages are printed
11326	 * out in other places. It's not critical so we leave it as-is for now
11327	 */
11328	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11329	comp = NULL;
11330    } else {
11331	comp = pctxt->comp;
11332	pctxt->comp = NULL;
11333    }
11334    xmlXPathFreeParserContext(pctxt);
11335    if (comp != NULL) {
11336	comp->expr = xmlStrdup(str);
11337#ifdef DEBUG_EVAL_COUNTS
11338	comp->string = xmlStrdup(str);
11339	comp->nb = 0;
11340#endif
11341    }
11342    return(comp);
11343}
11344
11345/**
11346 * xmlXPathCompile:
11347 * @str:  the XPath expression
11348 *
11349 * Compile an XPath expression
11350 *
11351 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
11352 *         the caller has to free the object.
11353 */
11354xmlXPathCompExprPtr
11355xmlXPathCompile(const xmlChar *str) {
11356    return(xmlXPathCtxtCompile(NULL, str));
11357}
11358
11359/**
11360 * xmlXPathCompiledEval:
11361 * @comp:  the compiled XPath expression
11362 * @ctx:  the XPath context
11363 *
11364 * Evaluate the Precompiled XPath expression in the given context.
11365 *
11366 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11367 *         the caller has to free the object.
11368 */
11369xmlXPathObjectPtr
11370xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
11371    xmlXPathParserContextPtr ctxt;
11372    xmlXPathObjectPtr res, tmp, init = NULL;
11373    int stack = 0;
11374#ifndef LIBXML_THREAD_ENABLED
11375    static int reentance = 0;
11376#endif
11377
11378    CHECK_CTXT(ctx)
11379
11380    if (comp == NULL)
11381	return(NULL);
11382    xmlXPathInit();
11383
11384#ifndef LIBXML_THREAD_ENABLED
11385    reentance++;
11386    if (reentance > 1)
11387	xmlXPathDisableOptimizer = 1;
11388#endif
11389
11390#ifdef DEBUG_EVAL_COUNTS
11391    comp->nb++;
11392    if ((comp->string != NULL) && (comp->nb > 100)) {
11393	fprintf(stderr, "100 x %s\n", comp->string);
11394	comp->nb = 0;
11395    }
11396#endif
11397    ctxt = xmlXPathCompParserContext(comp, ctx);
11398    xmlXPathRunEval(ctxt);
11399
11400    if (ctxt->value == NULL) {
11401	xmlGenericError(xmlGenericErrorContext,
11402		"xmlXPathCompiledEval: evaluation failed\n");
11403	res = NULL;
11404    } else {
11405	res = valuePop(ctxt);
11406    }
11407
11408
11409    do {
11410        tmp = valuePop(ctxt);
11411	if (tmp != NULL) {
11412	    if (tmp != init)
11413		stack++;
11414	    xmlXPathFreeObject(tmp);
11415        }
11416    } while (tmp != NULL);
11417    if ((stack != 0) && (res != NULL)) {
11418	xmlGenericError(xmlGenericErrorContext,
11419		"xmlXPathCompiledEval: %d object left on the stack\n",
11420	        stack);
11421    }
11422    if (ctxt->error != XPATH_EXPRESSION_OK) {
11423	xmlXPathFreeObject(res);
11424	res = NULL;
11425    }
11426
11427
11428    ctxt->comp = NULL;
11429    xmlXPathFreeParserContext(ctxt);
11430#ifndef LIBXML_THREAD_ENABLED
11431    reentance--;
11432#endif
11433    return(res);
11434}
11435
11436/**
11437 * xmlXPathEvalExpr:
11438 * @ctxt:  the XPath Parser context
11439 *
11440 * Parse and evaluate an XPath expression in the given context,
11441 * then push the result on the context stack
11442 */
11443void
11444xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
11445#ifdef XPATH_STREAMING
11446    xmlXPathCompExprPtr comp;
11447#endif
11448
11449    if (ctxt == NULL) return;
11450
11451#ifdef XPATH_STREAMING
11452    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
11453    if (comp != NULL) {
11454        if (ctxt->comp != NULL)
11455	    xmlXPathFreeCompExpr(ctxt->comp);
11456        ctxt->comp = comp;
11457	if (ctxt->cur != NULL)
11458	    while (*ctxt->cur != 0) ctxt->cur++;
11459    } else
11460#endif
11461    {
11462	xmlXPathCompileExpr(ctxt);
11463    }
11464    CHECK_ERROR;
11465    xmlXPathRunEval(ctxt);
11466}
11467
11468/**
11469 * xmlXPathEval:
11470 * @str:  the XPath expression
11471 * @ctx:  the XPath context
11472 *
11473 * Evaluate the XPath Location Path in the given context.
11474 *
11475 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11476 *         the caller has to free the object.
11477 */
11478xmlXPathObjectPtr
11479xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11480    xmlXPathParserContextPtr ctxt;
11481    xmlXPathObjectPtr res, tmp, init = NULL;
11482    int stack = 0;
11483
11484    CHECK_CTXT(ctx)
11485
11486    xmlXPathInit();
11487
11488    ctxt = xmlXPathNewParserContext(str, ctx);
11489    xmlXPathEvalExpr(ctxt);
11490
11491    if (ctxt->value == NULL) {
11492	xmlGenericError(xmlGenericErrorContext,
11493		"xmlXPathEval: evaluation failed\n");
11494	res = NULL;
11495    } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
11496#ifdef XPATH_STREAMING
11497            && (ctxt->comp->stream == NULL)
11498#endif
11499	      ) {
11500	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11501	res = NULL;
11502    } else {
11503	res = valuePop(ctxt);
11504    }
11505
11506    do {
11507        tmp = valuePop(ctxt);
11508	if (tmp != NULL) {
11509	    if (tmp != init)
11510		stack++;
11511	    xmlXPathFreeObject(tmp);
11512        }
11513    } while (tmp != NULL);
11514    if ((stack != 0) && (res != NULL)) {
11515	xmlGenericError(xmlGenericErrorContext,
11516		"xmlXPathEval: %d object left on the stack\n",
11517	        stack);
11518    }
11519    if (ctxt->error != XPATH_EXPRESSION_OK) {
11520	xmlXPathFreeObject(res);
11521	res = NULL;
11522    }
11523
11524    xmlXPathFreeParserContext(ctxt);
11525    return(res);
11526}
11527
11528/**
11529 * xmlXPathEvalExpression:
11530 * @str:  the XPath expression
11531 * @ctxt:  the XPath context
11532 *
11533 * Evaluate the XPath expression in the given context.
11534 *
11535 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11536 *         the caller has to free the object.
11537 */
11538xmlXPathObjectPtr
11539xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11540    xmlXPathParserContextPtr pctxt;
11541    xmlXPathObjectPtr res, tmp;
11542    int stack = 0;
11543
11544    CHECK_CTXT(ctxt)
11545
11546    xmlXPathInit();
11547
11548    pctxt = xmlXPathNewParserContext(str, ctxt);
11549    xmlXPathEvalExpr(pctxt);
11550
11551    if (*pctxt->cur != 0) {
11552	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11553	res = NULL;
11554    } else {
11555	res = valuePop(pctxt);
11556    }
11557    do {
11558        tmp = valuePop(pctxt);
11559	if (tmp != NULL) {
11560	    xmlXPathFreeObject(tmp);
11561	    stack++;
11562	}
11563    } while (tmp != NULL);
11564    if ((stack != 0) && (res != NULL)) {
11565	xmlGenericError(xmlGenericErrorContext,
11566		"xmlXPathEvalExpression: %d object left on the stack\n",
11567	        stack);
11568    }
11569    xmlXPathFreeParserContext(pctxt);
11570    return(res);
11571}
11572
11573/************************************************************************
11574 *									*
11575 *	Extra functions not pertaining to the XPath spec		*
11576 *									*
11577 ************************************************************************/
11578/**
11579 * xmlXPathEscapeUriFunction:
11580 * @ctxt:  the XPath Parser context
11581 * @nargs:  the number of arguments
11582 *
11583 * Implement the escape-uri() XPath function
11584 *    string escape-uri(string $str, bool $escape-reserved)
11585 *
11586 * This function applies the URI escaping rules defined in section 2 of [RFC
11587 * 2396] to the string supplied as $uri-part, which typically represents all
11588 * or part of a URI. The effect of the function is to replace any special
11589 * character in the string by an escape sequence of the form %xx%yy...,
11590 * where xxyy... is the hexadecimal representation of the octets used to
11591 * represent the character in UTF-8.
11592 *
11593 * The set of characters that are escaped depends on the setting of the
11594 * boolean argument $escape-reserved.
11595 *
11596 * If $escape-reserved is true, all characters are escaped other than lower
11597 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11598 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11599 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11600 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11601 * A-F).
11602 *
11603 * If $escape-reserved is false, the behavior differs in that characters
11604 * referred to in [RFC 2396] as reserved characters are not escaped. These
11605 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11606 *
11607 * [RFC 2396] does not define whether escaped URIs should use lower case or
11608 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11609 * compared using string comparison functions, this function must always use
11610 * the upper-case letters A-F.
11611 *
11612 * Generally, $escape-reserved should be set to true when escaping a string
11613 * that is to form a single part of a URI, and to false when escaping an
11614 * entire URI or URI reference.
11615 *
11616 * In the case of non-ascii characters, the string is encoded according to
11617 * utf-8 and then converted according to RFC 2396.
11618 *
11619 * Examples
11620 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11621 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11622 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11623 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11624 *
11625 */
11626static void
11627xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11628    xmlXPathObjectPtr str;
11629    int escape_reserved;
11630    xmlBufferPtr target;
11631    xmlChar *cptr;
11632    xmlChar escape[4];
11633
11634    CHECK_ARITY(2);
11635
11636    escape_reserved = xmlXPathPopBoolean(ctxt);
11637
11638    CAST_TO_STRING;
11639    str = valuePop(ctxt);
11640
11641    target = xmlBufferCreate();
11642
11643    escape[0] = '%';
11644    escape[3] = 0;
11645
11646    if (target) {
11647	for (cptr = str->stringval; *cptr; cptr++) {
11648	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
11649		(*cptr >= 'a' && *cptr <= 'z') ||
11650		(*cptr >= '0' && *cptr <= '9') ||
11651		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
11652		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
11653		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11654		(*cptr == '%' &&
11655		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11656		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11657		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
11658		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11659		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11660		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11661		(!escape_reserved &&
11662		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11663		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11664		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11665		  *cptr == ','))) {
11666		xmlBufferAdd(target, cptr, 1);
11667	    } else {
11668		if ((*cptr >> 4) < 10)
11669		    escape[1] = '0' + (*cptr >> 4);
11670		else
11671		    escape[1] = 'A' - 10 + (*cptr >> 4);
11672		if ((*cptr & 0xF) < 10)
11673		    escape[2] = '0' + (*cptr & 0xF);
11674		else
11675		    escape[2] = 'A' - 10 + (*cptr & 0xF);
11676
11677		xmlBufferAdd(target, &escape[0], 3);
11678	    }
11679	}
11680    }
11681    valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11682    xmlBufferFree(target);
11683    xmlXPathFreeObject(str);
11684}
11685
11686/**
11687 * xmlXPathRegisterAllFunctions:
11688 * @ctxt:  the XPath context
11689 *
11690 * Registers all default XPath functions in this context
11691 */
11692void
11693xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11694{
11695    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11696                         xmlXPathBooleanFunction);
11697    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11698                         xmlXPathCeilingFunction);
11699    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11700                         xmlXPathCountFunction);
11701    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11702                         xmlXPathConcatFunction);
11703    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11704                         xmlXPathContainsFunction);
11705    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11706                         xmlXPathIdFunction);
11707    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11708                         xmlXPathFalseFunction);
11709    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11710                         xmlXPathFloorFunction);
11711    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11712                         xmlXPathLastFunction);
11713    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11714                         xmlXPathLangFunction);
11715    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11716                         xmlXPathLocalNameFunction);
11717    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11718                         xmlXPathNotFunction);
11719    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11720                         xmlXPathNameFunction);
11721    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11722                         xmlXPathNamespaceURIFunction);
11723    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11724                         xmlXPathNormalizeFunction);
11725    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11726                         xmlXPathNumberFunction);
11727    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11728                         xmlXPathPositionFunction);
11729    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11730                         xmlXPathRoundFunction);
11731    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11732                         xmlXPathStringFunction);
11733    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11734                         xmlXPathStringLengthFunction);
11735    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11736                         xmlXPathStartsWithFunction);
11737    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11738                         xmlXPathSubstringFunction);
11739    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11740                         xmlXPathSubstringBeforeFunction);
11741    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11742                         xmlXPathSubstringAfterFunction);
11743    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11744                         xmlXPathSumFunction);
11745    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11746                         xmlXPathTrueFunction);
11747    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11748                         xmlXPathTranslateFunction);
11749
11750    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11751	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11752                         xmlXPathEscapeUriFunction);
11753}
11754
11755#endif /* LIBXML_XPATH_ENABLED */
11756