• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/gettext-0.17/gettext-tools/gnulib-lib/libxml/
1/*
2 * xpath.c: XML Path Language implementation
3 *          XPath is a language for addressing parts of an XML document,
4 *          designed to be used by both XSLT and XPointer
5 *f
6 * Reference: W3C Recommendation 16 November 1999
7 *     http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 *     http://www.w3.org/TR/xpath
10 *
11 * See Copyright for the status of this software
12 *
13 * Author: daniel@veillard.com
14 *
15 */
16
17#define IN_LIBXML
18#include "libxml.h"
19
20#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
31#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
34#ifdef HAVE_SIGNAL_H
35#include <signal.h>
36#endif
37
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
52#include <libxml/threads.h>
53#include <libxml/globals.h>
54#ifdef LIBXML_PATTERN_ENABLED
55#include <libxml/pattern.h>
56#endif
57
58#ifdef LIBXML_PATTERN_ENABLED
59#define XPATH_STREAMING
60#endif
61
62#define TODO 								\
63    xmlGenericError(xmlGenericErrorContext,				\
64	    "Unimplemented block at %s:%d\n",				\
65            __FILE__, __LINE__);
66
67/*
68* XP_OPTIMIZED_NON_ELEM_COMPARISON:
69* If defined, this will use xmlXPathCmpNodesExt() instead of
70* xmlXPathCmpNodes(). The new function is optimized comparison of
71* non-element nodes; actually it will speed up comparison only if
72* xmlXPathOrderDocElems() was called in order to index the elements of
73* a tree in document order; Libxslt does such an indexing, thus it will
74* benefit from this optimization.
75*/
76#define XP_OPTIMIZED_NON_ELEM_COMPARISON
77
78/*
79* XP_OPTIMIZED_FILTER_FIRST:
80* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81* in a way, that it stop evaluation at the first node.
82*/
83#define XP_OPTIMIZED_FILTER_FIRST
84
85/*
86* XP_DEBUG_OBJ_USAGE:
87* Internal flag to enable tracking of how much XPath objects have been
88* created.
89*/
90/* #define XP_DEBUG_OBJ_USAGE */
91
92/*
93 * TODO:
94 * There are a few spots where some tests are done which depend upon ascii
95 * data.  These should be enhanced for full UTF8 support (see particularly
96 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
97 */
98
99#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
100
101/************************************************************************
102 * 									*
103 * 			Floating point stuff				*
104 * 									*
105 ************************************************************************/
106
107#ifndef TRIO_REPLACE_STDIO
108#define TRIO_PUBLIC static
109#endif
110#include "trionan.c"
111
112/*
113 * The lack of portability of this section of the libc is annoying !
114 */
115double xmlXPathNAN = 0;
116double xmlXPathPINF = 1;
117double xmlXPathNINF = -1;
118static double xmlXPathNZERO = 0; /* not exported from headers */
119static int xmlXPathInitialized = 0;
120
121/**
122 * xmlXPathInit:
123 *
124 * Initialize the XPath environment
125 */
126void
127xmlXPathInit(void) {
128    if (xmlXPathInitialized) return;
129
130    xmlXPathPINF = trio_pinf();
131    xmlXPathNINF = trio_ninf();
132    xmlXPathNAN = trio_nan();
133    xmlXPathNZERO = trio_nzero();
134
135    xmlXPathInitialized = 1;
136}
137
138/**
139 * xmlXPathIsNaN:
140 * @val:  a double value
141 *
142 * Provides a portable isnan() function to detect whether a double
143 * is a NotaNumber. Based on trio code
144 * http://sourceforge.net/projects/ctrio/
145 *
146 * Returns 1 if the value is a NaN, 0 otherwise
147 */
148int
149xmlXPathIsNaN(double val) {
150    return(trio_isnan(val));
151}
152
153/**
154 * xmlXPathIsInf:
155 * @val:  a double value
156 *
157 * Provides a portable isinf() function to detect whether a double
158 * is a +Infinite or -Infinite. Based on trio code
159 * http://sourceforge.net/projects/ctrio/
160 *
161 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
162 */
163int
164xmlXPathIsInf(double val) {
165    return(trio_isinf(val));
166}
167
168#endif /* SCHEMAS or XPATH */
169#ifdef LIBXML_XPATH_ENABLED
170/**
171 * xmlXPathGetSign:
172 * @val:  a double value
173 *
174 * Provides a portable function to detect the sign of a double
175 * Modified from trio code
176 * http://sourceforge.net/projects/ctrio/
177 *
178 * Returns 1 if the value is Negative, 0 if positive
179 */
180static int
181xmlXPathGetSign(double val) {
182    return(trio_signbit(val));
183}
184
185
186/*
187 * TODO: when compatibility allows remove all "fake node libxslt" strings
188 *       the test should just be name[0] = ' '
189 */
190/* #define DEBUG */
191/* #define DEBUG_STEP */
192/* #define DEBUG_STEP_NTH */
193/* #define DEBUG_EXPR */
194/* #define DEBUG_EVAL_COUNTS */
195
196static xmlNs xmlXPathXMLNamespaceStruct = {
197    NULL,
198    XML_NAMESPACE_DECL,
199    XML_XML_NAMESPACE,
200    BAD_CAST "xml",
201    NULL
202};
203static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
204#ifndef LIBXML_THREAD_ENABLED
205/*
206 * Optimizer is disabled only when threaded apps are detected while
207 * the library ain't compiled for thread safety.
208 */
209static int xmlXPathDisableOptimizer = 0;
210#endif
211
212/************************************************************************
213 *									*
214 *			Error handling routines				*
215 *									*
216 ************************************************************************/
217
218/**
219 * XP_ERRORNULL:
220 * @X:  the error code
221 *
222 * Macro to raise an XPath error and return NULL.
223 */
224#define XP_ERRORNULL(X)							\
225    { xmlXPathErr(ctxt, X); return(NULL); }
226
227/*
228 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
229 */
230static const char *xmlXPathErrorMessages[] = {
231    "Ok\n",
232    "Number encoding\n",
233    "Unfinished literal\n",
234    "Start of literal\n",
235    "Expected $ for variable reference\n",
236    "Undefined variable\n",
237    "Invalid predicate\n",
238    "Invalid expression\n",
239    "Missing closing curly brace\n",
240    "Unregistered function\n",
241    "Invalid operand\n",
242    "Invalid type\n",
243    "Invalid number of arguments\n",
244    "Invalid context size\n",
245    "Invalid context position\n",
246    "Memory allocation error\n",
247    "Syntax error\n",
248    "Resource error\n",
249    "Sub resource error\n",
250    "Undefined namespace prefix\n",
251    "Encoding error\n",
252    "Char out of XML range\n",
253    "Invalid or incomplete context\n",
254    "?? Unknown error ??\n"	/* Must be last in the list! */
255};
256#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
257		   sizeof(xmlXPathErrorMessages[0])) - 1)
258/**
259 * xmlXPathErrMemory:
260 * @ctxt:  an XPath context
261 * @extra:  extra informations
262 *
263 * Handle a redefinition of attribute error
264 */
265static void
266xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
267{
268    if (ctxt != NULL) {
269        if (extra) {
270            xmlChar buf[200];
271
272            xmlStrPrintf(buf, 200,
273                         BAD_CAST "Memory allocation failed : %s\n",
274                         extra);
275            ctxt->lastError.message = (char *) xmlStrdup(buf);
276        } else {
277            ctxt->lastError.message = (char *)
278	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
279        }
280        ctxt->lastError.domain = XML_FROM_XPATH;
281        ctxt->lastError.code = XML_ERR_NO_MEMORY;
282	if (ctxt->error != NULL)
283	    ctxt->error(ctxt->userData, &ctxt->lastError);
284    } else {
285        if (extra)
286            __xmlRaiseError(NULL, NULL, NULL,
287                            NULL, NULL, XML_FROM_XPATH,
288                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
289                            extra, NULL, NULL, 0, 0,
290                            "Memory allocation failed : %s\n", extra);
291        else
292            __xmlRaiseError(NULL, NULL, NULL,
293                            NULL, NULL, XML_FROM_XPATH,
294                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
295                            NULL, NULL, NULL, 0, 0,
296                            "Memory allocation failed\n");
297    }
298}
299
300/**
301 * xmlXPathPErrMemory:
302 * @ctxt:  an XPath parser context
303 * @extra:  extra informations
304 *
305 * Handle a redefinition of attribute error
306 */
307static void
308xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
309{
310    if (ctxt == NULL)
311	xmlXPathErrMemory(NULL, extra);
312    else {
313	ctxt->error = XPATH_MEMORY_ERROR;
314	xmlXPathErrMemory(ctxt->context, extra);
315    }
316}
317
318/**
319 * xmlXPathErr:
320 * @ctxt:  a XPath parser context
321 * @error:  the error code
322 *
323 * Handle an XPath error
324 */
325void
326xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
327{
328    if ((error < 0) || (error > MAXERRNO))
329	error = MAXERRNO;
330    if (ctxt == NULL) {
331	__xmlRaiseError(NULL, NULL, NULL,
332			NULL, NULL, XML_FROM_XPATH,
333			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
334			XML_ERR_ERROR, NULL, 0,
335			NULL, NULL, NULL, 0, 0,
336			xmlXPathErrorMessages[error]);
337	return;
338    }
339    ctxt->error = error;
340    if (ctxt->context == NULL) {
341	__xmlRaiseError(NULL, NULL, NULL,
342			NULL, NULL, XML_FROM_XPATH,
343			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
344			XML_ERR_ERROR, NULL, 0,
345			(const char *) ctxt->base, NULL, NULL,
346			ctxt->cur - ctxt->base, 0,
347			xmlXPathErrorMessages[error]);
348	return;
349    }
350
351    /* cleanup current last error */
352    xmlResetError(&ctxt->context->lastError);
353
354    ctxt->context->lastError.domain = XML_FROM_XPATH;
355    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
356                           XPATH_EXPRESSION_OK;
357    ctxt->context->lastError.level = XML_ERR_ERROR;
358    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
359    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
360    ctxt->context->lastError.node = ctxt->context->debugNode;
361    if (ctxt->context->error != NULL) {
362	ctxt->context->error(ctxt->context->userData,
363	                     &ctxt->context->lastError);
364    } else {
365	__xmlRaiseError(NULL, NULL, NULL,
366			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
367			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
368			XML_ERR_ERROR, NULL, 0,
369			(const char *) ctxt->base, NULL, NULL,
370			ctxt->cur - ctxt->base, 0,
371			xmlXPathErrorMessages[error]);
372    }
373
374}
375
376/**
377 * xmlXPatherror:
378 * @ctxt:  the XPath Parser context
379 * @file:  the file name
380 * @line:  the line number
381 * @no:  the error number
382 *
383 * Formats an error message.
384 */
385void
386xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
387              int line ATTRIBUTE_UNUSED, int no) {
388    xmlXPathErr(ctxt, no);
389}
390
391/************************************************************************
392 * 									*
393 * 			Utilities	    				*
394 * 									*
395 ************************************************************************/
396
397/**
398 * xsltPointerList:
399 *
400 * Pointer-list for various purposes.
401 */
402typedef struct _xmlPointerList xmlPointerList;
403typedef xmlPointerList *xmlPointerListPtr;
404struct _xmlPointerList {
405    void **items;
406    int number;
407    int size;
408};
409/*
410* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
411* and here, we should make the functions public.
412*/
413static int
414xmlPointerListAddSize(xmlPointerListPtr list,
415		       void *item,
416		       int initialSize)
417{
418    if (list->items == NULL) {
419	if (initialSize <= 0)
420	    initialSize = 1;
421	list->items = (void **) xmlMalloc(
422	    initialSize * sizeof(void *));
423	if (list->items == NULL) {
424	    xmlXPathErrMemory(NULL,
425		"xmlPointerListCreate: allocating item\n");
426	    return(-1);
427	}
428	list->number = 0;
429	list->size = initialSize;
430    } else if (list->size <= list->number) {
431	list->size *= 2;
432	list->items = (void **) xmlRealloc(list->items,
433	    list->size * sizeof(void *));
434	if (list->items == NULL) {
435	    xmlXPathErrMemory(NULL,
436		"xmlPointerListCreate: re-allocating item\n");
437	    list->size = 0;
438	    return(-1);
439	}
440    }
441    list->items[list->number++] = item;
442    return(0);
443}
444
445/**
446 * xsltPointerListCreate:
447 *
448 * Creates an xsltPointerList structure.
449 *
450 * Returns a xsltPointerList structure or NULL in case of an error.
451 */
452static xmlPointerListPtr
453xmlPointerListCreate(int initialSize)
454{
455    xmlPointerListPtr ret;
456
457    ret = xmlMalloc(sizeof(xmlPointerList));
458    if (ret == NULL) {
459	xmlXPathErrMemory(NULL,
460	    "xmlPointerListCreate: allocating item\n");
461	return (NULL);
462    }
463    memset(ret, 0, sizeof(xmlPointerList));
464    if (initialSize > 0) {
465	xmlPointerListAddSize(ret, NULL, initialSize);
466	ret->number = 0;
467    }
468    return (ret);
469}
470
471/**
472 * xsltPointerListFree:
473 *
474 * Frees the xsltPointerList structure. This does not free
475 * the content of the list.
476 */
477static void
478xmlPointerListFree(xmlPointerListPtr list)
479{
480    if (list == NULL)
481	return;
482    if (list->items != NULL)
483	xmlFree(list->items);
484    xmlFree(list);
485}
486
487/************************************************************************
488 * 									*
489 * 			Parser Types					*
490 * 									*
491 ************************************************************************/
492
493/*
494 * Types are private:
495 */
496
497typedef enum {
498    XPATH_OP_END=0,
499    XPATH_OP_AND,
500    XPATH_OP_OR,
501    XPATH_OP_EQUAL,
502    XPATH_OP_CMP,
503    XPATH_OP_PLUS,
504    XPATH_OP_MULT,
505    XPATH_OP_UNION,
506    XPATH_OP_ROOT,
507    XPATH_OP_NODE,
508    XPATH_OP_RESET, /* 10 */
509    XPATH_OP_COLLECT,
510    XPATH_OP_VALUE, /* 12 */
511    XPATH_OP_VARIABLE,
512    XPATH_OP_FUNCTION,
513    XPATH_OP_ARG,
514    XPATH_OP_PREDICATE,
515    XPATH_OP_FILTER, /* 17 */
516    XPATH_OP_SORT /* 18 */
517#ifdef LIBXML_XPTR_ENABLED
518    ,XPATH_OP_RANGETO
519#endif
520} xmlXPathOp;
521
522typedef enum {
523    AXIS_ANCESTOR = 1,
524    AXIS_ANCESTOR_OR_SELF,
525    AXIS_ATTRIBUTE,
526    AXIS_CHILD,
527    AXIS_DESCENDANT,
528    AXIS_DESCENDANT_OR_SELF,
529    AXIS_FOLLOWING,
530    AXIS_FOLLOWING_SIBLING,
531    AXIS_NAMESPACE,
532    AXIS_PARENT,
533    AXIS_PRECEDING,
534    AXIS_PRECEDING_SIBLING,
535    AXIS_SELF
536} xmlXPathAxisVal;
537
538typedef enum {
539    NODE_TEST_NONE = 0,
540    NODE_TEST_TYPE = 1,
541    NODE_TEST_PI = 2,
542    NODE_TEST_ALL = 3,
543    NODE_TEST_NS = 4,
544    NODE_TEST_NAME = 5
545} xmlXPathTestVal;
546
547typedef enum {
548    NODE_TYPE_NODE = 0,
549    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
550    NODE_TYPE_TEXT = XML_TEXT_NODE,
551    NODE_TYPE_PI = XML_PI_NODE
552} xmlXPathTypeVal;
553
554#define XP_REWRITE_DOS_CHILD_ELEM 1
555
556typedef struct _xmlXPathStepOp xmlXPathStepOp;
557typedef xmlXPathStepOp *xmlXPathStepOpPtr;
558struct _xmlXPathStepOp {
559    xmlXPathOp op;		/* The identifier of the operation */
560    int ch1;			/* First child */
561    int ch2;			/* Second child */
562    int value;
563    int value2;
564    int value3;
565    void *value4;
566    void *value5;
567    void *cache;
568    void *cacheURI;
569    int rewriteType;
570};
571
572struct _xmlXPathCompExpr {
573    int nbStep;			/* Number of steps in this expression */
574    int maxStep;		/* Maximum number of steps allocated */
575    xmlXPathStepOp *steps;	/* ops for computation of this expression */
576    int last;			/* index of last step in expression */
577    xmlChar *expr;		/* the expression being computed */
578    xmlDictPtr dict;		/* the dictionnary to use if any */
579#ifdef DEBUG_EVAL_COUNTS
580    int nb;
581    xmlChar *string;
582#endif
583#ifdef XPATH_STREAMING
584    xmlPatternPtr stream;
585#endif
586};
587
588/************************************************************************
589 * 									*
590 * 			Forward declarations				*
591 * 									*
592 ************************************************************************/
593static void
594xmlXPathFreeValueTree(xmlNodeSetPtr obj);
595static void
596xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
597static int
598xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
599                        xmlXPathStepOpPtr op, xmlNodePtr *first);
600static int
601xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
602			    xmlXPathStepOpPtr op,
603			    int isPredicate);
604
605/************************************************************************
606 * 									*
607 * 			Parser Type functions 				*
608 * 									*
609 ************************************************************************/
610
611/**
612 * xmlXPathNewCompExpr:
613 *
614 * Create a new Xpath component
615 *
616 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
617 */
618static xmlXPathCompExprPtr
619xmlXPathNewCompExpr(void) {
620    xmlXPathCompExprPtr cur;
621
622    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
623    if (cur == NULL) {
624        xmlXPathErrMemory(NULL, "allocating component\n");
625	return(NULL);
626    }
627    memset(cur, 0, sizeof(xmlXPathCompExpr));
628    cur->maxStep = 10;
629    cur->nbStep = 0;
630    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
631	                                   sizeof(xmlXPathStepOp));
632    if (cur->steps == NULL) {
633        xmlXPathErrMemory(NULL, "allocating steps\n");
634	xmlFree(cur);
635	return(NULL);
636    }
637    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
638    cur->last = -1;
639#ifdef DEBUG_EVAL_COUNTS
640    cur->nb = 0;
641#endif
642    return(cur);
643}
644
645/**
646 * xmlXPathFreeCompExpr:
647 * @comp:  an XPATH comp
648 *
649 * Free up the memory allocated by @comp
650 */
651void
652xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
653{
654    xmlXPathStepOpPtr op;
655    int i;
656
657    if (comp == NULL)
658        return;
659    if (comp->dict == NULL) {
660	for (i = 0; i < comp->nbStep; i++) {
661	    op = &comp->steps[i];
662	    if (op->value4 != NULL) {
663		if (op->op == XPATH_OP_VALUE)
664		    xmlXPathFreeObject(op->value4);
665		else
666		    xmlFree(op->value4);
667	    }
668	    if (op->value5 != NULL)
669		xmlFree(op->value5);
670	}
671    } else {
672	for (i = 0; i < comp->nbStep; i++) {
673	    op = &comp->steps[i];
674	    if (op->value4 != NULL) {
675		if (op->op == XPATH_OP_VALUE)
676		    xmlXPathFreeObject(op->value4);
677	    }
678	}
679        xmlDictFree(comp->dict);
680    }
681    if (comp->steps != NULL) {
682        xmlFree(comp->steps);
683    }
684#ifdef DEBUG_EVAL_COUNTS
685    if (comp->string != NULL) {
686        xmlFree(comp->string);
687    }
688#endif
689#ifdef XPATH_STREAMING
690    if (comp->stream != NULL) {
691        xmlFreePatternList(comp->stream);
692    }
693#endif
694    if (comp->expr != NULL) {
695        xmlFree(comp->expr);
696    }
697
698    xmlFree(comp);
699}
700
701/**
702 * xmlXPathCompExprAdd:
703 * @comp:  the compiled expression
704 * @ch1: first child index
705 * @ch2: second child index
706 * @op:  an op
707 * @value:  the first int value
708 * @value2:  the second int value
709 * @value3:  the third int value
710 * @value4:  the first string value
711 * @value5:  the second string value
712 *
713 * Add a step to an XPath Compiled Expression
714 *
715 * Returns -1 in case of failure, the index otherwise
716 */
717static int
718xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
719   xmlXPathOp op, int value,
720   int value2, int value3, void *value4, void *value5) {
721    if (comp->nbStep >= comp->maxStep) {
722	xmlXPathStepOp *real;
723
724	comp->maxStep *= 2;
725	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
726		                      comp->maxStep * sizeof(xmlXPathStepOp));
727	if (real == NULL) {
728	    comp->maxStep /= 2;
729	    xmlXPathErrMemory(NULL, "adding step\n");
730	    return(-1);
731	}
732	comp->steps = real;
733    }
734    comp->last = comp->nbStep;
735    comp->steps[comp->nbStep].rewriteType = 0;
736    comp->steps[comp->nbStep].ch1 = ch1;
737    comp->steps[comp->nbStep].ch2 = ch2;
738    comp->steps[comp->nbStep].op = op;
739    comp->steps[comp->nbStep].value = value;
740    comp->steps[comp->nbStep].value2 = value2;
741    comp->steps[comp->nbStep].value3 = value3;
742    if ((comp->dict != NULL) &&
743        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
744	 (op == XPATH_OP_COLLECT))) {
745        if (value4 != NULL) {
746	    comp->steps[comp->nbStep].value4 = (xmlChar *)
747	        (void *)xmlDictLookup(comp->dict, value4, -1);
748	    xmlFree(value4);
749	} else
750	    comp->steps[comp->nbStep].value4 = NULL;
751        if (value5 != NULL) {
752	    comp->steps[comp->nbStep].value5 = (xmlChar *)
753	        (void *)xmlDictLookup(comp->dict, value5, -1);
754	    xmlFree(value5);
755	} else
756	    comp->steps[comp->nbStep].value5 = NULL;
757    } else {
758	comp->steps[comp->nbStep].value4 = value4;
759	comp->steps[comp->nbStep].value5 = value5;
760    }
761    comp->steps[comp->nbStep].cache = NULL;
762    return(comp->nbStep++);
763}
764
765/**
766 * xmlXPathCompSwap:
767 * @comp:  the compiled expression
768 * @op: operation index
769 *
770 * Swaps 2 operations in the compiled expression
771 */
772static void
773xmlXPathCompSwap(xmlXPathStepOpPtr op) {
774    int tmp;
775
776#ifndef LIBXML_THREAD_ENABLED
777    /*
778     * Since this manipulates possibly shared variables, this is
779     * disabled if one detects that the library is used in a multithreaded
780     * application
781     */
782    if (xmlXPathDisableOptimizer)
783	return;
784#endif
785
786    tmp = op->ch1;
787    op->ch1 = op->ch2;
788    op->ch2 = tmp;
789}
790
791#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
792    xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
793	                (op), (val), (val2), (val3), (val4), (val5))
794#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
795    xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
796	                (op), (val), (val2), (val3), (val4), (val5))
797
798#define PUSH_LEAVE_EXPR(op, val, val2) 					\
799xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
800
801#define PUSH_UNARY_EXPR(op, ch, val, val2) 				\
802xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
803
804#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) 			\
805xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
806			(val), (val2), 0 ,NULL ,NULL)
807
808/************************************************************************
809 *									*
810 * 		XPath object cache structures				*
811 *									*
812 ************************************************************************/
813
814/* #define XP_DEFAULT_CACHE_ON */
815
816#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
817
818typedef struct _xmlXPathContextCache xmlXPathContextCache;
819typedef xmlXPathContextCache *xmlXPathContextCachePtr;
820struct _xmlXPathContextCache {
821    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
822    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
823    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
824    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
825    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
826    int maxNodeset;
827    int maxString;
828    int maxBoolean;
829    int maxNumber;
830    int maxMisc;
831#ifdef XP_DEBUG_OBJ_USAGE
832    int dbgCachedAll;
833    int dbgCachedNodeset;
834    int dbgCachedString;
835    int dbgCachedBool;
836    int dbgCachedNumber;
837    int dbgCachedPoint;
838    int dbgCachedRange;
839    int dbgCachedLocset;
840    int dbgCachedUsers;
841    int dbgCachedXSLTTree;
842    int dbgCachedUndefined;
843
844
845    int dbgReusedAll;
846    int dbgReusedNodeset;
847    int dbgReusedString;
848    int dbgReusedBool;
849    int dbgReusedNumber;
850    int dbgReusedPoint;
851    int dbgReusedRange;
852    int dbgReusedLocset;
853    int dbgReusedUsers;
854    int dbgReusedXSLTTree;
855    int dbgReusedUndefined;
856
857#endif
858};
859
860/************************************************************************
861 *									*
862 * 		Debugging related functions				*
863 *									*
864 ************************************************************************/
865
866#define STRANGE 							\
867    xmlGenericError(xmlGenericErrorContext,				\
868	    "Internal error at %s:%d\n",				\
869            __FILE__, __LINE__);
870
871#ifdef LIBXML_DEBUG_ENABLED
872static void
873xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
874    int i;
875    char shift[100];
876
877    for (i = 0;((i < depth) && (i < 25));i++)
878        shift[2 * i] = shift[2 * i + 1] = ' ';
879    shift[2 * i] = shift[2 * i + 1] = 0;
880    if (cur == NULL) {
881	fprintf(output, shift);
882	fprintf(output, "Node is NULL !\n");
883	return;
884
885    }
886
887    if ((cur->type == XML_DOCUMENT_NODE) ||
888	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
889	fprintf(output, shift);
890	fprintf(output, " /\n");
891    } else if (cur->type == XML_ATTRIBUTE_NODE)
892	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
893    else
894	xmlDebugDumpOneNode(output, cur, depth);
895}
896static void
897xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
898    xmlNodePtr tmp;
899    int i;
900    char shift[100];
901
902    for (i = 0;((i < depth) && (i < 25));i++)
903        shift[2 * i] = shift[2 * i + 1] = ' ';
904    shift[2 * i] = shift[2 * i + 1] = 0;
905    if (cur == NULL) {
906	fprintf(output, shift);
907	fprintf(output, "Node is NULL !\n");
908	return;
909
910    }
911
912    while (cur != NULL) {
913	tmp = cur;
914	cur = cur->next;
915	xmlDebugDumpOneNode(output, tmp, depth);
916    }
917}
918
919static void
920xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
921    int i;
922    char shift[100];
923
924    for (i = 0;((i < depth) && (i < 25));i++)
925        shift[2 * i] = shift[2 * i + 1] = ' ';
926    shift[2 * i] = shift[2 * i + 1] = 0;
927
928    if (cur == NULL) {
929	fprintf(output, shift);
930	fprintf(output, "NodeSet is NULL !\n");
931	return;
932
933    }
934
935    if (cur != NULL) {
936	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
937	for (i = 0;i < cur->nodeNr;i++) {
938	    fprintf(output, shift);
939	    fprintf(output, "%d", i + 1);
940	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
941	}
942    }
943}
944
945static void
946xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
947    int i;
948    char shift[100];
949
950    for (i = 0;((i < depth) && (i < 25));i++)
951        shift[2 * i] = shift[2 * i + 1] = ' ';
952    shift[2 * i] = shift[2 * i + 1] = 0;
953
954    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
955	fprintf(output, shift);
956	fprintf(output, "Value Tree is NULL !\n");
957	return;
958
959    }
960
961    fprintf(output, shift);
962    fprintf(output, "%d", i + 1);
963    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
964}
965#if defined(LIBXML_XPTR_ENABLED)
966static void
967xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
968    int i;
969    char shift[100];
970
971    for (i = 0;((i < depth) && (i < 25));i++)
972        shift[2 * i] = shift[2 * i + 1] = ' ';
973    shift[2 * i] = shift[2 * i + 1] = 0;
974
975    if (cur == NULL) {
976	fprintf(output, shift);
977	fprintf(output, "LocationSet is NULL !\n");
978	return;
979
980    }
981
982    for (i = 0;i < cur->locNr;i++) {
983	fprintf(output, shift);
984        fprintf(output, "%d : ", i + 1);
985	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
986    }
987}
988#endif /* LIBXML_XPTR_ENABLED */
989
990/**
991 * xmlXPathDebugDumpObject:
992 * @output:  the FILE * to dump the output
993 * @cur:  the object to inspect
994 * @depth:  indentation level
995 *
996 * Dump the content of the object for debugging purposes
997 */
998void
999xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1000    int i;
1001    char shift[100];
1002
1003    if (output == NULL) return;
1004
1005    for (i = 0;((i < depth) && (i < 25));i++)
1006        shift[2 * i] = shift[2 * i + 1] = ' ';
1007    shift[2 * i] = shift[2 * i + 1] = 0;
1008
1009
1010    fprintf(output, shift);
1011
1012    if (cur == NULL) {
1013        fprintf(output, "Object is empty (NULL)\n");
1014	return;
1015    }
1016    switch(cur->type) {
1017        case XPATH_UNDEFINED:
1018	    fprintf(output, "Object is uninitialized\n");
1019	    break;
1020        case XPATH_NODESET:
1021	    fprintf(output, "Object is a Node Set :\n");
1022	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1023	    break;
1024	case XPATH_XSLT_TREE:
1025	    fprintf(output, "Object is an XSLT value tree :\n");
1026	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1027	    break;
1028        case XPATH_BOOLEAN:
1029	    fprintf(output, "Object is a Boolean : ");
1030	    if (cur->boolval) fprintf(output, "true\n");
1031	    else fprintf(output, "false\n");
1032	    break;
1033        case XPATH_NUMBER:
1034	    switch (xmlXPathIsInf(cur->floatval)) {
1035	    case 1:
1036		fprintf(output, "Object is a number : Infinity\n");
1037		break;
1038	    case -1:
1039		fprintf(output, "Object is a number : -Infinity\n");
1040		break;
1041	    default:
1042		if (xmlXPathIsNaN(cur->floatval)) {
1043		    fprintf(output, "Object is a number : NaN\n");
1044		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1045		    fprintf(output, "Object is a number : 0\n");
1046		} else {
1047		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1048		}
1049	    }
1050	    break;
1051        case XPATH_STRING:
1052	    fprintf(output, "Object is a string : ");
1053	    xmlDebugDumpString(output, cur->stringval);
1054	    fprintf(output, "\n");
1055	    break;
1056	case XPATH_POINT:
1057	    fprintf(output, "Object is a point : index %d in node", cur->index);
1058	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1059	    fprintf(output, "\n");
1060	    break;
1061	case XPATH_RANGE:
1062	    if ((cur->user2 == NULL) ||
1063		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1064		fprintf(output, "Object is a collapsed range :\n");
1065		fprintf(output, shift);
1066		if (cur->index >= 0)
1067		    fprintf(output, "index %d in ", cur->index);
1068		fprintf(output, "node\n");
1069		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1070			              depth + 1);
1071	    } else  {
1072		fprintf(output, "Object is a range :\n");
1073		fprintf(output, shift);
1074		fprintf(output, "From ");
1075		if (cur->index >= 0)
1076		    fprintf(output, "index %d in ", cur->index);
1077		fprintf(output, "node\n");
1078		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1079			              depth + 1);
1080		fprintf(output, shift);
1081		fprintf(output, "To ");
1082		if (cur->index2 >= 0)
1083		    fprintf(output, "index %d in ", cur->index2);
1084		fprintf(output, "node\n");
1085		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1086			              depth + 1);
1087		fprintf(output, "\n");
1088	    }
1089	    break;
1090	case XPATH_LOCATIONSET:
1091#if defined(LIBXML_XPTR_ENABLED)
1092	    fprintf(output, "Object is a Location Set:\n");
1093	    xmlXPathDebugDumpLocationSet(output,
1094		    (xmlLocationSetPtr) cur->user, depth);
1095#endif
1096	    break;
1097	case XPATH_USERS:
1098	    fprintf(output, "Object is user defined\n");
1099	    break;
1100    }
1101}
1102
1103static void
1104xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1105	                     xmlXPathStepOpPtr op, int depth) {
1106    int i;
1107    char shift[100];
1108
1109    for (i = 0;((i < depth) && (i < 25));i++)
1110        shift[2 * i] = shift[2 * i + 1] = ' ';
1111    shift[2 * i] = shift[2 * i + 1] = 0;
1112
1113    fprintf(output, shift);
1114    if (op == NULL) {
1115	fprintf(output, "Step is NULL\n");
1116	return;
1117    }
1118    switch (op->op) {
1119        case XPATH_OP_END:
1120	    fprintf(output, "END"); break;
1121        case XPATH_OP_AND:
1122	    fprintf(output, "AND"); break;
1123        case XPATH_OP_OR:
1124	    fprintf(output, "OR"); break;
1125        case XPATH_OP_EQUAL:
1126	     if (op->value)
1127		 fprintf(output, "EQUAL =");
1128	     else
1129		 fprintf(output, "EQUAL !=");
1130	     break;
1131        case XPATH_OP_CMP:
1132	     if (op->value)
1133		 fprintf(output, "CMP <");
1134	     else
1135		 fprintf(output, "CMP >");
1136	     if (!op->value2)
1137		 fprintf(output, "=");
1138	     break;
1139        case XPATH_OP_PLUS:
1140	     if (op->value == 0)
1141		 fprintf(output, "PLUS -");
1142	     else if (op->value == 1)
1143		 fprintf(output, "PLUS +");
1144	     else if (op->value == 2)
1145		 fprintf(output, "PLUS unary -");
1146	     else if (op->value == 3)
1147		 fprintf(output, "PLUS unary - -");
1148	     break;
1149        case XPATH_OP_MULT:
1150	     if (op->value == 0)
1151		 fprintf(output, "MULT *");
1152	     else if (op->value == 1)
1153		 fprintf(output, "MULT div");
1154	     else
1155		 fprintf(output, "MULT mod");
1156	     break;
1157        case XPATH_OP_UNION:
1158	     fprintf(output, "UNION"); break;
1159        case XPATH_OP_ROOT:
1160	     fprintf(output, "ROOT"); break;
1161        case XPATH_OP_NODE:
1162	     fprintf(output, "NODE"); break;
1163        case XPATH_OP_RESET:
1164	     fprintf(output, "RESET"); break;
1165        case XPATH_OP_SORT:
1166	     fprintf(output, "SORT"); break;
1167        case XPATH_OP_COLLECT: {
1168	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1169	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1170	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1171	    const xmlChar *prefix = op->value4;
1172	    const xmlChar *name = op->value5;
1173
1174	    fprintf(output, "COLLECT ");
1175	    switch (axis) {
1176		case AXIS_ANCESTOR:
1177		    fprintf(output, " 'ancestors' "); break;
1178		case AXIS_ANCESTOR_OR_SELF:
1179		    fprintf(output, " 'ancestors-or-self' "); break;
1180		case AXIS_ATTRIBUTE:
1181		    fprintf(output, " 'attributes' "); break;
1182		case AXIS_CHILD:
1183		    fprintf(output, " 'child' "); break;
1184		case AXIS_DESCENDANT:
1185		    fprintf(output, " 'descendant' "); break;
1186		case AXIS_DESCENDANT_OR_SELF:
1187		    fprintf(output, " 'descendant-or-self' "); break;
1188		case AXIS_FOLLOWING:
1189		    fprintf(output, " 'following' "); break;
1190		case AXIS_FOLLOWING_SIBLING:
1191		    fprintf(output, " 'following-siblings' "); break;
1192		case AXIS_NAMESPACE:
1193		    fprintf(output, " 'namespace' "); break;
1194		case AXIS_PARENT:
1195		    fprintf(output, " 'parent' "); break;
1196		case AXIS_PRECEDING:
1197		    fprintf(output, " 'preceding' "); break;
1198		case AXIS_PRECEDING_SIBLING:
1199		    fprintf(output, " 'preceding-sibling' "); break;
1200		case AXIS_SELF:
1201		    fprintf(output, " 'self' "); break;
1202	    }
1203	    switch (test) {
1204                case NODE_TEST_NONE:
1205		    fprintf(output, "'none' "); break;
1206                case NODE_TEST_TYPE:
1207		    fprintf(output, "'type' "); break;
1208                case NODE_TEST_PI:
1209		    fprintf(output, "'PI' "); break;
1210                case NODE_TEST_ALL:
1211		    fprintf(output, "'all' "); break;
1212                case NODE_TEST_NS:
1213		    fprintf(output, "'namespace' "); break;
1214                case NODE_TEST_NAME:
1215		    fprintf(output, "'name' "); break;
1216	    }
1217	    switch (type) {
1218                case NODE_TYPE_NODE:
1219		    fprintf(output, "'node' "); break;
1220                case NODE_TYPE_COMMENT:
1221		    fprintf(output, "'comment' "); break;
1222                case NODE_TYPE_TEXT:
1223		    fprintf(output, "'text' "); break;
1224                case NODE_TYPE_PI:
1225		    fprintf(output, "'PI' "); break;
1226	    }
1227	    if (prefix != NULL)
1228		fprintf(output, "%s:", prefix);
1229	    if (name != NULL)
1230		fprintf(output, "%s", (const char *) name);
1231	    break;
1232
1233        }
1234	case XPATH_OP_VALUE: {
1235	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1236
1237	    fprintf(output, "ELEM ");
1238	    xmlXPathDebugDumpObject(output, object, 0);
1239	    goto finish;
1240	}
1241	case XPATH_OP_VARIABLE: {
1242	    const xmlChar *prefix = op->value5;
1243	    const xmlChar *name = op->value4;
1244
1245	    if (prefix != NULL)
1246		fprintf(output, "VARIABLE %s:%s", prefix, name);
1247	    else
1248		fprintf(output, "VARIABLE %s", name);
1249	    break;
1250	}
1251	case XPATH_OP_FUNCTION: {
1252	    int nbargs = op->value;
1253	    const xmlChar *prefix = op->value5;
1254	    const xmlChar *name = op->value4;
1255
1256	    if (prefix != NULL)
1257		fprintf(output, "FUNCTION %s:%s(%d args)",
1258			prefix, name, nbargs);
1259	    else
1260		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1261	    break;
1262	}
1263        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1264        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1265        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1266#ifdef LIBXML_XPTR_ENABLED
1267        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1268#endif
1269	default:
1270        fprintf(output, "UNKNOWN %d\n", op->op); return;
1271    }
1272    fprintf(output, "\n");
1273finish:
1274    if (op->ch1 >= 0)
1275	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1276    if (op->ch2 >= 0)
1277	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1278}
1279
1280/**
1281 * xmlXPathDebugDumpCompExpr:
1282 * @output:  the FILE * for the output
1283 * @comp:  the precompiled XPath expression
1284 * @depth:  the indentation level.
1285 *
1286 * Dumps the tree of the compiled XPath expression.
1287 */
1288void
1289xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1290	                  int depth) {
1291    int i;
1292    char shift[100];
1293
1294    if ((output == NULL) || (comp == NULL)) return;
1295
1296    for (i = 0;((i < depth) && (i < 25));i++)
1297        shift[2 * i] = shift[2 * i + 1] = ' ';
1298    shift[2 * i] = shift[2 * i + 1] = 0;
1299
1300    fprintf(output, shift);
1301
1302    fprintf(output, "Compiled Expression : %d elements\n",
1303	    comp->nbStep);
1304    i = comp->last;
1305    xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1306}
1307
1308#ifdef XP_DEBUG_OBJ_USAGE
1309
1310/*
1311* XPath object usage related debugging variables.
1312*/
1313static int xmlXPathDebugObjCounterUndefined = 0;
1314static int xmlXPathDebugObjCounterNodeset = 0;
1315static int xmlXPathDebugObjCounterBool = 0;
1316static int xmlXPathDebugObjCounterNumber = 0;
1317static int xmlXPathDebugObjCounterString = 0;
1318static int xmlXPathDebugObjCounterPoint = 0;
1319static int xmlXPathDebugObjCounterRange = 0;
1320static int xmlXPathDebugObjCounterLocset = 0;
1321static int xmlXPathDebugObjCounterUsers = 0;
1322static int xmlXPathDebugObjCounterXSLTTree = 0;
1323static int xmlXPathDebugObjCounterAll = 0;
1324
1325static int xmlXPathDebugObjTotalUndefined = 0;
1326static int xmlXPathDebugObjTotalNodeset = 0;
1327static int xmlXPathDebugObjTotalBool = 0;
1328static int xmlXPathDebugObjTotalNumber = 0;
1329static int xmlXPathDebugObjTotalString = 0;
1330static int xmlXPathDebugObjTotalPoint = 0;
1331static int xmlXPathDebugObjTotalRange = 0;
1332static int xmlXPathDebugObjTotalLocset = 0;
1333static int xmlXPathDebugObjTotalUsers = 0;
1334static int xmlXPathDebugObjTotalXSLTTree = 0;
1335static int xmlXPathDebugObjTotalAll = 0;
1336
1337static int xmlXPathDebugObjMaxUndefined = 0;
1338static int xmlXPathDebugObjMaxNodeset = 0;
1339static int xmlXPathDebugObjMaxBool = 0;
1340static int xmlXPathDebugObjMaxNumber = 0;
1341static int xmlXPathDebugObjMaxString = 0;
1342static int xmlXPathDebugObjMaxPoint = 0;
1343static int xmlXPathDebugObjMaxRange = 0;
1344static int xmlXPathDebugObjMaxLocset = 0;
1345static int xmlXPathDebugObjMaxUsers = 0;
1346static int xmlXPathDebugObjMaxXSLTTree = 0;
1347static int xmlXPathDebugObjMaxAll = 0;
1348
1349/* REVISIT TODO: Make this static when committing */
1350static void
1351xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1352{
1353    if (ctxt != NULL) {
1354	if (ctxt->cache != NULL) {
1355	    xmlXPathContextCachePtr cache =
1356		(xmlXPathContextCachePtr) ctxt->cache;
1357
1358	    cache->dbgCachedAll = 0;
1359	    cache->dbgCachedNodeset = 0;
1360	    cache->dbgCachedString = 0;
1361	    cache->dbgCachedBool = 0;
1362	    cache->dbgCachedNumber = 0;
1363	    cache->dbgCachedPoint = 0;
1364	    cache->dbgCachedRange = 0;
1365	    cache->dbgCachedLocset = 0;
1366	    cache->dbgCachedUsers = 0;
1367	    cache->dbgCachedXSLTTree = 0;
1368	    cache->dbgCachedUndefined = 0;
1369
1370	    cache->dbgReusedAll = 0;
1371	    cache->dbgReusedNodeset = 0;
1372	    cache->dbgReusedString = 0;
1373	    cache->dbgReusedBool = 0;
1374	    cache->dbgReusedNumber = 0;
1375	    cache->dbgReusedPoint = 0;
1376	    cache->dbgReusedRange = 0;
1377	    cache->dbgReusedLocset = 0;
1378	    cache->dbgReusedUsers = 0;
1379	    cache->dbgReusedXSLTTree = 0;
1380	    cache->dbgReusedUndefined = 0;
1381	}
1382    }
1383
1384    xmlXPathDebugObjCounterUndefined = 0;
1385    xmlXPathDebugObjCounterNodeset = 0;
1386    xmlXPathDebugObjCounterBool = 0;
1387    xmlXPathDebugObjCounterNumber = 0;
1388    xmlXPathDebugObjCounterString = 0;
1389    xmlXPathDebugObjCounterPoint = 0;
1390    xmlXPathDebugObjCounterRange = 0;
1391    xmlXPathDebugObjCounterLocset = 0;
1392    xmlXPathDebugObjCounterUsers = 0;
1393    xmlXPathDebugObjCounterXSLTTree = 0;
1394    xmlXPathDebugObjCounterAll = 0;
1395
1396    xmlXPathDebugObjTotalUndefined = 0;
1397    xmlXPathDebugObjTotalNodeset = 0;
1398    xmlXPathDebugObjTotalBool = 0;
1399    xmlXPathDebugObjTotalNumber = 0;
1400    xmlXPathDebugObjTotalString = 0;
1401    xmlXPathDebugObjTotalPoint = 0;
1402    xmlXPathDebugObjTotalRange = 0;
1403    xmlXPathDebugObjTotalLocset = 0;
1404    xmlXPathDebugObjTotalUsers = 0;
1405    xmlXPathDebugObjTotalXSLTTree = 0;
1406    xmlXPathDebugObjTotalAll = 0;
1407
1408    xmlXPathDebugObjMaxUndefined = 0;
1409    xmlXPathDebugObjMaxNodeset = 0;
1410    xmlXPathDebugObjMaxBool = 0;
1411    xmlXPathDebugObjMaxNumber = 0;
1412    xmlXPathDebugObjMaxString = 0;
1413    xmlXPathDebugObjMaxPoint = 0;
1414    xmlXPathDebugObjMaxRange = 0;
1415    xmlXPathDebugObjMaxLocset = 0;
1416    xmlXPathDebugObjMaxUsers = 0;
1417    xmlXPathDebugObjMaxXSLTTree = 0;
1418    xmlXPathDebugObjMaxAll = 0;
1419
1420}
1421
1422static void
1423xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1424			      xmlXPathObjectType objType)
1425{
1426    int isCached = 0;
1427
1428    if (ctxt != NULL) {
1429	if (ctxt->cache != NULL) {
1430	    xmlXPathContextCachePtr cache =
1431		(xmlXPathContextCachePtr) ctxt->cache;
1432
1433	    isCached = 1;
1434
1435	    cache->dbgReusedAll++;
1436	    switch (objType) {
1437		case XPATH_UNDEFINED:
1438		    cache->dbgReusedUndefined++;
1439		    break;
1440		case XPATH_NODESET:
1441		    cache->dbgReusedNodeset++;
1442		    break;
1443		case XPATH_BOOLEAN:
1444		    cache->dbgReusedBool++;
1445		    break;
1446		case XPATH_NUMBER:
1447		    cache->dbgReusedNumber++;
1448		    break;
1449		case XPATH_STRING:
1450		    cache->dbgReusedString++;
1451		    break;
1452		case XPATH_POINT:
1453		    cache->dbgReusedPoint++;
1454		    break;
1455		case XPATH_RANGE:
1456		    cache->dbgReusedRange++;
1457		    break;
1458		case XPATH_LOCATIONSET:
1459		    cache->dbgReusedLocset++;
1460		    break;
1461		case XPATH_USERS:
1462		    cache->dbgReusedUsers++;
1463		    break;
1464		case XPATH_XSLT_TREE:
1465		    cache->dbgReusedXSLTTree++;
1466		    break;
1467		default:
1468		    break;
1469	    }
1470	}
1471    }
1472
1473    switch (objType) {
1474	case XPATH_UNDEFINED:
1475	    if (! isCached)
1476		xmlXPathDebugObjTotalUndefined++;
1477	    xmlXPathDebugObjCounterUndefined++;
1478	    if (xmlXPathDebugObjCounterUndefined >
1479		xmlXPathDebugObjMaxUndefined)
1480		xmlXPathDebugObjMaxUndefined =
1481		    xmlXPathDebugObjCounterUndefined;
1482	    break;
1483	case XPATH_NODESET:
1484	    if (! isCached)
1485		xmlXPathDebugObjTotalNodeset++;
1486	    xmlXPathDebugObjCounterNodeset++;
1487	    if (xmlXPathDebugObjCounterNodeset >
1488		xmlXPathDebugObjMaxNodeset)
1489		xmlXPathDebugObjMaxNodeset =
1490		    xmlXPathDebugObjCounterNodeset;
1491	    break;
1492	case XPATH_BOOLEAN:
1493	    if (! isCached)
1494		xmlXPathDebugObjTotalBool++;
1495	    xmlXPathDebugObjCounterBool++;
1496	    if (xmlXPathDebugObjCounterBool >
1497		xmlXPathDebugObjMaxBool)
1498		xmlXPathDebugObjMaxBool =
1499		    xmlXPathDebugObjCounterBool;
1500	    break;
1501	case XPATH_NUMBER:
1502	    if (! isCached)
1503		xmlXPathDebugObjTotalNumber++;
1504	    xmlXPathDebugObjCounterNumber++;
1505	    if (xmlXPathDebugObjCounterNumber >
1506		xmlXPathDebugObjMaxNumber)
1507		xmlXPathDebugObjMaxNumber =
1508		    xmlXPathDebugObjCounterNumber;
1509	    break;
1510	case XPATH_STRING:
1511	    if (! isCached)
1512		xmlXPathDebugObjTotalString++;
1513	    xmlXPathDebugObjCounterString++;
1514	    if (xmlXPathDebugObjCounterString >
1515		xmlXPathDebugObjMaxString)
1516		xmlXPathDebugObjMaxString =
1517		    xmlXPathDebugObjCounterString;
1518	    break;
1519	case XPATH_POINT:
1520	    if (! isCached)
1521		xmlXPathDebugObjTotalPoint++;
1522	    xmlXPathDebugObjCounterPoint++;
1523	    if (xmlXPathDebugObjCounterPoint >
1524		xmlXPathDebugObjMaxPoint)
1525		xmlXPathDebugObjMaxPoint =
1526		    xmlXPathDebugObjCounterPoint;
1527	    break;
1528	case XPATH_RANGE:
1529	    if (! isCached)
1530		xmlXPathDebugObjTotalRange++;
1531	    xmlXPathDebugObjCounterRange++;
1532	    if (xmlXPathDebugObjCounterRange >
1533		xmlXPathDebugObjMaxRange)
1534		xmlXPathDebugObjMaxRange =
1535		    xmlXPathDebugObjCounterRange;
1536	    break;
1537	case XPATH_LOCATIONSET:
1538	    if (! isCached)
1539		xmlXPathDebugObjTotalLocset++;
1540	    xmlXPathDebugObjCounterLocset++;
1541	    if (xmlXPathDebugObjCounterLocset >
1542		xmlXPathDebugObjMaxLocset)
1543		xmlXPathDebugObjMaxLocset =
1544		    xmlXPathDebugObjCounterLocset;
1545	    break;
1546	case XPATH_USERS:
1547	    if (! isCached)
1548		xmlXPathDebugObjTotalUsers++;
1549	    xmlXPathDebugObjCounterUsers++;
1550	    if (xmlXPathDebugObjCounterUsers >
1551		xmlXPathDebugObjMaxUsers)
1552		xmlXPathDebugObjMaxUsers =
1553		    xmlXPathDebugObjCounterUsers;
1554	    break;
1555	case XPATH_XSLT_TREE:
1556	    if (! isCached)
1557		xmlXPathDebugObjTotalXSLTTree++;
1558	    xmlXPathDebugObjCounterXSLTTree++;
1559	    if (xmlXPathDebugObjCounterXSLTTree >
1560		xmlXPathDebugObjMaxXSLTTree)
1561		xmlXPathDebugObjMaxXSLTTree =
1562		    xmlXPathDebugObjCounterXSLTTree;
1563	    break;
1564	default:
1565	    break;
1566    }
1567    if (! isCached)
1568	xmlXPathDebugObjTotalAll++;
1569    xmlXPathDebugObjCounterAll++;
1570    if (xmlXPathDebugObjCounterAll >
1571	xmlXPathDebugObjMaxAll)
1572	xmlXPathDebugObjMaxAll =
1573	    xmlXPathDebugObjCounterAll;
1574}
1575
1576static void
1577xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1578			      xmlXPathObjectType objType)
1579{
1580    int isCached = 0;
1581
1582    if (ctxt != NULL) {
1583	if (ctxt->cache != NULL) {
1584	    xmlXPathContextCachePtr cache =
1585		(xmlXPathContextCachePtr) ctxt->cache;
1586
1587	    isCached = 1;
1588
1589	    cache->dbgCachedAll++;
1590	    switch (objType) {
1591		case XPATH_UNDEFINED:
1592		    cache->dbgCachedUndefined++;
1593		    break;
1594		case XPATH_NODESET:
1595		    cache->dbgCachedNodeset++;
1596		    break;
1597		case XPATH_BOOLEAN:
1598		    cache->dbgCachedBool++;
1599		    break;
1600		case XPATH_NUMBER:
1601		    cache->dbgCachedNumber++;
1602		    break;
1603		case XPATH_STRING:
1604		    cache->dbgCachedString++;
1605		    break;
1606		case XPATH_POINT:
1607		    cache->dbgCachedPoint++;
1608		    break;
1609		case XPATH_RANGE:
1610		    cache->dbgCachedRange++;
1611		    break;
1612		case XPATH_LOCATIONSET:
1613		    cache->dbgCachedLocset++;
1614		    break;
1615		case XPATH_USERS:
1616		    cache->dbgCachedUsers++;
1617		    break;
1618		case XPATH_XSLT_TREE:
1619		    cache->dbgCachedXSLTTree++;
1620		    break;
1621		default:
1622		    break;
1623	    }
1624
1625	}
1626    }
1627    switch (objType) {
1628	case XPATH_UNDEFINED:
1629	    xmlXPathDebugObjCounterUndefined--;
1630	    break;
1631	case XPATH_NODESET:
1632	    xmlXPathDebugObjCounterNodeset--;
1633	    break;
1634	case XPATH_BOOLEAN:
1635	    xmlXPathDebugObjCounterBool--;
1636	    break;
1637	case XPATH_NUMBER:
1638	    xmlXPathDebugObjCounterNumber--;
1639	    break;
1640	case XPATH_STRING:
1641	    xmlXPathDebugObjCounterString--;
1642	    break;
1643	case XPATH_POINT:
1644	    xmlXPathDebugObjCounterPoint--;
1645	    break;
1646	case XPATH_RANGE:
1647	    xmlXPathDebugObjCounterRange--;
1648	    break;
1649	case XPATH_LOCATIONSET:
1650	    xmlXPathDebugObjCounterLocset--;
1651	    break;
1652	case XPATH_USERS:
1653	    xmlXPathDebugObjCounterUsers--;
1654	    break;
1655	case XPATH_XSLT_TREE:
1656	    xmlXPathDebugObjCounterXSLTTree--;
1657	    break;
1658	default:
1659	    break;
1660    }
1661    xmlXPathDebugObjCounterAll--;
1662}
1663
1664/* REVISIT TODO: Make this static when committing */
1665static void
1666xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1667{
1668    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1669	reqXSLTTree, reqUndefined;
1670    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1671	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1672    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1673	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1674    int leftObjs = xmlXPathDebugObjCounterAll;
1675
1676    reqAll = xmlXPathDebugObjTotalAll;
1677    reqNodeset = xmlXPathDebugObjTotalNodeset;
1678    reqString = xmlXPathDebugObjTotalString;
1679    reqBool = xmlXPathDebugObjTotalBool;
1680    reqNumber = xmlXPathDebugObjTotalNumber;
1681    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1682    reqUndefined = xmlXPathDebugObjTotalUndefined;
1683
1684    printf("# XPath object usage:\n");
1685
1686    if (ctxt != NULL) {
1687	if (ctxt->cache != NULL) {
1688	    xmlXPathContextCachePtr cache =
1689		(xmlXPathContextCachePtr) ctxt->cache;
1690
1691	    reAll = cache->dbgReusedAll;
1692	    reqAll += reAll;
1693	    reNodeset = cache->dbgReusedNodeset;
1694	    reqNodeset += reNodeset;
1695	    reString = cache->dbgReusedString;
1696	    reqString += reString;
1697	    reBool = cache->dbgReusedBool;
1698	    reqBool += reBool;
1699	    reNumber = cache->dbgReusedNumber;
1700	    reqNumber += reNumber;
1701	    reXSLTTree = cache->dbgReusedXSLTTree;
1702	    reqXSLTTree += reXSLTTree;
1703	    reUndefined = cache->dbgReusedUndefined;
1704	    reqUndefined += reUndefined;
1705
1706	    caAll = cache->dbgCachedAll;
1707	    caBool = cache->dbgCachedBool;
1708	    caNodeset = cache->dbgCachedNodeset;
1709	    caString = cache->dbgCachedString;
1710	    caNumber = cache->dbgCachedNumber;
1711	    caXSLTTree = cache->dbgCachedXSLTTree;
1712	    caUndefined = cache->dbgCachedUndefined;
1713
1714	    if (cache->nodesetObjs)
1715		leftObjs -= cache->nodesetObjs->number;
1716	    if (cache->stringObjs)
1717		leftObjs -= cache->stringObjs->number;
1718	    if (cache->booleanObjs)
1719		leftObjs -= cache->booleanObjs->number;
1720	    if (cache->numberObjs)
1721		leftObjs -= cache->numberObjs->number;
1722	    if (cache->miscObjs)
1723		leftObjs -= cache->miscObjs->number;
1724	}
1725    }
1726
1727    printf("# all\n");
1728    printf("#   total  : %d\n", reqAll);
1729    printf("#   left  : %d\n", leftObjs);
1730    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
1731    printf("#   reused : %d\n", reAll);
1732    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
1733
1734    printf("# node-sets\n");
1735    printf("#   total  : %d\n", reqNodeset);
1736    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
1737    printf("#   reused : %d\n", reNodeset);
1738    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
1739
1740    printf("# strings\n");
1741    printf("#   total  : %d\n", reqString);
1742    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
1743    printf("#   reused : %d\n", reString);
1744    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
1745
1746    printf("# booleans\n");
1747    printf("#   total  : %d\n", reqBool);
1748    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
1749    printf("#   reused : %d\n", reBool);
1750    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
1751
1752    printf("# numbers\n");
1753    printf("#   total  : %d\n", reqNumber);
1754    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
1755    printf("#   reused : %d\n", reNumber);
1756    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
1757
1758    printf("# XSLT result tree fragments\n");
1759    printf("#   total  : %d\n", reqXSLTTree);
1760    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1761    printf("#   reused : %d\n", reXSLTTree);
1762    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
1763
1764    printf("# undefined\n");
1765    printf("#   total  : %d\n", reqUndefined);
1766    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
1767    printf("#   reused : %d\n", reUndefined);
1768    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
1769
1770}
1771
1772#endif /* XP_DEBUG_OBJ_USAGE */
1773
1774#endif /* LIBXML_DEBUG_ENABLED */
1775
1776/************************************************************************
1777 *									*
1778 *			XPath object caching				*
1779 *									*
1780 ************************************************************************/
1781
1782/**
1783 * xmlXPathNewCache:
1784 *
1785 * Create a new object cache
1786 *
1787 * Returns the xmlXPathCache just allocated.
1788 */
1789static xmlXPathContextCachePtr
1790xmlXPathNewCache(void)
1791{
1792    xmlXPathContextCachePtr ret;
1793
1794    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1795    if (ret == NULL) {
1796        xmlXPathErrMemory(NULL, "creating object cache\n");
1797	return(NULL);
1798    }
1799    memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1800    ret->maxNodeset = 100;
1801    ret->maxString = 100;
1802    ret->maxBoolean = 100;
1803    ret->maxNumber = 100;
1804    ret->maxMisc = 100;
1805    return(ret);
1806}
1807
1808static void
1809xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1810{
1811    int i;
1812    xmlXPathObjectPtr obj;
1813
1814    if (list == NULL)
1815	return;
1816
1817    for (i = 0; i < list->number; i++) {
1818	obj = list->items[i];
1819	/*
1820	* Note that it is already assured that we don't need to
1821	* look out for namespace nodes in the node-set.
1822	*/
1823	if (obj->nodesetval != NULL) {
1824	    if (obj->nodesetval->nodeTab != NULL)
1825		xmlFree(obj->nodesetval->nodeTab);
1826	    xmlFree(obj->nodesetval);
1827	}
1828	xmlFree(obj);
1829#ifdef XP_DEBUG_OBJ_USAGE
1830	xmlXPathDebugObjCounterAll--;
1831#endif
1832    }
1833    xmlPointerListFree(list);
1834}
1835
1836static void
1837xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1838{
1839    if (cache == NULL)
1840	return;
1841    if (cache->nodesetObjs)
1842	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1843    if (cache->stringObjs)
1844	xmlXPathCacheFreeObjectList(cache->stringObjs);
1845    if (cache->booleanObjs)
1846	xmlXPathCacheFreeObjectList(cache->booleanObjs);
1847    if (cache->numberObjs)
1848	xmlXPathCacheFreeObjectList(cache->numberObjs);
1849    if (cache->miscObjs)
1850	xmlXPathCacheFreeObjectList(cache->miscObjs);
1851    xmlFree(cache);
1852}
1853
1854/**
1855 * xmlXPathContextSetCache:
1856 *
1857 * @ctxt:  the XPath context
1858 * @active: enables/disables (creates/frees) the cache
1859 * @value: a value with semantics dependant on @options
1860 * @options: options (currently only the value 0 is used)
1861 *
1862 * Creates/frees an object cache on the XPath context.
1863 * If activates XPath objects (xmlXPathObject) will be cached internally
1864 * to be reused.
1865 * @options:
1866 *   0: This will set the XPath object caching:
1867 *      @value:
1868 *        This will set the maximum number of XPath objects
1869 *        to be cached per slot
1870 *        There are 5 slots for: node-set, string, number, boolean, and
1871 *        misc objects. Use <0 for the default number (100).
1872 *   Other values for @options have currently no effect.
1873 *
1874 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1875 */
1876int
1877xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1878			int active,
1879			int value,
1880			int options)
1881{
1882    if (ctxt == NULL)
1883	return(-1);
1884    if (active) {
1885	xmlXPathContextCachePtr cache;
1886
1887	if (ctxt->cache == NULL) {
1888	    ctxt->cache = xmlXPathNewCache();
1889	    if (ctxt->cache == NULL)
1890		return(-1);
1891	}
1892	cache = (xmlXPathContextCachePtr) ctxt->cache;
1893	if (options == 0) {
1894	    if (value < 0)
1895		value = 100;
1896	    cache->maxNodeset = value;
1897	    cache->maxString = value;
1898	    cache->maxNumber = value;
1899	    cache->maxBoolean = value;
1900	    cache->maxMisc = value;
1901	}
1902    } else if (ctxt->cache != NULL) {
1903	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1904	ctxt->cache = NULL;
1905    }
1906    return(0);
1907}
1908
1909/**
1910 * xmlXPathCacheWrapNodeSet:
1911 * @ctxt: the XPath context
1912 * @val:  the NodePtr value
1913 *
1914 * This is the cached version of xmlXPathWrapNodeSet().
1915 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1916 *
1917 * Returns the created or reused object.
1918 */
1919static xmlXPathObjectPtr
1920xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1921{
1922    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1923	xmlXPathContextCachePtr cache =
1924	    (xmlXPathContextCachePtr) ctxt->cache;
1925
1926	if ((cache->miscObjs != NULL) &&
1927	    (cache->miscObjs->number != 0))
1928	{
1929	    xmlXPathObjectPtr ret;
1930
1931	    ret = (xmlXPathObjectPtr)
1932		cache->miscObjs->items[--cache->miscObjs->number];
1933	    ret->type = XPATH_NODESET;
1934	    ret->nodesetval = val;
1935#ifdef XP_DEBUG_OBJ_USAGE
1936	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1937#endif
1938	    return(ret);
1939	}
1940    }
1941
1942    return(xmlXPathWrapNodeSet(val));
1943
1944}
1945
1946/**
1947 * xmlXPathCacheWrapString:
1948 * @ctxt: the XPath context
1949 * @val:  the xmlChar * value
1950 *
1951 * This is the cached version of xmlXPathWrapString().
1952 * Wraps the @val string into an XPath object.
1953 *
1954 * Returns the created or reused object.
1955 */
1956static xmlXPathObjectPtr
1957xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1958{
1959    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1960	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1961
1962	if ((cache->stringObjs != NULL) &&
1963	    (cache->stringObjs->number != 0))
1964	{
1965
1966	    xmlXPathObjectPtr ret;
1967
1968	    ret = (xmlXPathObjectPtr)
1969		cache->stringObjs->items[--cache->stringObjs->number];
1970	    ret->type = XPATH_STRING;
1971	    ret->stringval = val;
1972#ifdef XP_DEBUG_OBJ_USAGE
1973	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1974#endif
1975	    return(ret);
1976	} else if ((cache->miscObjs != NULL) &&
1977	    (cache->miscObjs->number != 0))
1978	{
1979	    xmlXPathObjectPtr ret;
1980	    /*
1981	    * Fallback to misc-cache.
1982	    */
1983	    ret = (xmlXPathObjectPtr)
1984		cache->miscObjs->items[--cache->miscObjs->number];
1985
1986	    ret->type = XPATH_STRING;
1987	    ret->stringval = val;
1988#ifdef XP_DEBUG_OBJ_USAGE
1989	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1990#endif
1991	    return(ret);
1992	}
1993    }
1994    return(xmlXPathWrapString(val));
1995}
1996
1997/**
1998 * xmlXPathCacheNewNodeSet:
1999 * @ctxt: the XPath context
2000 * @val:  the NodePtr value
2001 *
2002 * This is the cached version of xmlXPathNewNodeSet().
2003 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2004 * it with the single Node @val
2005 *
2006 * Returns the created or reused object.
2007 */
2008static xmlXPathObjectPtr
2009xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2010{
2011    if ((ctxt != NULL) && (ctxt->cache)) {
2012	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2013
2014	if ((cache->nodesetObjs != NULL) &&
2015	    (cache->nodesetObjs->number != 0))
2016	{
2017	    xmlXPathObjectPtr ret;
2018	    /*
2019	    * Use the nodset-cache.
2020	    */
2021	    ret = (xmlXPathObjectPtr)
2022		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2023	    ret->type = XPATH_NODESET;
2024	    ret->boolval = 0;
2025	    if (val) {
2026		if ((ret->nodesetval->nodeMax == 0) ||
2027		    (val->type == XML_NAMESPACE_DECL))
2028		{
2029		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2030		} else {
2031		    ret->nodesetval->nodeTab[0] = val;
2032		    ret->nodesetval->nodeNr = 1;
2033		}
2034	    }
2035#ifdef XP_DEBUG_OBJ_USAGE
2036	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2037#endif
2038	    return(ret);
2039	} else if ((cache->miscObjs != NULL) &&
2040	    (cache->miscObjs->number != 0))
2041	{
2042	    xmlXPathObjectPtr ret;
2043	    /*
2044	    * Fallback to misc-cache.
2045	    */
2046
2047	    ret = (xmlXPathObjectPtr)
2048		cache->miscObjs->items[--cache->miscObjs->number];
2049
2050	    ret->type = XPATH_NODESET;
2051	    ret->boolval = 0;
2052	    ret->nodesetval = xmlXPathNodeSetCreate(val);
2053#ifdef XP_DEBUG_OBJ_USAGE
2054	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2055#endif
2056	    return(ret);
2057	}
2058    }
2059    return(xmlXPathNewNodeSet(val));
2060}
2061
2062/**
2063 * xmlXPathCacheNewCString:
2064 * @ctxt: the XPath context
2065 * @val:  the char * value
2066 *
2067 * This is the cached version of xmlXPathNewCString().
2068 * Acquire an xmlXPathObjectPtr of type string and of value @val
2069 *
2070 * Returns the created or reused object.
2071 */
2072static xmlXPathObjectPtr
2073xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2074{
2075    if ((ctxt != NULL) && (ctxt->cache)) {
2076	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2077
2078	if ((cache->stringObjs != NULL) &&
2079	    (cache->stringObjs->number != 0))
2080	{
2081	    xmlXPathObjectPtr ret;
2082
2083	    ret = (xmlXPathObjectPtr)
2084		cache->stringObjs->items[--cache->stringObjs->number];
2085
2086	    ret->type = XPATH_STRING;
2087	    ret->stringval = xmlStrdup(BAD_CAST val);
2088#ifdef XP_DEBUG_OBJ_USAGE
2089	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2090#endif
2091	    return(ret);
2092	} else if ((cache->miscObjs != NULL) &&
2093	    (cache->miscObjs->number != 0))
2094	{
2095	    xmlXPathObjectPtr ret;
2096
2097	    ret = (xmlXPathObjectPtr)
2098		cache->miscObjs->items[--cache->miscObjs->number];
2099
2100	    ret->type = XPATH_STRING;
2101	    ret->stringval = xmlStrdup(BAD_CAST val);
2102#ifdef XP_DEBUG_OBJ_USAGE
2103	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2104#endif
2105	    return(ret);
2106	}
2107    }
2108    return(xmlXPathNewCString(val));
2109}
2110
2111/**
2112 * xmlXPathCacheNewString:
2113 * @ctxt: the XPath context
2114 * @val:  the xmlChar * value
2115 *
2116 * This is the cached version of xmlXPathNewString().
2117 * Acquire an xmlXPathObjectPtr of type string and of value @val
2118 *
2119 * Returns the created or reused object.
2120 */
2121static xmlXPathObjectPtr
2122xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2123{
2124    if ((ctxt != NULL) && (ctxt->cache)) {
2125	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2126
2127	if ((cache->stringObjs != NULL) &&
2128	    (cache->stringObjs->number != 0))
2129	{
2130	    xmlXPathObjectPtr ret;
2131
2132	    ret = (xmlXPathObjectPtr)
2133		cache->stringObjs->items[--cache->stringObjs->number];
2134	    ret->type = XPATH_STRING;
2135	    if (val != NULL)
2136		ret->stringval = xmlStrdup(val);
2137	    else
2138		ret->stringval = xmlStrdup((const xmlChar *)"");
2139#ifdef XP_DEBUG_OBJ_USAGE
2140	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2141#endif
2142	    return(ret);
2143	} else if ((cache->miscObjs != NULL) &&
2144	    (cache->miscObjs->number != 0))
2145	{
2146	    xmlXPathObjectPtr ret;
2147
2148	    ret = (xmlXPathObjectPtr)
2149		cache->miscObjs->items[--cache->miscObjs->number];
2150
2151	    ret->type = XPATH_STRING;
2152	    if (val != NULL)
2153		ret->stringval = xmlStrdup(val);
2154	    else
2155		ret->stringval = xmlStrdup((const xmlChar *)"");
2156#ifdef XP_DEBUG_OBJ_USAGE
2157	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2158#endif
2159	    return(ret);
2160	}
2161    }
2162    return(xmlXPathNewString(val));
2163}
2164
2165/**
2166 * xmlXPathCacheNewBoolean:
2167 * @ctxt: the XPath context
2168 * @val:  the boolean value
2169 *
2170 * This is the cached version of xmlXPathNewBoolean().
2171 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2172 *
2173 * Returns the created or reused object.
2174 */
2175static xmlXPathObjectPtr
2176xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2177{
2178    if ((ctxt != NULL) && (ctxt->cache)) {
2179	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2180
2181	if ((cache->booleanObjs != NULL) &&
2182	    (cache->booleanObjs->number != 0))
2183	{
2184	    xmlXPathObjectPtr ret;
2185
2186	    ret = (xmlXPathObjectPtr)
2187		cache->booleanObjs->items[--cache->booleanObjs->number];
2188	    ret->type = XPATH_BOOLEAN;
2189	    ret->boolval = (val != 0);
2190#ifdef XP_DEBUG_OBJ_USAGE
2191	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2192#endif
2193	    return(ret);
2194	} else if ((cache->miscObjs != NULL) &&
2195	    (cache->miscObjs->number != 0))
2196	{
2197	    xmlXPathObjectPtr ret;
2198
2199	    ret = (xmlXPathObjectPtr)
2200		cache->miscObjs->items[--cache->miscObjs->number];
2201
2202	    ret->type = XPATH_BOOLEAN;
2203	    ret->boolval = (val != 0);
2204#ifdef XP_DEBUG_OBJ_USAGE
2205	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2206#endif
2207	    return(ret);
2208	}
2209    }
2210    return(xmlXPathNewBoolean(val));
2211}
2212
2213/**
2214 * xmlXPathCacheNewFloat:
2215 * @ctxt: the XPath context
2216 * @val:  the double value
2217 *
2218 * This is the cached version of xmlXPathNewFloat().
2219 * Acquires an xmlXPathObjectPtr of type double and of value @val
2220 *
2221 * Returns the created or reused object.
2222 */
2223static xmlXPathObjectPtr
2224xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2225{
2226     if ((ctxt != NULL) && (ctxt->cache)) {
2227	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2228
2229	if ((cache->numberObjs != NULL) &&
2230	    (cache->numberObjs->number != 0))
2231	{
2232	    xmlXPathObjectPtr ret;
2233
2234	    ret = (xmlXPathObjectPtr)
2235		cache->numberObjs->items[--cache->numberObjs->number];
2236	    ret->type = XPATH_NUMBER;
2237	    ret->floatval = val;
2238#ifdef XP_DEBUG_OBJ_USAGE
2239	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2240#endif
2241	    return(ret);
2242	} else if ((cache->miscObjs != NULL) &&
2243	    (cache->miscObjs->number != 0))
2244	{
2245	    xmlXPathObjectPtr ret;
2246
2247	    ret = (xmlXPathObjectPtr)
2248		cache->miscObjs->items[--cache->miscObjs->number];
2249
2250	    ret->type = XPATH_NUMBER;
2251	    ret->floatval = val;
2252#ifdef XP_DEBUG_OBJ_USAGE
2253	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2254#endif
2255	    return(ret);
2256	}
2257    }
2258    return(xmlXPathNewFloat(val));
2259}
2260
2261/**
2262 * xmlXPathCacheConvertString:
2263 * @ctxt: the XPath context
2264 * @val:  an XPath object
2265 *
2266 * This is the cached version of xmlXPathConvertString().
2267 * Converts an existing object to its string() equivalent
2268 *
2269 * Returns a created or reused object, the old one is freed (cached)
2270 *         (or the operation is done directly on @val)
2271 */
2272
2273static xmlXPathObjectPtr
2274xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2275    xmlChar *res = NULL;
2276
2277    if (val == NULL)
2278	return(xmlXPathCacheNewCString(ctxt, ""));
2279
2280    switch (val->type) {
2281    case XPATH_UNDEFINED:
2282#ifdef DEBUG_EXPR
2283	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2284#endif
2285	break;
2286    case XPATH_NODESET:
2287    case XPATH_XSLT_TREE:
2288	res = xmlXPathCastNodeSetToString(val->nodesetval);
2289	break;
2290    case XPATH_STRING:
2291	return(val);
2292    case XPATH_BOOLEAN:
2293	res = xmlXPathCastBooleanToString(val->boolval);
2294	break;
2295    case XPATH_NUMBER:
2296	res = xmlXPathCastNumberToString(val->floatval);
2297	break;
2298    case XPATH_USERS:
2299    case XPATH_POINT:
2300    case XPATH_RANGE:
2301    case XPATH_LOCATIONSET:
2302	TODO;
2303	break;
2304    }
2305    xmlXPathReleaseObject(ctxt, val);
2306    if (res == NULL)
2307	return(xmlXPathCacheNewCString(ctxt, ""));
2308    return(xmlXPathCacheWrapString(ctxt, res));
2309}
2310
2311/**
2312 * xmlXPathCacheObjectCopy:
2313 * @ctxt: the XPath context
2314 * @val:  the original object
2315 *
2316 * This is the cached version of xmlXPathObjectCopy().
2317 * Acquire a copy of a given object
2318 *
2319 * Returns a created or reused created object.
2320 */
2321static xmlXPathObjectPtr
2322xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2323{
2324    if (val == NULL)
2325	return(NULL);
2326
2327    if (XP_HAS_CACHE(ctxt)) {
2328	switch (val->type) {
2329	    case XPATH_NODESET:
2330		return(xmlXPathCacheWrapNodeSet(ctxt,
2331		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2332	    case XPATH_STRING:
2333		return(xmlXPathCacheNewString(ctxt, val->stringval));
2334	    case XPATH_BOOLEAN:
2335		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2336	    case XPATH_NUMBER:
2337		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2338	    default:
2339		break;
2340	}
2341    }
2342    return(xmlXPathObjectCopy(val));
2343}
2344
2345/**
2346 * xmlXPathCacheConvertBoolean:
2347 * @ctxt: the XPath context
2348 * @val:  an XPath object
2349 *
2350 * This is the cached version of xmlXPathConvertBoolean().
2351 * Converts an existing object to its boolean() equivalent
2352 *
2353 * Returns a created or reused object, the old one is freed (or the operation
2354 *         is done directly on @val)
2355 */
2356static xmlXPathObjectPtr
2357xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2358    xmlXPathObjectPtr ret;
2359
2360    if (val == NULL)
2361	return(xmlXPathCacheNewBoolean(ctxt, 0));
2362    if (val->type == XPATH_BOOLEAN)
2363	return(val);
2364    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2365    xmlXPathReleaseObject(ctxt, val);
2366    return(ret);
2367}
2368
2369/**
2370 * xmlXPathCacheConvertNumber:
2371 * @ctxt: the XPath context
2372 * @val:  an XPath object
2373 *
2374 * This is the cached version of xmlXPathConvertNumber().
2375 * Converts an existing object to its number() equivalent
2376 *
2377 * Returns a created or reused object, the old one is freed (or the operation
2378 *         is done directly on @val)
2379 */
2380static xmlXPathObjectPtr
2381xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2382    xmlXPathObjectPtr ret;
2383
2384    if (val == NULL)
2385	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2386    if (val->type == XPATH_NUMBER)
2387	return(val);
2388    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2389    xmlXPathReleaseObject(ctxt, val);
2390    return(ret);
2391}
2392
2393/************************************************************************
2394 *									*
2395 * 		Parser stacks related functions and macros		*
2396 *									*
2397 ************************************************************************/
2398
2399/**
2400 * valuePop:
2401 * @ctxt: an XPath evaluation context
2402 *
2403 * Pops the top XPath object from the value stack
2404 *
2405 * Returns the XPath object just removed
2406 */
2407xmlXPathObjectPtr
2408valuePop(xmlXPathParserContextPtr ctxt)
2409{
2410    xmlXPathObjectPtr ret;
2411
2412    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2413        return (NULL);
2414    ctxt->valueNr--;
2415    if (ctxt->valueNr > 0)
2416        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2417    else
2418        ctxt->value = NULL;
2419    ret = ctxt->valueTab[ctxt->valueNr];
2420    ctxt->valueTab[ctxt->valueNr] = NULL;
2421    return (ret);
2422}
2423/**
2424 * valuePush:
2425 * @ctxt:  an XPath evaluation context
2426 * @value:  the XPath object
2427 *
2428 * Pushes a new XPath object on top of the value stack
2429 *
2430 * returns the number of items on the value stack
2431 */
2432int
2433valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2434{
2435    if ((ctxt == NULL) || (value == NULL)) return(-1);
2436    if (ctxt->valueNr >= ctxt->valueMax) {
2437        xmlXPathObjectPtr *tmp;
2438
2439        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2440                                             2 * ctxt->valueMax *
2441                                             sizeof(ctxt->valueTab[0]));
2442        if (tmp == NULL) {
2443            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2444            return (0);
2445        }
2446        ctxt->valueMax *= 2;
2447	ctxt->valueTab = tmp;
2448    }
2449    ctxt->valueTab[ctxt->valueNr] = value;
2450    ctxt->value = value;
2451    return (ctxt->valueNr++);
2452}
2453
2454/**
2455 * xmlXPathPopBoolean:
2456 * @ctxt:  an XPath parser context
2457 *
2458 * Pops a boolean from the stack, handling conversion if needed.
2459 * Check error with #xmlXPathCheckError.
2460 *
2461 * Returns the boolean
2462 */
2463int
2464xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2465    xmlXPathObjectPtr obj;
2466    int ret;
2467
2468    obj = valuePop(ctxt);
2469    if (obj == NULL) {
2470	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2471	return(0);
2472    }
2473    if (obj->type != XPATH_BOOLEAN)
2474	ret = xmlXPathCastToBoolean(obj);
2475    else
2476        ret = obj->boolval;
2477    xmlXPathReleaseObject(ctxt->context, obj);
2478    return(ret);
2479}
2480
2481/**
2482 * xmlXPathPopNumber:
2483 * @ctxt:  an XPath parser context
2484 *
2485 * Pops a number from the stack, handling conversion if needed.
2486 * Check error with #xmlXPathCheckError.
2487 *
2488 * Returns the number
2489 */
2490double
2491xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2492    xmlXPathObjectPtr obj;
2493    double ret;
2494
2495    obj = valuePop(ctxt);
2496    if (obj == NULL) {
2497	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2498	return(0);
2499    }
2500    if (obj->type != XPATH_NUMBER)
2501	ret = xmlXPathCastToNumber(obj);
2502    else
2503        ret = obj->floatval;
2504    xmlXPathReleaseObject(ctxt->context, obj);
2505    return(ret);
2506}
2507
2508/**
2509 * xmlXPathPopString:
2510 * @ctxt:  an XPath parser context
2511 *
2512 * Pops a string from the stack, handling conversion if needed.
2513 * Check error with #xmlXPathCheckError.
2514 *
2515 * Returns the string
2516 */
2517xmlChar *
2518xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2519    xmlXPathObjectPtr obj;
2520    xmlChar * ret;
2521
2522    obj = valuePop(ctxt);
2523    if (obj == NULL) {
2524	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2525	return(NULL);
2526    }
2527    ret = xmlXPathCastToString(obj);	/* this does required strdup */
2528    /* TODO: needs refactoring somewhere else */
2529    if (obj->stringval == ret)
2530	obj->stringval = NULL;
2531    xmlXPathReleaseObject(ctxt->context, obj);
2532    return(ret);
2533}
2534
2535/**
2536 * xmlXPathPopNodeSet:
2537 * @ctxt:  an XPath parser context
2538 *
2539 * Pops a node-set from the stack, handling conversion if needed.
2540 * Check error with #xmlXPathCheckError.
2541 *
2542 * Returns the node-set
2543 */
2544xmlNodeSetPtr
2545xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2546    xmlXPathObjectPtr obj;
2547    xmlNodeSetPtr ret;
2548
2549    if (ctxt == NULL) return(NULL);
2550    if (ctxt->value == NULL) {
2551	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2552	return(NULL);
2553    }
2554    if (!xmlXPathStackIsNodeSet(ctxt)) {
2555	xmlXPathSetTypeError(ctxt);
2556	return(NULL);
2557    }
2558    obj = valuePop(ctxt);
2559    ret = obj->nodesetval;
2560#if 0
2561    /* to fix memory leak of not clearing obj->user */
2562    if (obj->boolval && obj->user != NULL)
2563        xmlFreeNodeList((xmlNodePtr) obj->user);
2564#endif
2565    obj->nodesetval = NULL;
2566    xmlXPathReleaseObject(ctxt->context, obj);
2567    return(ret);
2568}
2569
2570/**
2571 * xmlXPathPopExternal:
2572 * @ctxt:  an XPath parser context
2573 *
2574 * Pops an external object from the stack, handling conversion if needed.
2575 * Check error with #xmlXPathCheckError.
2576 *
2577 * Returns the object
2578 */
2579void *
2580xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2581    xmlXPathObjectPtr obj;
2582    void * ret;
2583
2584    if ((ctxt == NULL) || (ctxt->value == NULL)) {
2585	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2586	return(NULL);
2587    }
2588    if (ctxt->value->type != XPATH_USERS) {
2589	xmlXPathSetTypeError(ctxt);
2590	return(NULL);
2591    }
2592    obj = valuePop(ctxt);
2593    ret = obj->user;
2594    obj->user = NULL;
2595    xmlXPathReleaseObject(ctxt->context, obj);
2596    return(ret);
2597}
2598
2599/*
2600 * Macros for accessing the content. Those should be used only by the parser,
2601 * and not exported.
2602 *
2603 * Dirty macros, i.e. one need to make assumption on the context to use them
2604 *
2605 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2606 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2607 *           in ISO-Latin or UTF-8.
2608 *           This should be used internally by the parser
2609 *           only to compare to ASCII values otherwise it would break when
2610 *           running with UTF-8 encoding.
2611 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2612 *           to compare on ASCII based substring.
2613 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2614 *           strings within the parser.
2615 *   CURRENT Returns the current char value, with the full decoding of
2616 *           UTF-8 if we are using this mode. It returns an int.
2617 *   NEXT    Skip to the next character, this does the proper decoding
2618 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2619 *           It returns the pointer to the current xmlChar.
2620 */
2621
2622#define CUR (*ctxt->cur)
2623#define SKIP(val) ctxt->cur += (val)
2624#define NXT(val) ctxt->cur[(val)]
2625#define CUR_PTR ctxt->cur
2626#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2627
2628#define COPY_BUF(l,b,i,v)                                              \
2629    if (l == 1) b[i++] = (xmlChar) v;                                  \
2630    else i += xmlCopyChar(l,&b[i],v)
2631
2632#define NEXTL(l)  ctxt->cur += l
2633
2634#define SKIP_BLANKS 							\
2635    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2636
2637#define CURRENT (*ctxt->cur)
2638#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2639
2640
2641#ifndef DBL_DIG
2642#define DBL_DIG 16
2643#endif
2644#ifndef DBL_EPSILON
2645#define DBL_EPSILON 1E-9
2646#endif
2647
2648#define UPPER_DOUBLE 1E9
2649#define LOWER_DOUBLE 1E-5
2650
2651#define INTEGER_DIGITS DBL_DIG
2652#define FRACTION_DIGITS (DBL_DIG + 1)
2653#define EXPONENT_DIGITS (3 + 2)
2654
2655/**
2656 * xmlXPathFormatNumber:
2657 * @number:     number to format
2658 * @buffer:     output buffer
2659 * @buffersize: size of output buffer
2660 *
2661 * Convert the number into a string representation.
2662 */
2663static void
2664xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2665{
2666    switch (xmlXPathIsInf(number)) {
2667    case 1:
2668	if (buffersize > (int)sizeof("Infinity"))
2669	    snprintf(buffer, buffersize, "Infinity");
2670	break;
2671    case -1:
2672	if (buffersize > (int)sizeof("-Infinity"))
2673	    snprintf(buffer, buffersize, "-Infinity");
2674	break;
2675    default:
2676	if (xmlXPathIsNaN(number)) {
2677	    if (buffersize > (int)sizeof("NaN"))
2678		snprintf(buffer, buffersize, "NaN");
2679	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
2680	    snprintf(buffer, buffersize, "0");
2681	} else if (number == ((int) number)) {
2682	    char work[30];
2683	    char *ptr, *cur;
2684	    int value = (int) number;
2685
2686            ptr = &buffer[0];
2687	    if (value == 0) {
2688		*ptr++ = '0';
2689	    } else {
2690		snprintf(work, 29, "%d", value);
2691		cur = &work[0];
2692		while ((*cur) && (ptr - buffer < buffersize)) {
2693		    *ptr++ = *cur++;
2694		}
2695	    }
2696	    if (ptr - buffer < buffersize) {
2697		*ptr = 0;
2698	    } else if (buffersize > 0) {
2699		ptr--;
2700		*ptr = 0;
2701	    }
2702	} else {
2703	    /* 3 is sign, decimal point, and terminating zero */
2704	    char work[DBL_DIG + EXPONENT_DIGITS + 3];
2705	    int integer_place, fraction_place;
2706	    char *ptr;
2707	    char *after_fraction;
2708	    double absolute_value;
2709	    int size;
2710
2711	    absolute_value = fabs(number);
2712
2713	    /*
2714	     * First choose format - scientific or regular floating point.
2715	     * In either case, result is in work, and after_fraction points
2716	     * just past the fractional part.
2717	    */
2718	    if ( ((absolute_value > UPPER_DOUBLE) ||
2719		  (absolute_value < LOWER_DOUBLE)) &&
2720		 (absolute_value != 0.0) ) {
2721		/* Use scientific notation */
2722		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2723		fraction_place = DBL_DIG - 1;
2724		size = snprintf(work, sizeof(work),"%*.*e",
2725			 integer_place, fraction_place, number);
2726		while ((size > 0) && (work[size] != 'e')) size--;
2727		after_fraction = work + size;
2728
2729	    }
2730	    else {
2731		/* Use regular notation */
2732		if (absolute_value > 0.0)
2733		    integer_place = 1 + (int)log10(absolute_value);
2734		else
2735		    integer_place = 0;
2736		fraction_place = (integer_place > 0)
2737		    ? DBL_DIG - integer_place
2738		    : DBL_DIG;
2739		size = snprintf(work, sizeof(work), "%0.*f",
2740				fraction_place, number);
2741		after_fraction = work + size;
2742	    }
2743
2744	    /* Remove fractional trailing zeroes */
2745	    ptr = after_fraction;
2746	    while (*(--ptr) == '0')
2747		;
2748	    if (*ptr != '.')
2749	        ptr++;
2750	    while ((*ptr++ = *after_fraction++) != 0);
2751
2752	    /* Finally copy result back to caller */
2753	    size = strlen(work) + 1;
2754	    if (size > buffersize) {
2755		work[buffersize - 1] = 0;
2756		size = buffersize;
2757	    }
2758	    memmove(buffer, work, size);
2759	}
2760	break;
2761    }
2762}
2763
2764
2765/************************************************************************
2766 *									*
2767 *			Routines to handle NodeSets			*
2768 *									*
2769 ************************************************************************/
2770
2771/**
2772 * xmlXPathOrderDocElems:
2773 * @doc:  an input document
2774 *
2775 * Call this routine to speed up XPath computation on static documents.
2776 * This stamps all the element nodes with the document order
2777 * Like for line information, the order is kept in the element->content
2778 * field, the value stored is actually - the node number (starting at -1)
2779 * to be able to differentiate from line numbers.
2780 *
2781 * Returns the number of elements found in the document or -1 in case
2782 *    of error.
2783 */
2784long
2785xmlXPathOrderDocElems(xmlDocPtr doc) {
2786    long count = 0;
2787    xmlNodePtr cur;
2788
2789    if (doc == NULL)
2790	return(-1);
2791    cur = doc->children;
2792    while (cur != NULL) {
2793	if (cur->type == XML_ELEMENT_NODE) {
2794	    cur->content = (void *) (-(++count));
2795	    if (cur->children != NULL) {
2796		cur = cur->children;
2797		continue;
2798	    }
2799	}
2800	if (cur->next != NULL) {
2801	    cur = cur->next;
2802	    continue;
2803	}
2804	do {
2805	    cur = cur->parent;
2806	    if (cur == NULL)
2807		break;
2808	    if (cur == (xmlNodePtr) doc) {
2809		cur = NULL;
2810		break;
2811	    }
2812	    if (cur->next != NULL) {
2813		cur = cur->next;
2814		break;
2815	    }
2816	} while (cur != NULL);
2817    }
2818    return(count);
2819}
2820
2821/**
2822 * xmlXPathCmpNodes:
2823 * @node1:  the first node
2824 * @node2:  the second node
2825 *
2826 * Compare two nodes w.r.t document order
2827 *
2828 * Returns -2 in case of error 1 if first point < second point, 0 if
2829 *         it's the same node, -1 otherwise
2830 */
2831int
2832xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2833    int depth1, depth2;
2834    int attr1 = 0, attr2 = 0;
2835    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2836    xmlNodePtr cur, root;
2837
2838    if ((node1 == NULL) || (node2 == NULL))
2839	return(-2);
2840    /*
2841     * a couple of optimizations which will avoid computations in most cases
2842     */
2843    if (node1->type == XML_ATTRIBUTE_NODE) {
2844	attr1 = 1;
2845	attrNode1 = node1;
2846	node1 = node1->parent;
2847    }
2848    if (node2->type == XML_ATTRIBUTE_NODE) {
2849	attr2 = 1;
2850	attrNode2 = node2;
2851	node2 = node2->parent;
2852    }
2853    if (node1 == node2) {
2854	if (attr1 == attr2) {
2855	    /* not required, but we keep attributes in order */
2856	    if (attr1 != 0) {
2857	        cur = attrNode2->prev;
2858		while (cur != NULL) {
2859		    if (cur == attrNode1)
2860		        return (1);
2861		    cur = cur->prev;
2862		}
2863		return (-1);
2864	    }
2865	    return(0);
2866	}
2867	if (attr2 == 1)
2868	    return(1);
2869	return(-1);
2870    }
2871    if ((node1->type == XML_NAMESPACE_DECL) ||
2872        (node2->type == XML_NAMESPACE_DECL))
2873	return(1);
2874    if (node1 == node2->prev)
2875	return(1);
2876    if (node1 == node2->next)
2877	return(-1);
2878
2879    /*
2880     * Speedup using document order if availble.
2881     */
2882    if ((node1->type == XML_ELEMENT_NODE) &&
2883	(node2->type == XML_ELEMENT_NODE) &&
2884	(0 > (long) node1->content) &&
2885	(0 > (long) node2->content) &&
2886	(node1->doc == node2->doc)) {
2887	long l1, l2;
2888
2889	l1 = -((long) node1->content);
2890	l2 = -((long) node2->content);
2891	if (l1 < l2)
2892	    return(1);
2893	if (l1 > l2)
2894	    return(-1);
2895    }
2896
2897    /*
2898     * compute depth to root
2899     */
2900    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2901	if (cur == node1)
2902	    return(1);
2903	depth2++;
2904    }
2905    root = cur;
2906    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2907	if (cur == node2)
2908	    return(-1);
2909	depth1++;
2910    }
2911    /*
2912     * Distinct document (or distinct entities :-( ) case.
2913     */
2914    if (root != cur) {
2915	return(-2);
2916    }
2917    /*
2918     * get the nearest common ancestor.
2919     */
2920    while (depth1 > depth2) {
2921	depth1--;
2922	node1 = node1->parent;
2923    }
2924    while (depth2 > depth1) {
2925	depth2--;
2926	node2 = node2->parent;
2927    }
2928    while (node1->parent != node2->parent) {
2929	node1 = node1->parent;
2930	node2 = node2->parent;
2931	/* should not happen but just in case ... */
2932	if ((node1 == NULL) || (node2 == NULL))
2933	    return(-2);
2934    }
2935    /*
2936     * Find who's first.
2937     */
2938    if (node1 == node2->prev)
2939	return(1);
2940    if (node1 == node2->next)
2941	return(-1);
2942    /*
2943     * Speedup using document order if availble.
2944     */
2945    if ((node1->type == XML_ELEMENT_NODE) &&
2946	(node2->type == XML_ELEMENT_NODE) &&
2947	(0 > (long) node1->content) &&
2948	(0 > (long) node2->content) &&
2949	(node1->doc == node2->doc)) {
2950	long l1, l2;
2951
2952	l1 = -((long) node1->content);
2953	l2 = -((long) node2->content);
2954	if (l1 < l2)
2955	    return(1);
2956	if (l1 > l2)
2957	    return(-1);
2958    }
2959
2960    for (cur = node1->next;cur != NULL;cur = cur->next)
2961	if (cur == node2)
2962	    return(1);
2963    return(-1); /* assume there is no sibling list corruption */
2964}
2965
2966#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2967/**
2968 * xmlXPathCmpNodesExt:
2969 * @node1:  the first node
2970 * @node2:  the second node
2971 *
2972 * Compare two nodes w.r.t document order.
2973 * This one is optimized for handling of non-element nodes.
2974 *
2975 * Returns -2 in case of error 1 if first point < second point, 0 if
2976 *         it's the same node, -1 otherwise
2977 */
2978static int
2979xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2980    int depth1, depth2;
2981    int misc = 0, precedence1 = 0, precedence2 = 0;
2982    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2983    xmlNodePtr cur, root;
2984    long l1, l2;
2985
2986    if ((node1 == NULL) || (node2 == NULL))
2987	return(-2);
2988
2989    if (node1 == node2)
2990	return(0);
2991
2992    /*
2993     * a couple of optimizations which will avoid computations in most cases
2994     */
2995    switch (node1->type) {
2996	case XML_ELEMENT_NODE:
2997	    if (node2->type == XML_ELEMENT_NODE) {
2998		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
2999		    (0 > (long) node2->content) &&
3000		    (node1->doc == node2->doc))
3001		{
3002		    l1 = -((long) node1->content);
3003		    l2 = -((long) node2->content);
3004		    if (l1 < l2)
3005			return(1);
3006		    if (l1 > l2)
3007			return(-1);
3008		} else
3009		    goto turtle_comparison;
3010	    }
3011	    break;
3012	case XML_ATTRIBUTE_NODE:
3013	    precedence1 = 1; /* element is owner */
3014	    miscNode1 = node1;
3015	    node1 = node1->parent;
3016	    misc = 1;
3017	    break;
3018	case XML_TEXT_NODE:
3019	case XML_CDATA_SECTION_NODE:
3020	case XML_COMMENT_NODE:
3021	case XML_PI_NODE: {
3022	    miscNode1 = node1;
3023	    /*
3024	    * Find nearest element node.
3025	    */
3026	    if (node1->prev != NULL) {
3027		do {
3028		    node1 = node1->prev;
3029		    if (node1->type == XML_ELEMENT_NODE) {
3030			precedence1 = 3; /* element in prev-sibl axis */
3031			break;
3032		    }
3033		    if (node1->prev == NULL) {
3034			precedence1 = 2; /* element is parent */
3035			/*
3036			* URGENT TODO: Are there any cases, where the
3037			* parent of such a node is not an element node?
3038			*/
3039			node1 = node1->parent;
3040			break;
3041		    }
3042		} while (1);
3043	    } else {
3044		precedence1 = 2; /* element is parent */
3045		node1 = node1->parent;
3046	    }
3047	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
3048		/*
3049		* Fallback for whatever case.
3050		*/
3051		node1 = miscNode1;
3052		precedence1 = 0;
3053	    } else
3054		misc = 1;
3055	}
3056	    break;
3057	case XML_NAMESPACE_DECL:
3058	    /*
3059	    * TODO: why do we return 1 for namespace nodes?
3060	    */
3061	    return(1);
3062	default:
3063	    break;
3064    }
3065    switch (node2->type) {
3066	case XML_ELEMENT_NODE:
3067	    break;
3068	case XML_ATTRIBUTE_NODE:
3069	    precedence2 = 1; /* element is owner */
3070	    miscNode2 = node2;
3071	    node2 = node2->parent;
3072	    misc = 1;
3073	    break;
3074	case XML_TEXT_NODE:
3075	case XML_CDATA_SECTION_NODE:
3076	case XML_COMMENT_NODE:
3077	case XML_PI_NODE: {
3078	    miscNode2 = node2;
3079	    if (node2->prev != NULL) {
3080		do {
3081		    node2 = node2->prev;
3082		    if (node2->type == XML_ELEMENT_NODE) {
3083			precedence2 = 3; /* element in prev-sibl axis */
3084			break;
3085		    }
3086		    if (node2->prev == NULL) {
3087			precedence2 = 2; /* element is parent */
3088			node2 = node2->parent;
3089			break;
3090		    }
3091		} while (1);
3092	    } else {
3093		precedence2 = 2; /* element is parent */
3094		node2 = node2->parent;
3095	    }
3096	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3097		(0 <= (long) node1->content))
3098	    {
3099		node2 = miscNode2;
3100		precedence2 = 0;
3101	    } else
3102		misc = 1;
3103	}
3104	    break;
3105	case XML_NAMESPACE_DECL:
3106	    return(1);
3107	default:
3108	    break;
3109    }
3110    if (misc) {
3111	if (node1 == node2) {
3112	    if (precedence1 == precedence2) {
3113		/*
3114		* The ugly case; but normally there aren't many
3115		* adjacent non-element nodes around.
3116		*/
3117		cur = miscNode2->prev;
3118		while (cur != NULL) {
3119		    if (cur == miscNode1)
3120			return(1);
3121		    if (cur->type == XML_ELEMENT_NODE)
3122			return(-1);
3123		    cur = cur->prev;
3124		}
3125		return (-1);
3126	    } else {
3127		/*
3128		* Evaluate based on higher precedence wrt to the element.
3129		* TODO: This assumes attributes are sorted before content.
3130		*   Is this 100% correct?
3131		*/
3132		if (precedence1 < precedence2)
3133		    return(1);
3134		else
3135		    return(-1);
3136	    }
3137	}
3138	/*
3139	* Special case: One of the helper-elements is contained by the other.
3140	* <foo>
3141	*   <node2>
3142	*     <node1>Text-1(precedence1 == 2)</node1>
3143	*   </node2>
3144	*   Text-6(precedence2 == 3)
3145	* </foo>
3146	*/
3147	if ((precedence2 == 3) && (precedence1 > 1)) {
3148	    cur = node1->parent;
3149	    while (cur) {
3150		if (cur == node2)
3151		    return(1);
3152		cur = cur->parent;
3153	    }
3154	}
3155	if ((precedence1 == 3) && (precedence2 > 1)) {
3156	    cur = node2->parent;
3157	    while (cur) {
3158		if (cur == node1)
3159		    return(-1);
3160		cur = cur->parent;
3161	    }
3162	}
3163    }
3164
3165    /*
3166     * Speedup using document order if availble.
3167     */
3168    if ((node1->type == XML_ELEMENT_NODE) &&
3169	(node2->type == XML_ELEMENT_NODE) &&
3170	(0 > (long) node1->content) &&
3171	(0 > (long) node2->content) &&
3172	(node1->doc == node2->doc)) {
3173
3174	l1 = -((long) node1->content);
3175	l2 = -((long) node2->content);
3176	if (l1 < l2)
3177	    return(1);
3178	if (l1 > l2)
3179	    return(-1);
3180    }
3181
3182turtle_comparison:
3183
3184    if (node1 == node2->prev)
3185	return(1);
3186    if (node1 == node2->next)
3187	return(-1);
3188    /*
3189     * compute depth to root
3190     */
3191    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3192	if (cur == node1)
3193	    return(1);
3194	depth2++;
3195    }
3196    root = cur;
3197    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3198	if (cur == node2)
3199	    return(-1);
3200	depth1++;
3201    }
3202    /*
3203     * Distinct document (or distinct entities :-( ) case.
3204     */
3205    if (root != cur) {
3206	return(-2);
3207    }
3208    /*
3209     * get the nearest common ancestor.
3210     */
3211    while (depth1 > depth2) {
3212	depth1--;
3213	node1 = node1->parent;
3214    }
3215    while (depth2 > depth1) {
3216	depth2--;
3217	node2 = node2->parent;
3218    }
3219    while (node1->parent != node2->parent) {
3220	node1 = node1->parent;
3221	node2 = node2->parent;
3222	/* should not happen but just in case ... */
3223	if ((node1 == NULL) || (node2 == NULL))
3224	    return(-2);
3225    }
3226    /*
3227     * Find who's first.
3228     */
3229    if (node1 == node2->prev)
3230	return(1);
3231    if (node1 == node2->next)
3232	return(-1);
3233    /*
3234     * Speedup using document order if availble.
3235     */
3236    if ((node1->type == XML_ELEMENT_NODE) &&
3237	(node2->type == XML_ELEMENT_NODE) &&
3238	(0 > (long) node1->content) &&
3239	(0 > (long) node2->content) &&
3240	(node1->doc == node2->doc)) {
3241
3242	l1 = -((long) node1->content);
3243	l2 = -((long) node2->content);
3244	if (l1 < l2)
3245	    return(1);
3246	if (l1 > l2)
3247	    return(-1);
3248    }
3249
3250    for (cur = node1->next;cur != NULL;cur = cur->next)
3251	if (cur == node2)
3252	    return(1);
3253    return(-1); /* assume there is no sibling list corruption */
3254}
3255#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3256
3257/**
3258 * xmlXPathNodeSetSort:
3259 * @set:  the node set
3260 *
3261 * Sort the node set in document order
3262 */
3263void
3264xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3265    int i, j, incr, len;
3266    xmlNodePtr tmp;
3267
3268    if (set == NULL)
3269	return;
3270
3271    /* Use Shell's sort to sort the node-set */
3272    len = set->nodeNr;
3273    for (incr = len / 2; incr > 0; incr /= 2) {
3274	for (i = incr; i < len; i++) {
3275	    j = i - incr;
3276	    while (j >= 0) {
3277#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3278		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3279			set->nodeTab[j + incr]) == -1)
3280#else
3281		if (xmlXPathCmpNodes(set->nodeTab[j],
3282			set->nodeTab[j + incr]) == -1)
3283#endif
3284		{
3285		    tmp = set->nodeTab[j];
3286		    set->nodeTab[j] = set->nodeTab[j + incr];
3287		    set->nodeTab[j + incr] = tmp;
3288		    j -= incr;
3289		} else
3290		    break;
3291	    }
3292	}
3293    }
3294}
3295
3296#define XML_NODESET_DEFAULT	10
3297/**
3298 * xmlXPathNodeSetDupNs:
3299 * @node:  the parent node of the namespace XPath node
3300 * @ns:  the libxml namespace declaration node.
3301 *
3302 * Namespace node in libxml don't match the XPath semantic. In a node set
3303 * the namespace nodes are duplicated and the next pointer is set to the
3304 * parent node in the XPath semantic.
3305 *
3306 * Returns the newly created object.
3307 */
3308static xmlNodePtr
3309xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3310    xmlNsPtr cur;
3311
3312    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3313	return(NULL);
3314    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3315	return((xmlNodePtr) ns);
3316
3317    /*
3318     * Allocate a new Namespace and fill the fields.
3319     */
3320    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3321    if (cur == NULL) {
3322        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3323	return(NULL);
3324    }
3325    memset(cur, 0, sizeof(xmlNs));
3326    cur->type = XML_NAMESPACE_DECL;
3327    if (ns->href != NULL)
3328	cur->href = xmlStrdup(ns->href);
3329    if (ns->prefix != NULL)
3330	cur->prefix = xmlStrdup(ns->prefix);
3331    cur->next = (xmlNsPtr) node;
3332    return((xmlNodePtr) cur);
3333}
3334
3335/**
3336 * xmlXPathNodeSetFreeNs:
3337 * @ns:  the XPath namespace node found in a nodeset.
3338 *
3339 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3340 * the namespace nodes are duplicated and the next pointer is set to the
3341 * parent node in the XPath semantic. Check if such a node needs to be freed
3342 */
3343void
3344xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3345    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3346	return;
3347
3348    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3349	if (ns->href != NULL)
3350	    xmlFree((xmlChar *)ns->href);
3351	if (ns->prefix != NULL)
3352	    xmlFree((xmlChar *)ns->prefix);
3353	xmlFree(ns);
3354    }
3355}
3356
3357/**
3358 * xmlXPathNodeSetCreate:
3359 * @val:  an initial xmlNodePtr, or NULL
3360 *
3361 * Create a new xmlNodeSetPtr of type double and of value @val
3362 *
3363 * Returns the newly created object.
3364 */
3365xmlNodeSetPtr
3366xmlXPathNodeSetCreate(xmlNodePtr val) {
3367    xmlNodeSetPtr ret;
3368
3369    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3370    if (ret == NULL) {
3371        xmlXPathErrMemory(NULL, "creating nodeset\n");
3372	return(NULL);
3373    }
3374    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3375    if (val != NULL) {
3376        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3377					     sizeof(xmlNodePtr));
3378	if (ret->nodeTab == NULL) {
3379	    xmlXPathErrMemory(NULL, "creating nodeset\n");
3380	    xmlFree(ret);
3381	    return(NULL);
3382	}
3383	memset(ret->nodeTab, 0 ,
3384	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3385        ret->nodeMax = XML_NODESET_DEFAULT;
3386	if (val->type == XML_NAMESPACE_DECL) {
3387	    xmlNsPtr ns = (xmlNsPtr) val;
3388
3389	    ret->nodeTab[ret->nodeNr++] =
3390		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3391	} else
3392	    ret->nodeTab[ret->nodeNr++] = val;
3393    }
3394    return(ret);
3395}
3396
3397/**
3398 * xmlXPathNodeSetCreateSize:
3399 * @size:  the initial size of the set
3400 *
3401 * Create a new xmlNodeSetPtr of type double and of value @val
3402 *
3403 * Returns the newly created object.
3404 */
3405static xmlNodeSetPtr
3406xmlXPathNodeSetCreateSize(int size) {
3407    xmlNodeSetPtr ret;
3408
3409    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3410    if (ret == NULL) {
3411        xmlXPathErrMemory(NULL, "creating nodeset\n");
3412	return(NULL);
3413    }
3414    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3415    if (size < XML_NODESET_DEFAULT)
3416	size = XML_NODESET_DEFAULT;
3417    ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3418    if (ret->nodeTab == NULL) {
3419	xmlXPathErrMemory(NULL, "creating nodeset\n");
3420	xmlFree(ret);
3421	return(NULL);
3422    }
3423    memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3424    ret->nodeMax = size;
3425    return(ret);
3426}
3427
3428/**
3429 * xmlXPathNodeSetContains:
3430 * @cur:  the node-set
3431 * @val:  the node
3432 *
3433 * checks whether @cur contains @val
3434 *
3435 * Returns true (1) if @cur contains @val, false (0) otherwise
3436 */
3437int
3438xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3439    int i;
3440
3441    if ((cur == NULL) || (val == NULL)) return(0);
3442    if (val->type == XML_NAMESPACE_DECL) {
3443	for (i = 0; i < cur->nodeNr; i++) {
3444	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3445		xmlNsPtr ns1, ns2;
3446
3447		ns1 = (xmlNsPtr) val;
3448		ns2 = (xmlNsPtr) cur->nodeTab[i];
3449		if (ns1 == ns2)
3450		    return(1);
3451		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3452	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3453		    return(1);
3454	    }
3455	}
3456    } else {
3457	for (i = 0; i < cur->nodeNr; i++) {
3458	    if (cur->nodeTab[i] == val)
3459		return(1);
3460	}
3461    }
3462    return(0);
3463}
3464
3465/**
3466 * xmlXPathNodeSetAddNs:
3467 * @cur:  the initial node set
3468 * @node:  the hosting node
3469 * @ns:  a the namespace node
3470 *
3471 * add a new namespace node to an existing NodeSet
3472 */
3473void
3474xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3475    int i;
3476
3477
3478    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3479        (ns->type != XML_NAMESPACE_DECL) ||
3480	(node->type != XML_ELEMENT_NODE))
3481	return;
3482
3483    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3484    /*
3485     * prevent duplicates
3486     */
3487    for (i = 0;i < cur->nodeNr;i++) {
3488        if ((cur->nodeTab[i] != NULL) &&
3489	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3490	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3491	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3492	    return;
3493    }
3494
3495    /*
3496     * grow the nodeTab if needed
3497     */
3498    if (cur->nodeMax == 0) {
3499        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3500					     sizeof(xmlNodePtr));
3501	if (cur->nodeTab == NULL) {
3502	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3503	    return;
3504	}
3505	memset(cur->nodeTab, 0 ,
3506	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3507        cur->nodeMax = XML_NODESET_DEFAULT;
3508    } else if (cur->nodeNr == cur->nodeMax) {
3509        xmlNodePtr *temp;
3510
3511        cur->nodeMax *= 2;
3512	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3513				      sizeof(xmlNodePtr));
3514	if (temp == NULL) {
3515	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3516	    return;
3517	}
3518	cur->nodeTab = temp;
3519    }
3520    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3521}
3522
3523/**
3524 * xmlXPathNodeSetAdd:
3525 * @cur:  the initial node set
3526 * @val:  a new xmlNodePtr
3527 *
3528 * add a new xmlNodePtr to an existing NodeSet
3529 */
3530void
3531xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3532    int i;
3533
3534    if ((cur == NULL) || (val == NULL)) return;
3535
3536#if 0
3537    if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3538	return;	/* an XSLT fake node */
3539#endif
3540
3541    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3542    /*
3543     * prevent duplcates
3544     */
3545    for (i = 0;i < cur->nodeNr;i++)
3546        if (cur->nodeTab[i] == val) return;
3547
3548    /*
3549     * grow the nodeTab if needed
3550     */
3551    if (cur->nodeMax == 0) {
3552        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3553					     sizeof(xmlNodePtr));
3554	if (cur->nodeTab == NULL) {
3555	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3556	    return;
3557	}
3558	memset(cur->nodeTab, 0 ,
3559	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3560        cur->nodeMax = XML_NODESET_DEFAULT;
3561    } else if (cur->nodeNr == cur->nodeMax) {
3562        xmlNodePtr *temp;
3563
3564        cur->nodeMax *= 2;
3565	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3566				      sizeof(xmlNodePtr));
3567	if (temp == NULL) {
3568	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3569	    return;
3570	}
3571	cur->nodeTab = temp;
3572    }
3573    if (val->type == XML_NAMESPACE_DECL) {
3574	xmlNsPtr ns = (xmlNsPtr) val;
3575
3576	cur->nodeTab[cur->nodeNr++] =
3577	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3578    } else
3579	cur->nodeTab[cur->nodeNr++] = val;
3580}
3581
3582/**
3583 * xmlXPathNodeSetAddUnique:
3584 * @cur:  the initial node set
3585 * @val:  a new xmlNodePtr
3586 *
3587 * add a new xmlNodePtr to an existing NodeSet, optimized version
3588 * when we are sure the node is not already in the set.
3589 */
3590void
3591xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3592    if ((cur == NULL) || (val == NULL)) return;
3593
3594#if 0
3595    if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3596	return;	/* an XSLT fake node */
3597#endif
3598
3599    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3600    /*
3601     * grow the nodeTab if needed
3602     */
3603    if (cur->nodeMax == 0) {
3604        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3605					     sizeof(xmlNodePtr));
3606	if (cur->nodeTab == NULL) {
3607	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3608	    return;
3609	}
3610	memset(cur->nodeTab, 0 ,
3611	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3612        cur->nodeMax = XML_NODESET_DEFAULT;
3613    } else if (cur->nodeNr == cur->nodeMax) {
3614        xmlNodePtr *temp;
3615
3616        cur->nodeMax *= 2;
3617	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3618				      sizeof(xmlNodePtr));
3619	if (temp == NULL) {
3620	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3621	    return;
3622	}
3623	cur->nodeTab = temp;
3624    }
3625    if (val->type == XML_NAMESPACE_DECL) {
3626	xmlNsPtr ns = (xmlNsPtr) val;
3627
3628	cur->nodeTab[cur->nodeNr++] =
3629	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3630    } else
3631	cur->nodeTab[cur->nodeNr++] = val;
3632}
3633
3634/**
3635 * xmlXPathNodeSetMerge:
3636 * @val1:  the first NodeSet or NULL
3637 * @val2:  the second NodeSet
3638 *
3639 * Merges two nodesets, all nodes from @val2 are added to @val1
3640 * if @val1 is NULL, a new set is created and copied from @val2
3641 *
3642 * Returns @val1 once extended or NULL in case of error.
3643 */
3644xmlNodeSetPtr
3645xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3646    int i, j, initNr, skip;
3647    xmlNodePtr n1, n2;
3648
3649    if (val2 == NULL) return(val1);
3650    if (val1 == NULL) {
3651	val1 = xmlXPathNodeSetCreate(NULL);
3652#if 0
3653	/*
3654	* TODO: The optimization won't work in every case, since
3655	*  those nasty namespace nodes need to be added with
3656	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3657	*  memcpy is not possible.
3658	*  If there was a flag on the nodesetval, indicating that
3659	*  some temporary nodes are in, that would be helpfull.
3660	*/
3661	/*
3662	* Optimization: Create an equally sized node-set
3663	* and memcpy the content.
3664	*/
3665	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3666	if (val1 == NULL)
3667	    return(NULL);
3668	if (val2->nodeNr != 0) {
3669	    if (val2->nodeNr == 1)
3670		*(val1->nodeTab) = *(val2->nodeTab);
3671	    else {
3672		memcpy(val1->nodeTab, val2->nodeTab,
3673		    val2->nodeNr * sizeof(xmlNodePtr));
3674	    }
3675	    val1->nodeNr = val2->nodeNr;
3676	}
3677	return(val1);
3678#endif
3679    }
3680
3681    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3682    initNr = val1->nodeNr;
3683
3684    for (i = 0;i < val2->nodeNr;i++) {
3685	n2 = val2->nodeTab[i];
3686	/*
3687	 * check against duplicates
3688	 */
3689	skip = 0;
3690	for (j = 0; j < initNr; j++) {
3691	    n1 = val1->nodeTab[j];
3692	    if (n1 == n2) {
3693		skip = 1;
3694		break;
3695	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3696		       (n2->type == XML_NAMESPACE_DECL)) {
3697		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3698		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3699			((xmlNsPtr) n2)->prefix)))
3700		{
3701		    skip = 1;
3702		    break;
3703		}
3704	    }
3705	}
3706	if (skip)
3707	    continue;
3708
3709	/*
3710	 * grow the nodeTab if needed
3711	 */
3712	if (val1->nodeMax == 0) {
3713	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3714						    sizeof(xmlNodePtr));
3715	    if (val1->nodeTab == NULL) {
3716	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3717		return(NULL);
3718	    }
3719	    memset(val1->nodeTab, 0 ,
3720		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3721	    val1->nodeMax = XML_NODESET_DEFAULT;
3722	} else if (val1->nodeNr == val1->nodeMax) {
3723	    xmlNodePtr *temp;
3724
3725	    val1->nodeMax *= 2;
3726	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3727					     sizeof(xmlNodePtr));
3728	    if (temp == NULL) {
3729	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3730		return(NULL);
3731	    }
3732	    val1->nodeTab = temp;
3733	}
3734	if (n2->type == XML_NAMESPACE_DECL) {
3735	    xmlNsPtr ns = (xmlNsPtr) n2;
3736
3737	    val1->nodeTab[val1->nodeNr++] =
3738		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3739	} else
3740	    val1->nodeTab[val1->nodeNr++] = n2;
3741    }
3742
3743    return(val1);
3744}
3745
3746#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3747/**
3748 * xmlXPathNodeSetMergeUnique:
3749 * @val1:  the first NodeSet or NULL
3750 * @val2:  the second NodeSet
3751 *
3752 * Merges two nodesets, all nodes from @val2 are added to @val1
3753 * if @val1 is NULL, a new set is created and copied from @val2
3754 *
3755 * Returns @val1 once extended or NULL in case of error.
3756 */
3757static xmlNodeSetPtr
3758xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3759    int i;
3760
3761    if (val2 == NULL) return(val1);
3762    if (val1 == NULL) {
3763	val1 = xmlXPathNodeSetCreate(NULL);
3764    }
3765
3766    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3767
3768    for (i = 0;i < val2->nodeNr;i++) {
3769	/*
3770	 * grow the nodeTab if needed
3771	 */
3772	if (val1->nodeMax == 0) {
3773	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3774						    sizeof(xmlNodePtr));
3775	    if (val1->nodeTab == NULL) {
3776	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3777		return(NULL);
3778	    }
3779	    memset(val1->nodeTab, 0 ,
3780		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3781	    val1->nodeMax = XML_NODESET_DEFAULT;
3782	} else if (val1->nodeNr == val1->nodeMax) {
3783	    xmlNodePtr *temp;
3784
3785	    val1->nodeMax *= 2;
3786	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3787					     sizeof(xmlNodePtr));
3788	    if (temp == NULL) {
3789	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3790		return(NULL);
3791	    }
3792	    val1->nodeTab = temp;
3793	}
3794	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3795	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3796
3797	    val1->nodeTab[val1->nodeNr++] =
3798		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3799	} else
3800	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3801    }
3802
3803    return(val1);
3804}
3805#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3806
3807/**
3808 * xmlXPathNodeSetMergeAndClear:
3809 * @set1:  the first NodeSet or NULL
3810 * @set2:  the second NodeSet
3811 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3812 *
3813 * Merges two nodesets, all nodes from @set2 are added to @set1
3814 * if @set1 is NULL, a new set is created and copied from @set2.
3815 * Checks for duplicate nodes. Clears set2.
3816 *
3817 * Returns @set1 once extended or NULL in case of error.
3818 */
3819static xmlNodeSetPtr
3820xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3821			     int hasNullEntries)
3822{
3823    if ((set1 == NULL) && (hasNullEntries == 0)) {
3824	/*
3825	* Note that doing a memcpy of the list, namespace nodes are
3826	* just assigned to set1, since set2 is cleared anyway.
3827	*/
3828	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3829	if (set1 == NULL)
3830	    return(NULL);
3831	if (set2->nodeNr != 0) {
3832	    memcpy(set1->nodeTab, set2->nodeTab,
3833		set2->nodeNr * sizeof(xmlNodePtr));
3834	    set1->nodeNr = set2->nodeNr;
3835	}
3836    } else {
3837	int i, j, initNbSet1;
3838	xmlNodePtr n1, n2;
3839
3840	if (set1 == NULL)
3841	    	set1 = xmlXPathNodeSetCreate(NULL);
3842
3843	initNbSet1 = set1->nodeNr;
3844	for (i = 0;i < set2->nodeNr;i++) {
3845	    n2 = set2->nodeTab[i];
3846	    /*
3847	    * Skip NULLed entries.
3848	    */
3849	    if (n2 == NULL)
3850		continue;
3851	    /*
3852	    * Skip duplicates.
3853	    */
3854	    for (j = 0; j < initNbSet1; j++) {
3855		n1 = set1->nodeTab[j];
3856		if (n1 == n2) {
3857		    goto skip_node;
3858		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3859		    (n2->type == XML_NAMESPACE_DECL))
3860		{
3861		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3862			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3863			((xmlNsPtr) n2)->prefix)))
3864		    {
3865			/*
3866			* Free the namespace node.
3867			*/
3868			set2->nodeTab[i] = NULL;
3869			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3870			goto skip_node;
3871		    }
3872		}
3873	    }
3874	    /*
3875	    * grow the nodeTab if needed
3876	    */
3877	    if (set1->nodeMax == 0) {
3878		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3879		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3880		if (set1->nodeTab == NULL) {
3881		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3882		    return(NULL);
3883		}
3884		memset(set1->nodeTab, 0,
3885		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3886		set1->nodeMax = XML_NODESET_DEFAULT;
3887	    } else if (set1->nodeNr >= set1->nodeMax) {
3888		xmlNodePtr *temp;
3889
3890		set1->nodeMax *= 2;
3891		temp = (xmlNodePtr *) xmlRealloc(
3892		    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3893		if (temp == NULL) {
3894		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3895		    return(NULL);
3896		}
3897		set1->nodeTab = temp;
3898	    }
3899	    if (n2->type == XML_NAMESPACE_DECL) {
3900		xmlNsPtr ns = (xmlNsPtr) n2;
3901
3902		set1->nodeTab[set1->nodeNr++] =
3903		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3904	    } else
3905		set1->nodeTab[set1->nodeNr++] = n2;
3906skip_node:
3907	    {}
3908	}
3909    }
3910    set2->nodeNr = 0;
3911    return(set1);
3912}
3913
3914/**
3915 * xmlXPathNodeSetMergeAndClearNoDupls:
3916 * @set1:  the first NodeSet or NULL
3917 * @set2:  the second NodeSet
3918 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3919 *
3920 * Merges two nodesets, all nodes from @set2 are added to @set1
3921 * if @set1 is NULL, a new set is created and copied from @set2.
3922 * Doesn't chack for duplicate nodes. Clears set2.
3923 *
3924 * Returns @set1 once extended or NULL in case of error.
3925 */
3926static xmlNodeSetPtr
3927xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3928				    int hasNullEntries)
3929{
3930    if (set2 == NULL)
3931	return(set1);
3932    if ((set1 == NULL) && (hasNullEntries == 0)) {
3933	/*
3934	* Note that doing a memcpy of the list, namespace nodes are
3935	* just assigned to set1, since set2 is cleared anyway.
3936	*/
3937	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3938	if (set1 == NULL)
3939	    return(NULL);
3940	if (set2->nodeNr != 0) {
3941	    memcpy(set1->nodeTab, set2->nodeTab,
3942		set2->nodeNr * sizeof(xmlNodePtr));
3943	    set1->nodeNr = set2->nodeNr;
3944	}
3945    } else {
3946	int i;
3947	xmlNodePtr n2;
3948
3949	if (set1 == NULL)
3950	    set1 = xmlXPathNodeSetCreate(NULL);
3951
3952	for (i = 0;i < set2->nodeNr;i++) {
3953	    n2 = set2->nodeTab[i];
3954	    /*
3955	    * Skip NULLed entries.
3956	    */
3957	    if (n2 == NULL)
3958		continue;
3959	    if (set1->nodeMax == 0) {
3960		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3961		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3962		if (set1->nodeTab == NULL) {
3963		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3964		    return(NULL);
3965		}
3966		memset(set1->nodeTab, 0,
3967		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3968		set1->nodeMax = XML_NODESET_DEFAULT;
3969	    } else if (set1->nodeNr >= set1->nodeMax) {
3970		xmlNodePtr *temp;
3971
3972		set1->nodeMax *= 2;
3973		temp = (xmlNodePtr *) xmlRealloc(
3974		    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3975		if (temp == NULL) {
3976		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3977		    return(NULL);
3978		}
3979		set1->nodeTab = temp;
3980	    }
3981	    set1->nodeTab[set1->nodeNr++] = n2;
3982	}
3983    }
3984    set2->nodeNr = 0;
3985    return(set1);
3986}
3987
3988/**
3989 * xmlXPathNodeSetDel:
3990 * @cur:  the initial node set
3991 * @val:  an xmlNodePtr
3992 *
3993 * Removes an xmlNodePtr from an existing NodeSet
3994 */
3995void
3996xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3997    int i;
3998
3999    if (cur == NULL) return;
4000    if (val == NULL) return;
4001
4002    /*
4003     * find node in nodeTab
4004     */
4005    for (i = 0;i < cur->nodeNr;i++)
4006        if (cur->nodeTab[i] == val) break;
4007
4008    if (i >= cur->nodeNr) {	/* not found */
4009#ifdef DEBUG
4010        xmlGenericError(xmlGenericErrorContext,
4011	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4012		val->name);
4013#endif
4014        return;
4015    }
4016    if ((cur->nodeTab[i] != NULL) &&
4017	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4018	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4019    cur->nodeNr--;
4020    for (;i < cur->nodeNr;i++)
4021        cur->nodeTab[i] = cur->nodeTab[i + 1];
4022    cur->nodeTab[cur->nodeNr] = NULL;
4023}
4024
4025/**
4026 * xmlXPathNodeSetRemove:
4027 * @cur:  the initial node set
4028 * @val:  the index to remove
4029 *
4030 * Removes an entry from an existing NodeSet list.
4031 */
4032void
4033xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4034    if (cur == NULL) return;
4035    if (val >= cur->nodeNr) return;
4036    if ((cur->nodeTab[val] != NULL) &&
4037	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4038	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4039    cur->nodeNr--;
4040    for (;val < cur->nodeNr;val++)
4041        cur->nodeTab[val] = cur->nodeTab[val + 1];
4042    cur->nodeTab[cur->nodeNr] = NULL;
4043}
4044
4045/**
4046 * xmlXPathFreeNodeSet:
4047 * @obj:  the xmlNodeSetPtr to free
4048 *
4049 * Free the NodeSet compound (not the actual nodes !).
4050 */
4051void
4052xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4053    if (obj == NULL) return;
4054    if (obj->nodeTab != NULL) {
4055	int i;
4056
4057	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4058	for (i = 0;i < obj->nodeNr;i++)
4059	    if ((obj->nodeTab[i] != NULL) &&
4060		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4061		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4062	xmlFree(obj->nodeTab);
4063    }
4064    xmlFree(obj);
4065}
4066
4067/**
4068 * xmlXPathNodeSetClear:
4069 * @set:  the node set to clear
4070 *
4071 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4072 * are feed), but does *not* free the list itself. Sets the length of the
4073 * list to 0.
4074 */
4075static void
4076xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4077{
4078    if ((set == NULL) || (set->nodeNr <= 0))
4079	return;
4080    else if (hasNsNodes) {
4081	int i;
4082	xmlNodePtr node;
4083
4084	for (i = 0; i < set->nodeNr; i++) {
4085	    node = set->nodeTab[i];
4086	    if ((node != NULL) &&
4087		(node->type == XML_NAMESPACE_DECL))
4088		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4089	}
4090    }
4091    set->nodeNr = 0;
4092}
4093
4094/**
4095 * xmlXPathNodeSetClearFromPos:
4096 * @set: the node set to be cleared
4097 * @pos: the start position to clear from
4098 *
4099 * Clears the list from temporary XPath objects (e.g. namespace nodes
4100 * are feed) starting with the entry at @pos, but does *not* free the list
4101 * itself. Sets the length of the list to @pos.
4102 */
4103static void
4104xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4105{
4106    if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4107	return;
4108    else if ((hasNsNodes)) {
4109	int i;
4110	xmlNodePtr node;
4111
4112	for (i = pos; i < set->nodeNr; i++) {
4113	    node = set->nodeTab[i];
4114	    if ((node != NULL) &&
4115		(node->type == XML_NAMESPACE_DECL))
4116		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4117	}
4118    }
4119    set->nodeNr = pos;
4120}
4121
4122/**
4123 * xmlXPathFreeValueTree:
4124 * @obj:  the xmlNodeSetPtr to free
4125 *
4126 * Free the NodeSet compound and the actual tree, this is different
4127 * from xmlXPathFreeNodeSet()
4128 */
4129static void
4130xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4131    int i;
4132
4133    if (obj == NULL) return;
4134
4135    if (obj->nodeTab != NULL) {
4136	for (i = 0;i < obj->nodeNr;i++) {
4137	    if (obj->nodeTab[i] != NULL) {
4138		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4139		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4140		} else {
4141		    xmlFreeNodeList(obj->nodeTab[i]);
4142		}
4143	    }
4144	}
4145	xmlFree(obj->nodeTab);
4146    }
4147    xmlFree(obj);
4148}
4149
4150#if defined(DEBUG) || defined(DEBUG_STEP)
4151/**
4152 * xmlGenericErrorContextNodeSet:
4153 * @output:  a FILE * for the output
4154 * @obj:  the xmlNodeSetPtr to display
4155 *
4156 * Quick display of a NodeSet
4157 */
4158void
4159xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4160    int i;
4161
4162    if (output == NULL) output = xmlGenericErrorContext;
4163    if (obj == NULL)  {
4164        fprintf(output, "NodeSet == NULL !\n");
4165	return;
4166    }
4167    if (obj->nodeNr == 0) {
4168        fprintf(output, "NodeSet is empty\n");
4169	return;
4170    }
4171    if (obj->nodeTab == NULL) {
4172	fprintf(output, " nodeTab == NULL !\n");
4173	return;
4174    }
4175    for (i = 0; i < obj->nodeNr; i++) {
4176        if (obj->nodeTab[i] == NULL) {
4177	    fprintf(output, " NULL !\n");
4178	    return;
4179        }
4180	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4181	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4182	    fprintf(output, " /");
4183	else if (obj->nodeTab[i]->name == NULL)
4184	    fprintf(output, " noname!");
4185	else fprintf(output, " %s", obj->nodeTab[i]->name);
4186    }
4187    fprintf(output, "\n");
4188}
4189#endif
4190
4191/**
4192 * xmlXPathNewNodeSet:
4193 * @val:  the NodePtr value
4194 *
4195 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4196 * it with the single Node @val
4197 *
4198 * Returns the newly created object.
4199 */
4200xmlXPathObjectPtr
4201xmlXPathNewNodeSet(xmlNodePtr val) {
4202    xmlXPathObjectPtr ret;
4203
4204    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4205    if (ret == NULL) {
4206        xmlXPathErrMemory(NULL, "creating nodeset\n");
4207	return(NULL);
4208    }
4209    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4210    ret->type = XPATH_NODESET;
4211    ret->boolval = 0;
4212    ret->nodesetval = xmlXPathNodeSetCreate(val);
4213    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4214#ifdef XP_DEBUG_OBJ_USAGE
4215    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4216#endif
4217    return(ret);
4218}
4219
4220/**
4221 * xmlXPathNewValueTree:
4222 * @val:  the NodePtr value
4223 *
4224 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4225 * it with the tree root @val
4226 *
4227 * Returns the newly created object.
4228 */
4229xmlXPathObjectPtr
4230xmlXPathNewValueTree(xmlNodePtr val) {
4231    xmlXPathObjectPtr ret;
4232
4233    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4234    if (ret == NULL) {
4235        xmlXPathErrMemory(NULL, "creating result value tree\n");
4236	return(NULL);
4237    }
4238    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4239    ret->type = XPATH_XSLT_TREE;
4240    ret->boolval = 1;
4241    ret->user = (void *) val;
4242    ret->nodesetval = xmlXPathNodeSetCreate(val);
4243#ifdef XP_DEBUG_OBJ_USAGE
4244    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4245#endif
4246    return(ret);
4247}
4248
4249/**
4250 * xmlXPathNewNodeSetList:
4251 * @val:  an existing NodeSet
4252 *
4253 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4254 * it with the Nodeset @val
4255 *
4256 * Returns the newly created object.
4257 */
4258xmlXPathObjectPtr
4259xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4260{
4261    xmlXPathObjectPtr ret;
4262    int i;
4263
4264    if (val == NULL)
4265        ret = NULL;
4266    else if (val->nodeTab == NULL)
4267        ret = xmlXPathNewNodeSet(NULL);
4268    else {
4269        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4270        for (i = 1; i < val->nodeNr; ++i)
4271            xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4272    }
4273
4274    return (ret);
4275}
4276
4277/**
4278 * xmlXPathWrapNodeSet:
4279 * @val:  the NodePtr value
4280 *
4281 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4282 *
4283 * Returns the newly created object.
4284 */
4285xmlXPathObjectPtr
4286xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4287    xmlXPathObjectPtr ret;
4288
4289    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4290    if (ret == NULL) {
4291        xmlXPathErrMemory(NULL, "creating node set object\n");
4292	return(NULL);
4293    }
4294    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4295    ret->type = XPATH_NODESET;
4296    ret->nodesetval = val;
4297#ifdef XP_DEBUG_OBJ_USAGE
4298    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4299#endif
4300    return(ret);
4301}
4302
4303/**
4304 * xmlXPathFreeNodeSetList:
4305 * @obj:  an existing NodeSetList object
4306 *
4307 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4308 * the list contrary to xmlXPathFreeObject().
4309 */
4310void
4311xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4312    if (obj == NULL) return;
4313#ifdef XP_DEBUG_OBJ_USAGE
4314    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4315#endif
4316    xmlFree(obj);
4317}
4318
4319/**
4320 * xmlXPathDifference:
4321 * @nodes1:  a node-set
4322 * @nodes2:  a node-set
4323 *
4324 * Implements the EXSLT - Sets difference() function:
4325 *    node-set set:difference (node-set, node-set)
4326 *
4327 * Returns the difference between the two node sets, or nodes1 if
4328 *         nodes2 is empty
4329 */
4330xmlNodeSetPtr
4331xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4332    xmlNodeSetPtr ret;
4333    int i, l1;
4334    xmlNodePtr cur;
4335
4336    if (xmlXPathNodeSetIsEmpty(nodes2))
4337	return(nodes1);
4338
4339    ret = xmlXPathNodeSetCreate(NULL);
4340    if (xmlXPathNodeSetIsEmpty(nodes1))
4341	return(ret);
4342
4343    l1 = xmlXPathNodeSetGetLength(nodes1);
4344
4345    for (i = 0; i < l1; i++) {
4346	cur = xmlXPathNodeSetItem(nodes1, i);
4347	if (!xmlXPathNodeSetContains(nodes2, cur))
4348	    xmlXPathNodeSetAddUnique(ret, cur);
4349    }
4350    return(ret);
4351}
4352
4353/**
4354 * xmlXPathIntersection:
4355 * @nodes1:  a node-set
4356 * @nodes2:  a node-set
4357 *
4358 * Implements the EXSLT - Sets intersection() function:
4359 *    node-set set:intersection (node-set, node-set)
4360 *
4361 * Returns a node set comprising the nodes that are within both the
4362 *         node sets passed as arguments
4363 */
4364xmlNodeSetPtr
4365xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4366    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4367    int i, l1;
4368    xmlNodePtr cur;
4369
4370    if (xmlXPathNodeSetIsEmpty(nodes1))
4371	return(ret);
4372    if (xmlXPathNodeSetIsEmpty(nodes2))
4373	return(ret);
4374
4375    l1 = xmlXPathNodeSetGetLength(nodes1);
4376
4377    for (i = 0; i < l1; i++) {
4378	cur = xmlXPathNodeSetItem(nodes1, i);
4379	if (xmlXPathNodeSetContains(nodes2, cur))
4380	    xmlXPathNodeSetAddUnique(ret, cur);
4381    }
4382    return(ret);
4383}
4384
4385/**
4386 * xmlXPathDistinctSorted:
4387 * @nodes:  a node-set, sorted by document order
4388 *
4389 * Implements the EXSLT - Sets distinct() function:
4390 *    node-set set:distinct (node-set)
4391 *
4392 * Returns a subset of the nodes contained in @nodes, or @nodes if
4393 *         it is empty
4394 */
4395xmlNodeSetPtr
4396xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4397    xmlNodeSetPtr ret;
4398    xmlHashTablePtr hash;
4399    int i, l;
4400    xmlChar * strval;
4401    xmlNodePtr cur;
4402
4403    if (xmlXPathNodeSetIsEmpty(nodes))
4404	return(nodes);
4405
4406    ret = xmlXPathNodeSetCreate(NULL);
4407    l = xmlXPathNodeSetGetLength(nodes);
4408    hash = xmlHashCreate (l);
4409    for (i = 0; i < l; i++) {
4410	cur = xmlXPathNodeSetItem(nodes, i);
4411	strval = xmlXPathCastNodeToString(cur);
4412	if (xmlHashLookup(hash, strval) == NULL) {
4413	    xmlHashAddEntry(hash, strval, strval);
4414	    xmlXPathNodeSetAddUnique(ret, cur);
4415	} else {
4416	    xmlFree(strval);
4417	}
4418    }
4419    xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4420    return(ret);
4421}
4422
4423/**
4424 * xmlXPathDistinct:
4425 * @nodes:  a node-set
4426 *
4427 * Implements the EXSLT - Sets distinct() function:
4428 *    node-set set:distinct (node-set)
4429 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4430 * is called with the sorted node-set
4431 *
4432 * Returns a subset of the nodes contained in @nodes, or @nodes if
4433 *         it is empty
4434 */
4435xmlNodeSetPtr
4436xmlXPathDistinct (xmlNodeSetPtr nodes) {
4437    if (xmlXPathNodeSetIsEmpty(nodes))
4438	return(nodes);
4439
4440    xmlXPathNodeSetSort(nodes);
4441    return(xmlXPathDistinctSorted(nodes));
4442}
4443
4444/**
4445 * xmlXPathHasSameNodes:
4446 * @nodes1:  a node-set
4447 * @nodes2:  a node-set
4448 *
4449 * Implements the EXSLT - Sets has-same-nodes function:
4450 *    boolean set:has-same-node(node-set, node-set)
4451 *
4452 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4453 *         otherwise
4454 */
4455int
4456xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4457    int i, l;
4458    xmlNodePtr cur;
4459
4460    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4461	xmlXPathNodeSetIsEmpty(nodes2))
4462	return(0);
4463
4464    l = xmlXPathNodeSetGetLength(nodes1);
4465    for (i = 0; i < l; i++) {
4466	cur = xmlXPathNodeSetItem(nodes1, i);
4467	if (xmlXPathNodeSetContains(nodes2, cur))
4468	    return(1);
4469    }
4470    return(0);
4471}
4472
4473/**
4474 * xmlXPathNodeLeadingSorted:
4475 * @nodes: a node-set, sorted by document order
4476 * @node: a node
4477 *
4478 * Implements the EXSLT - Sets leading() function:
4479 *    node-set set:leading (node-set, node-set)
4480 *
4481 * Returns the nodes in @nodes that precede @node in document order,
4482 *         @nodes if @node is NULL or an empty node-set if @nodes
4483 *         doesn't contain @node
4484 */
4485xmlNodeSetPtr
4486xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4487    int i, l;
4488    xmlNodePtr cur;
4489    xmlNodeSetPtr ret;
4490
4491    if (node == NULL)
4492	return(nodes);
4493
4494    ret = xmlXPathNodeSetCreate(NULL);
4495    if (xmlXPathNodeSetIsEmpty(nodes) ||
4496	(!xmlXPathNodeSetContains(nodes, node)))
4497	return(ret);
4498
4499    l = xmlXPathNodeSetGetLength(nodes);
4500    for (i = 0; i < l; i++) {
4501	cur = xmlXPathNodeSetItem(nodes, i);
4502	if (cur == node)
4503	    break;
4504	xmlXPathNodeSetAddUnique(ret, cur);
4505    }
4506    return(ret);
4507}
4508
4509/**
4510 * xmlXPathNodeLeading:
4511 * @nodes:  a node-set
4512 * @node:  a node
4513 *
4514 * Implements the EXSLT - Sets leading() function:
4515 *    node-set set:leading (node-set, node-set)
4516 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4517 * is called.
4518 *
4519 * Returns the nodes in @nodes that precede @node in document order,
4520 *         @nodes if @node is NULL or an empty node-set if @nodes
4521 *         doesn't contain @node
4522 */
4523xmlNodeSetPtr
4524xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4525    xmlXPathNodeSetSort(nodes);
4526    return(xmlXPathNodeLeadingSorted(nodes, node));
4527}
4528
4529/**
4530 * xmlXPathLeadingSorted:
4531 * @nodes1:  a node-set, sorted by document order
4532 * @nodes2:  a node-set, sorted by document order
4533 *
4534 * Implements the EXSLT - Sets leading() function:
4535 *    node-set set:leading (node-set, node-set)
4536 *
4537 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4538 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4539 *         an empty node-set if @nodes1 doesn't contain @nodes2
4540 */
4541xmlNodeSetPtr
4542xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4543    if (xmlXPathNodeSetIsEmpty(nodes2))
4544	return(nodes1);
4545    return(xmlXPathNodeLeadingSorted(nodes1,
4546				     xmlXPathNodeSetItem(nodes2, 1)));
4547}
4548
4549/**
4550 * xmlXPathLeading:
4551 * @nodes1:  a node-set
4552 * @nodes2:  a node-set
4553 *
4554 * Implements the EXSLT - Sets leading() function:
4555 *    node-set set:leading (node-set, node-set)
4556 * @nodes1 and @nodes2 are sorted by document order, then
4557 * #exslSetsLeadingSorted is called.
4558 *
4559 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4560 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4561 *         an empty node-set if @nodes1 doesn't contain @nodes2
4562 */
4563xmlNodeSetPtr
4564xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4565    if (xmlXPathNodeSetIsEmpty(nodes2))
4566	return(nodes1);
4567    if (xmlXPathNodeSetIsEmpty(nodes1))
4568	return(xmlXPathNodeSetCreate(NULL));
4569    xmlXPathNodeSetSort(nodes1);
4570    xmlXPathNodeSetSort(nodes2);
4571    return(xmlXPathNodeLeadingSorted(nodes1,
4572				     xmlXPathNodeSetItem(nodes2, 1)));
4573}
4574
4575/**
4576 * xmlXPathNodeTrailingSorted:
4577 * @nodes: a node-set, sorted by document order
4578 * @node: a node
4579 *
4580 * Implements the EXSLT - Sets trailing() function:
4581 *    node-set set:trailing (node-set, node-set)
4582 *
4583 * Returns the nodes in @nodes that follow @node in document order,
4584 *         @nodes if @node is NULL or an empty node-set if @nodes
4585 *         doesn't contain @node
4586 */
4587xmlNodeSetPtr
4588xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4589    int i, l;
4590    xmlNodePtr cur;
4591    xmlNodeSetPtr ret;
4592
4593    if (node == NULL)
4594	return(nodes);
4595
4596    ret = xmlXPathNodeSetCreate(NULL);
4597    if (xmlXPathNodeSetIsEmpty(nodes) ||
4598	(!xmlXPathNodeSetContains(nodes, node)))
4599	return(ret);
4600
4601    l = xmlXPathNodeSetGetLength(nodes);
4602    for (i = l; i > 0; i--) {
4603	cur = xmlXPathNodeSetItem(nodes, i);
4604	if (cur == node)
4605	    break;
4606	xmlXPathNodeSetAddUnique(ret, cur);
4607    }
4608    return(ret);
4609}
4610
4611/**
4612 * xmlXPathNodeTrailing:
4613 * @nodes:  a node-set
4614 * @node:  a node
4615 *
4616 * Implements the EXSLT - Sets trailing() function:
4617 *    node-set set:trailing (node-set, node-set)
4618 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4619 * is called.
4620 *
4621 * Returns the nodes in @nodes that follow @node in document order,
4622 *         @nodes if @node is NULL or an empty node-set if @nodes
4623 *         doesn't contain @node
4624 */
4625xmlNodeSetPtr
4626xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4627    xmlXPathNodeSetSort(nodes);
4628    return(xmlXPathNodeTrailingSorted(nodes, node));
4629}
4630
4631/**
4632 * xmlXPathTrailingSorted:
4633 * @nodes1:  a node-set, sorted by document order
4634 * @nodes2:  a node-set, sorted by document order
4635 *
4636 * Implements the EXSLT - Sets trailing() function:
4637 *    node-set set:trailing (node-set, node-set)
4638 *
4639 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4640 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4641 *         an empty node-set if @nodes1 doesn't contain @nodes2
4642 */
4643xmlNodeSetPtr
4644xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4645    if (xmlXPathNodeSetIsEmpty(nodes2))
4646	return(nodes1);
4647    return(xmlXPathNodeTrailingSorted(nodes1,
4648				      xmlXPathNodeSetItem(nodes2, 0)));
4649}
4650
4651/**
4652 * xmlXPathTrailing:
4653 * @nodes1:  a node-set
4654 * @nodes2:  a node-set
4655 *
4656 * Implements the EXSLT - Sets trailing() function:
4657 *    node-set set:trailing (node-set, node-set)
4658 * @nodes1 and @nodes2 are sorted by document order, then
4659 * #xmlXPathTrailingSorted is called.
4660 *
4661 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4662 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4663 *         an empty node-set if @nodes1 doesn't contain @nodes2
4664 */
4665xmlNodeSetPtr
4666xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4667    if (xmlXPathNodeSetIsEmpty(nodes2))
4668	return(nodes1);
4669    if (xmlXPathNodeSetIsEmpty(nodes1))
4670	return(xmlXPathNodeSetCreate(NULL));
4671    xmlXPathNodeSetSort(nodes1);
4672    xmlXPathNodeSetSort(nodes2);
4673    return(xmlXPathNodeTrailingSorted(nodes1,
4674				      xmlXPathNodeSetItem(nodes2, 0)));
4675}
4676
4677/************************************************************************
4678 *									*
4679 *		Routines to handle extra functions			*
4680 *									*
4681 ************************************************************************/
4682
4683/**
4684 * xmlXPathRegisterFunc:
4685 * @ctxt:  the XPath context
4686 * @name:  the function name
4687 * @f:  the function implementation or NULL
4688 *
4689 * Register a new function. If @f is NULL it unregisters the function
4690 *
4691 * Returns 0 in case of success, -1 in case of error
4692 */
4693int
4694xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4695		     xmlXPathFunction f) {
4696    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4697}
4698
4699/**
4700 * xmlXPathRegisterFuncNS:
4701 * @ctxt:  the XPath context
4702 * @name:  the function name
4703 * @ns_uri:  the function namespace URI
4704 * @f:  the function implementation or NULL
4705 *
4706 * Register a new function. If @f is NULL it unregisters the function
4707 *
4708 * Returns 0 in case of success, -1 in case of error
4709 */
4710int
4711xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4712		       const xmlChar *ns_uri, xmlXPathFunction f) {
4713    if (ctxt == NULL)
4714	return(-1);
4715    if (name == NULL)
4716	return(-1);
4717
4718    if (ctxt->funcHash == NULL)
4719	ctxt->funcHash = xmlHashCreate(0);
4720    if (ctxt->funcHash == NULL)
4721	return(-1);
4722    if (f == NULL)
4723        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4724    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4725}
4726
4727/**
4728 * xmlXPathRegisterFuncLookup:
4729 * @ctxt:  the XPath context
4730 * @f:  the lookup function
4731 * @funcCtxt:  the lookup data
4732 *
4733 * Registers an external mechanism to do function lookup.
4734 */
4735void
4736xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4737			    xmlXPathFuncLookupFunc f,
4738			    void *funcCtxt) {
4739    if (ctxt == NULL)
4740	return;
4741    ctxt->funcLookupFunc = f;
4742    ctxt->funcLookupData = funcCtxt;
4743}
4744
4745/**
4746 * xmlXPathFunctionLookup:
4747 * @ctxt:  the XPath context
4748 * @name:  the function name
4749 *
4750 * Search in the Function array of the context for the given
4751 * function.
4752 *
4753 * Returns the xmlXPathFunction or NULL if not found
4754 */
4755xmlXPathFunction
4756xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4757    if (ctxt == NULL)
4758	return (NULL);
4759
4760    if (ctxt->funcLookupFunc != NULL) {
4761	xmlXPathFunction ret;
4762	xmlXPathFuncLookupFunc f;
4763
4764	f = ctxt->funcLookupFunc;
4765	ret = f(ctxt->funcLookupData, name, NULL);
4766	if (ret != NULL)
4767	    return(ret);
4768    }
4769    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4770}
4771
4772/**
4773 * xmlXPathFunctionLookupNS:
4774 * @ctxt:  the XPath context
4775 * @name:  the function name
4776 * @ns_uri:  the function namespace URI
4777 *
4778 * Search in the Function array of the context for the given
4779 * function.
4780 *
4781 * Returns the xmlXPathFunction or NULL if not found
4782 */
4783xmlXPathFunction
4784xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4785			 const xmlChar *ns_uri) {
4786    xmlXPathFunction ret;
4787
4788    if (ctxt == NULL)
4789	return(NULL);
4790    if (name == NULL)
4791	return(NULL);
4792
4793    if (ctxt->funcLookupFunc != NULL) {
4794	xmlXPathFuncLookupFunc f;
4795
4796	f = ctxt->funcLookupFunc;
4797	ret = f(ctxt->funcLookupData, name, ns_uri);
4798	if (ret != NULL)
4799	    return(ret);
4800    }
4801
4802    if (ctxt->funcHash == NULL)
4803	return(NULL);
4804
4805    XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4806    return(ret);
4807}
4808
4809/**
4810 * xmlXPathRegisteredFuncsCleanup:
4811 * @ctxt:  the XPath context
4812 *
4813 * Cleanup the XPath context data associated to registered functions
4814 */
4815void
4816xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4817    if (ctxt == NULL)
4818	return;
4819
4820    xmlHashFree(ctxt->funcHash, NULL);
4821    ctxt->funcHash = NULL;
4822}
4823
4824/************************************************************************
4825 *									*
4826 *			Routines to handle Variables			*
4827 *									*
4828 ************************************************************************/
4829
4830/**
4831 * xmlXPathRegisterVariable:
4832 * @ctxt:  the XPath context
4833 * @name:  the variable name
4834 * @value:  the variable value or NULL
4835 *
4836 * Register a new variable value. If @value is NULL it unregisters
4837 * the variable
4838 *
4839 * Returns 0 in case of success, -1 in case of error
4840 */
4841int
4842xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4843			 xmlXPathObjectPtr value) {
4844    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4845}
4846
4847/**
4848 * xmlXPathRegisterVariableNS:
4849 * @ctxt:  the XPath context
4850 * @name:  the variable name
4851 * @ns_uri:  the variable namespace URI
4852 * @value:  the variable value or NULL
4853 *
4854 * Register a new variable value. If @value is NULL it unregisters
4855 * the variable
4856 *
4857 * Returns 0 in case of success, -1 in case of error
4858 */
4859int
4860xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4861			   const xmlChar *ns_uri,
4862			   xmlXPathObjectPtr value) {
4863    if (ctxt == NULL)
4864	return(-1);
4865    if (name == NULL)
4866	return(-1);
4867
4868    if (ctxt->varHash == NULL)
4869	ctxt->varHash = xmlHashCreate(0);
4870    if (ctxt->varHash == NULL)
4871	return(-1);
4872    if (value == NULL)
4873        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4874	                           (xmlHashDeallocator)xmlXPathFreeObject));
4875    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4876			       (void *) value,
4877			       (xmlHashDeallocator)xmlXPathFreeObject));
4878}
4879
4880/**
4881 * xmlXPathRegisterVariableLookup:
4882 * @ctxt:  the XPath context
4883 * @f:  the lookup function
4884 * @data:  the lookup data
4885 *
4886 * register an external mechanism to do variable lookup
4887 */
4888void
4889xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4890	 xmlXPathVariableLookupFunc f, void *data) {
4891    if (ctxt == NULL)
4892	return;
4893    ctxt->varLookupFunc = f;
4894    ctxt->varLookupData = data;
4895}
4896
4897/**
4898 * xmlXPathVariableLookup:
4899 * @ctxt:  the XPath context
4900 * @name:  the variable name
4901 *
4902 * Search in the Variable array of the context for the given
4903 * variable value.
4904 *
4905 * Returns a copy of the value or NULL if not found
4906 */
4907xmlXPathObjectPtr
4908xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4909    if (ctxt == NULL)
4910	return(NULL);
4911
4912    if (ctxt->varLookupFunc != NULL) {
4913	xmlXPathObjectPtr ret;
4914
4915	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4916	        (ctxt->varLookupData, name, NULL);
4917	return(ret);
4918    }
4919    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4920}
4921
4922/**
4923 * xmlXPathVariableLookupNS:
4924 * @ctxt:  the XPath context
4925 * @name:  the variable name
4926 * @ns_uri:  the variable namespace URI
4927 *
4928 * Search in the Variable array of the context for the given
4929 * variable value.
4930 *
4931 * Returns the a copy of the value or NULL if not found
4932 */
4933xmlXPathObjectPtr
4934xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4935			 const xmlChar *ns_uri) {
4936    if (ctxt == NULL)
4937	return(NULL);
4938
4939    if (ctxt->varLookupFunc != NULL) {
4940	xmlXPathObjectPtr ret;
4941
4942	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4943	        (ctxt->varLookupData, name, ns_uri);
4944	if (ret != NULL) return(ret);
4945    }
4946
4947    if (ctxt->varHash == NULL)
4948	return(NULL);
4949    if (name == NULL)
4950	return(NULL);
4951
4952    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
4953		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4954}
4955
4956/**
4957 * xmlXPathRegisteredVariablesCleanup:
4958 * @ctxt:  the XPath context
4959 *
4960 * Cleanup the XPath context data associated to registered variables
4961 */
4962void
4963xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4964    if (ctxt == NULL)
4965	return;
4966
4967    xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
4968    ctxt->varHash = NULL;
4969}
4970
4971/**
4972 * xmlXPathRegisterNs:
4973 * @ctxt:  the XPath context
4974 * @prefix:  the namespace prefix
4975 * @ns_uri:  the namespace name
4976 *
4977 * Register a new namespace. If @ns_uri is NULL it unregisters
4978 * the namespace
4979 *
4980 * Returns 0 in case of success, -1 in case of error
4981 */
4982int
4983xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4984			   const xmlChar *ns_uri) {
4985    if (ctxt == NULL)
4986	return(-1);
4987    if (prefix == NULL)
4988	return(-1);
4989
4990    if (ctxt->nsHash == NULL)
4991	ctxt->nsHash = xmlHashCreate(10);
4992    if (ctxt->nsHash == NULL)
4993	return(-1);
4994    if (ns_uri == NULL)
4995        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4996	                          (xmlHashDeallocator)xmlFree));
4997    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
4998			      (xmlHashDeallocator)xmlFree));
4999}
5000
5001/**
5002 * xmlXPathNsLookup:
5003 * @ctxt:  the XPath context
5004 * @prefix:  the namespace prefix value
5005 *
5006 * Search in the namespace declaration array of the context for the given
5007 * namespace name associated to the given prefix
5008 *
5009 * Returns the value or NULL if not found
5010 */
5011const xmlChar *
5012xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5013    if (ctxt == NULL)
5014	return(NULL);
5015    if (prefix == NULL)
5016	return(NULL);
5017
5018#ifdef XML_XML_NAMESPACE
5019    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5020	return(XML_XML_NAMESPACE);
5021#endif
5022
5023    if (ctxt->namespaces != NULL) {
5024	int i;
5025
5026	for (i = 0;i < ctxt->nsNr;i++) {
5027	    if ((ctxt->namespaces[i] != NULL) &&
5028		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5029		return(ctxt->namespaces[i]->href);
5030	}
5031    }
5032
5033    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5034}
5035
5036/**
5037 * xmlXPathRegisteredNsCleanup:
5038 * @ctxt:  the XPath context
5039 *
5040 * Cleanup the XPath context data associated to registered variables
5041 */
5042void
5043xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5044    if (ctxt == NULL)
5045	return;
5046
5047    xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5048    ctxt->nsHash = NULL;
5049}
5050
5051/************************************************************************
5052 *									*
5053 *			Routines to handle Values			*
5054 *									*
5055 ************************************************************************/
5056
5057/* Allocations are terrible, one needs to optimize all this !!! */
5058
5059/**
5060 * xmlXPathNewFloat:
5061 * @val:  the double value
5062 *
5063 * Create a new xmlXPathObjectPtr of type double and of value @val
5064 *
5065 * Returns the newly created object.
5066 */
5067xmlXPathObjectPtr
5068xmlXPathNewFloat(double val) {
5069    xmlXPathObjectPtr ret;
5070
5071    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5072    if (ret == NULL) {
5073        xmlXPathErrMemory(NULL, "creating float object\n");
5074	return(NULL);
5075    }
5076    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5077    ret->type = XPATH_NUMBER;
5078    ret->floatval = val;
5079#ifdef XP_DEBUG_OBJ_USAGE
5080    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5081#endif
5082    return(ret);
5083}
5084
5085/**
5086 * xmlXPathNewBoolean:
5087 * @val:  the boolean value
5088 *
5089 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5090 *
5091 * Returns the newly created object.
5092 */
5093xmlXPathObjectPtr
5094xmlXPathNewBoolean(int val) {
5095    xmlXPathObjectPtr ret;
5096
5097    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5098    if (ret == NULL) {
5099        xmlXPathErrMemory(NULL, "creating boolean object\n");
5100	return(NULL);
5101    }
5102    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5103    ret->type = XPATH_BOOLEAN;
5104    ret->boolval = (val != 0);
5105#ifdef XP_DEBUG_OBJ_USAGE
5106    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5107#endif
5108    return(ret);
5109}
5110
5111/**
5112 * xmlXPathNewString:
5113 * @val:  the xmlChar * value
5114 *
5115 * Create a new xmlXPathObjectPtr of type string and of value @val
5116 *
5117 * Returns the newly created object.
5118 */
5119xmlXPathObjectPtr
5120xmlXPathNewString(const xmlChar *val) {
5121    xmlXPathObjectPtr ret;
5122
5123    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5124    if (ret == NULL) {
5125        xmlXPathErrMemory(NULL, "creating string object\n");
5126	return(NULL);
5127    }
5128    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5129    ret->type = XPATH_STRING;
5130    if (val != NULL)
5131	ret->stringval = xmlStrdup(val);
5132    else
5133	ret->stringval = xmlStrdup((const xmlChar *)"");
5134#ifdef XP_DEBUG_OBJ_USAGE
5135    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5136#endif
5137    return(ret);
5138}
5139
5140/**
5141 * xmlXPathWrapString:
5142 * @val:  the xmlChar * value
5143 *
5144 * Wraps the @val string into an XPath object.
5145 *
5146 * Returns the newly created object.
5147 */
5148xmlXPathObjectPtr
5149xmlXPathWrapString (xmlChar *val) {
5150    xmlXPathObjectPtr ret;
5151
5152    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5153    if (ret == NULL) {
5154        xmlXPathErrMemory(NULL, "creating string object\n");
5155	return(NULL);
5156    }
5157    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5158    ret->type = XPATH_STRING;
5159    ret->stringval = val;
5160#ifdef XP_DEBUG_OBJ_USAGE
5161    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5162#endif
5163    return(ret);
5164}
5165
5166/**
5167 * xmlXPathNewCString:
5168 * @val:  the char * value
5169 *
5170 * Create a new xmlXPathObjectPtr of type string and of value @val
5171 *
5172 * Returns the newly created object.
5173 */
5174xmlXPathObjectPtr
5175xmlXPathNewCString(const char *val) {
5176    xmlXPathObjectPtr ret;
5177
5178    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5179    if (ret == NULL) {
5180        xmlXPathErrMemory(NULL, "creating string object\n");
5181	return(NULL);
5182    }
5183    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5184    ret->type = XPATH_STRING;
5185    ret->stringval = xmlStrdup(BAD_CAST val);
5186#ifdef XP_DEBUG_OBJ_USAGE
5187    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5188#endif
5189    return(ret);
5190}
5191
5192/**
5193 * xmlXPathWrapCString:
5194 * @val:  the char * value
5195 *
5196 * Wraps a string into an XPath object.
5197 *
5198 * Returns the newly created object.
5199 */
5200xmlXPathObjectPtr
5201xmlXPathWrapCString (char * val) {
5202    return(xmlXPathWrapString((xmlChar *)(val)));
5203}
5204
5205/**
5206 * xmlXPathWrapExternal:
5207 * @val:  the user data
5208 *
5209 * Wraps the @val data into an XPath object.
5210 *
5211 * Returns the newly created object.
5212 */
5213xmlXPathObjectPtr
5214xmlXPathWrapExternal (void *val) {
5215    xmlXPathObjectPtr ret;
5216
5217    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5218    if (ret == NULL) {
5219        xmlXPathErrMemory(NULL, "creating user object\n");
5220	return(NULL);
5221    }
5222    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5223    ret->type = XPATH_USERS;
5224    ret->user = val;
5225#ifdef XP_DEBUG_OBJ_USAGE
5226    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5227#endif
5228    return(ret);
5229}
5230
5231/**
5232 * xmlXPathObjectCopy:
5233 * @val:  the original object
5234 *
5235 * allocate a new copy of a given object
5236 *
5237 * Returns the newly created object.
5238 */
5239xmlXPathObjectPtr
5240xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5241    xmlXPathObjectPtr ret;
5242
5243    if (val == NULL)
5244	return(NULL);
5245
5246    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247    if (ret == NULL) {
5248        xmlXPathErrMemory(NULL, "copying object\n");
5249	return(NULL);
5250    }
5251    memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5252#ifdef XP_DEBUG_OBJ_USAGE
5253    xmlXPathDebugObjUsageRequested(NULL, val->type);
5254#endif
5255    switch (val->type) {
5256	case XPATH_BOOLEAN:
5257	case XPATH_NUMBER:
5258	case XPATH_POINT:
5259	case XPATH_RANGE:
5260	    break;
5261	case XPATH_STRING:
5262	    ret->stringval = xmlStrdup(val->stringval);
5263	    break;
5264	case XPATH_XSLT_TREE:
5265#if 0
5266/*
5267  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5268  this previous handling is no longer correct, and can cause some serious
5269  problems (ref. bug 145547)
5270*/
5271	    if ((val->nodesetval != NULL) &&
5272		(val->nodesetval->nodeTab != NULL)) {
5273		xmlNodePtr cur, tmp;
5274		xmlDocPtr top;
5275
5276		ret->boolval = 1;
5277		top =  xmlNewDoc(NULL);
5278		top->name = (char *)
5279		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5280		ret->user = top;
5281		if (top != NULL) {
5282		    top->doc = top;
5283		    cur = val->nodesetval->nodeTab[0]->children;
5284		    while (cur != NULL) {
5285			tmp = xmlDocCopyNode(cur, top, 1);
5286			xmlAddChild((xmlNodePtr) top, tmp);
5287			cur = cur->next;
5288		    }
5289		}
5290
5291		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5292	    } else
5293		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5294	    /* Deallocate the copied tree value */
5295	    break;
5296#endif
5297	case XPATH_NODESET:
5298	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5299	    /* Do not deallocate the copied tree value */
5300	    ret->boolval = 0;
5301	    break;
5302	case XPATH_LOCATIONSET:
5303#ifdef LIBXML_XPTR_ENABLED
5304	{
5305	    xmlLocationSetPtr loc = val->user;
5306	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5307	    break;
5308	}
5309#endif
5310        case XPATH_USERS:
5311	    ret->user = val->user;
5312	    break;
5313        case XPATH_UNDEFINED:
5314	    xmlGenericError(xmlGenericErrorContext,
5315		    "xmlXPathObjectCopy: unsupported type %d\n",
5316		    val->type);
5317	    break;
5318    }
5319    return(ret);
5320}
5321
5322/**
5323 * xmlXPathFreeObject:
5324 * @obj:  the object to free
5325 *
5326 * Free up an xmlXPathObjectPtr object.
5327 */
5328void
5329xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5330    if (obj == NULL) return;
5331    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5332	if (obj->boolval) {
5333#if 0
5334	    if (obj->user != NULL) {
5335                xmlXPathFreeNodeSet(obj->nodesetval);
5336		xmlFreeNodeList((xmlNodePtr) obj->user);
5337	    } else
5338#endif
5339	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5340	    if (obj->nodesetval != NULL)
5341		xmlXPathFreeValueTree(obj->nodesetval);
5342	} else {
5343	    if (obj->nodesetval != NULL)
5344		xmlXPathFreeNodeSet(obj->nodesetval);
5345	}
5346#ifdef LIBXML_XPTR_ENABLED
5347    } else if (obj->type == XPATH_LOCATIONSET) {
5348	if (obj->user != NULL)
5349	    xmlXPtrFreeLocationSet(obj->user);
5350#endif
5351    } else if (obj->type == XPATH_STRING) {
5352	if (obj->stringval != NULL)
5353	    xmlFree(obj->stringval);
5354    }
5355#ifdef XP_DEBUG_OBJ_USAGE
5356    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5357#endif
5358    xmlFree(obj);
5359}
5360
5361/**
5362 * xmlXPathReleaseObject:
5363 * @obj:  the xmlXPathObjectPtr to free or to cache
5364 *
5365 * Depending on the state of the cache this frees the given
5366 * XPath object or stores it in the cache.
5367 */
5368static void
5369xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5370{
5371#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5372	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5373    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5374
5375#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5376
5377    if (obj == NULL)
5378	return;
5379    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5380	 xmlXPathFreeObject(obj);
5381    } else {
5382	xmlXPathContextCachePtr cache =
5383	    (xmlXPathContextCachePtr) ctxt->cache;
5384
5385	switch (obj->type) {
5386	    case XPATH_NODESET:
5387	    case XPATH_XSLT_TREE:
5388		if (obj->nodesetval != NULL) {
5389		    if (obj->boolval) {
5390		    	/*
5391			* It looks like the @boolval is used for
5392			* evaluation if this an XSLT Result Tree Fragment.
5393			* TODO: Check if this assumption is correct.
5394			*/
5395			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5396			xmlXPathFreeValueTree(obj->nodesetval);
5397			obj->nodesetval = NULL;
5398		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5399			(XP_CACHE_WANTS(cache->nodesetObjs,
5400					cache->maxNodeset)))
5401		    {
5402			XP_CACHE_ADD(cache->nodesetObjs, obj);
5403			goto obj_cached;
5404		    } else {
5405			xmlXPathFreeNodeSet(obj->nodesetval);
5406			obj->nodesetval = NULL;
5407		    }
5408		}
5409		break;
5410	    case XPATH_STRING:
5411		if (obj->stringval != NULL)
5412		    xmlFree(obj->stringval);
5413
5414		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5415		    XP_CACHE_ADD(cache->stringObjs, obj);
5416		    goto obj_cached;
5417		}
5418		break;
5419	    case XPATH_BOOLEAN:
5420		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5421		    XP_CACHE_ADD(cache->booleanObjs, obj);
5422		    goto obj_cached;
5423		}
5424		break;
5425	    case XPATH_NUMBER:
5426		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5427		    XP_CACHE_ADD(cache->numberObjs, obj);
5428		    goto obj_cached;
5429		}
5430		break;
5431#ifdef LIBXML_XPTR_ENABLED
5432	    case XPATH_LOCATIONSET:
5433		if (obj->user != NULL) {
5434		    xmlXPtrFreeLocationSet(obj->user);
5435		}
5436		goto free_obj;
5437#endif
5438	    default:
5439		goto free_obj;
5440	}
5441
5442	/*
5443	* Fallback to adding to the misc-objects slot.
5444	*/
5445	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5446	    XP_CACHE_ADD(cache->miscObjs, obj);
5447	} else
5448	    goto free_obj;
5449
5450obj_cached:
5451
5452#ifdef XP_DEBUG_OBJ_USAGE
5453	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5454#endif
5455
5456	if (obj->nodesetval != NULL) {
5457	    xmlNodeSetPtr tmpset = obj->nodesetval;
5458
5459	    /*
5460	    * TODO: Due to those nasty ns-nodes, we need to traverse
5461	    *  the list and free the ns-nodes.
5462	    * URGENT TODO: Check if it's actually slowing things down.
5463	    *  Maybe we shouldn't try to preserve the list.
5464	    */
5465	    if (tmpset->nodeNr > 1) {
5466		int i;
5467		xmlNodePtr node;
5468
5469		for (i = 0; i < tmpset->nodeNr; i++) {
5470		    node = tmpset->nodeTab[i];
5471		    if ((node != NULL) &&
5472			(node->type == XML_NAMESPACE_DECL))
5473		    {
5474			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5475		    }
5476		}
5477	    } else if (tmpset->nodeNr == 1) {
5478		if ((tmpset->nodeTab[0] != NULL) &&
5479		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5480		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5481	    }
5482	    tmpset->nodeNr = 0;
5483	    memset(obj, 0, sizeof(xmlXPathObject));
5484	    obj->nodesetval = tmpset;
5485	} else
5486	    memset(obj, 0, sizeof(xmlXPathObject));
5487
5488	return;
5489
5490free_obj:
5491	/*
5492	* Cache is full; free the object.
5493	*/
5494	if (obj->nodesetval != NULL)
5495	    xmlXPathFreeNodeSet(obj->nodesetval);
5496#ifdef XP_DEBUG_OBJ_USAGE
5497	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5498#endif
5499	xmlFree(obj);
5500    }
5501    return;
5502}
5503
5504
5505/************************************************************************
5506 *									*
5507 *			Type Casting Routines				*
5508 *									*
5509 ************************************************************************/
5510
5511/**
5512 * xmlXPathCastBooleanToString:
5513 * @val:  a boolean
5514 *
5515 * Converts a boolean to its string value.
5516 *
5517 * Returns a newly allocated string.
5518 */
5519xmlChar *
5520xmlXPathCastBooleanToString (int val) {
5521    xmlChar *ret;
5522    if (val)
5523	ret = xmlStrdup((const xmlChar *) "true");
5524    else
5525	ret = xmlStrdup((const xmlChar *) "false");
5526    return(ret);
5527}
5528
5529/**
5530 * xmlXPathCastNumberToString:
5531 * @val:  a number
5532 *
5533 * Converts a number to its string value.
5534 *
5535 * Returns a newly allocated string.
5536 */
5537xmlChar *
5538xmlXPathCastNumberToString (double val) {
5539    xmlChar *ret;
5540    switch (xmlXPathIsInf(val)) {
5541    case 1:
5542	ret = xmlStrdup((const xmlChar *) "Infinity");
5543	break;
5544    case -1:
5545	ret = xmlStrdup((const xmlChar *) "-Infinity");
5546	break;
5547    default:
5548	if (xmlXPathIsNaN(val)) {
5549	    ret = xmlStrdup((const xmlChar *) "NaN");
5550	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
5551	    ret = xmlStrdup((const xmlChar *) "0");
5552	} else {
5553	    /* could be improved */
5554	    char buf[100];
5555	    xmlXPathFormatNumber(val, buf, 99);
5556	    buf[99] = 0;
5557	    ret = xmlStrdup((const xmlChar *) buf);
5558	}
5559    }
5560    return(ret);
5561}
5562
5563/**
5564 * xmlXPathCastNodeToString:
5565 * @node:  a node
5566 *
5567 * Converts a node to its string value.
5568 *
5569 * Returns a newly allocated string.
5570 */
5571xmlChar *
5572xmlXPathCastNodeToString (xmlNodePtr node) {
5573    return(xmlNodeGetContent(node));
5574}
5575
5576/**
5577 * xmlXPathCastNodeSetToString:
5578 * @ns:  a node-set
5579 *
5580 * Converts a node-set to its string value.
5581 *
5582 * Returns a newly allocated string.
5583 */
5584xmlChar *
5585xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5586    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5587	return(xmlStrdup((const xmlChar *) ""));
5588
5589    if (ns->nodeNr > 1)
5590	xmlXPathNodeSetSort(ns);
5591    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5592}
5593
5594/**
5595 * xmlXPathCastToString:
5596 * @val:  an XPath object
5597 *
5598 * Converts an existing object to its string() equivalent
5599 *
5600 * Returns the allocated string value of the object, NULL in case of error.
5601 *         It's up to the caller to free the string memory with xmlFree().
5602 */
5603xmlChar *
5604xmlXPathCastToString(xmlXPathObjectPtr val) {
5605    xmlChar *ret = NULL;
5606
5607    if (val == NULL)
5608	return(xmlStrdup((const xmlChar *) ""));
5609    switch (val->type) {
5610	case XPATH_UNDEFINED:
5611#ifdef DEBUG_EXPR
5612	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5613#endif
5614	    ret = xmlStrdup((const xmlChar *) "");
5615	    break;
5616        case XPATH_NODESET:
5617        case XPATH_XSLT_TREE:
5618	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5619	    break;
5620	case XPATH_STRING:
5621	    return(xmlStrdup(val->stringval));
5622        case XPATH_BOOLEAN:
5623	    ret = xmlXPathCastBooleanToString(val->boolval);
5624	    break;
5625	case XPATH_NUMBER: {
5626	    ret = xmlXPathCastNumberToString(val->floatval);
5627	    break;
5628	}
5629	case XPATH_USERS:
5630	case XPATH_POINT:
5631	case XPATH_RANGE:
5632	case XPATH_LOCATIONSET:
5633	    TODO
5634	    ret = xmlStrdup((const xmlChar *) "");
5635	    break;
5636    }
5637    return(ret);
5638}
5639
5640/**
5641 * xmlXPathConvertString:
5642 * @val:  an XPath object
5643 *
5644 * Converts an existing object to its string() equivalent
5645 *
5646 * Returns the new object, the old one is freed (or the operation
5647 *         is done directly on @val)
5648 */
5649xmlXPathObjectPtr
5650xmlXPathConvertString(xmlXPathObjectPtr val) {
5651    xmlChar *res = NULL;
5652
5653    if (val == NULL)
5654	return(xmlXPathNewCString(""));
5655
5656    switch (val->type) {
5657    case XPATH_UNDEFINED:
5658#ifdef DEBUG_EXPR
5659	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5660#endif
5661	break;
5662    case XPATH_NODESET:
5663    case XPATH_XSLT_TREE:
5664	res = xmlXPathCastNodeSetToString(val->nodesetval);
5665	break;
5666    case XPATH_STRING:
5667	return(val);
5668    case XPATH_BOOLEAN:
5669	res = xmlXPathCastBooleanToString(val->boolval);
5670	break;
5671    case XPATH_NUMBER:
5672	res = xmlXPathCastNumberToString(val->floatval);
5673	break;
5674    case XPATH_USERS:
5675    case XPATH_POINT:
5676    case XPATH_RANGE:
5677    case XPATH_LOCATIONSET:
5678	TODO;
5679	break;
5680    }
5681    xmlXPathFreeObject(val);
5682    if (res == NULL)
5683	return(xmlXPathNewCString(""));
5684    return(xmlXPathWrapString(res));
5685}
5686
5687/**
5688 * xmlXPathCastBooleanToNumber:
5689 * @val:  a boolean
5690 *
5691 * Converts a boolean to its number value
5692 *
5693 * Returns the number value
5694 */
5695double
5696xmlXPathCastBooleanToNumber(int val) {
5697    if (val)
5698	return(1.0);
5699    return(0.0);
5700}
5701
5702/**
5703 * xmlXPathCastStringToNumber:
5704 * @val:  a string
5705 *
5706 * Converts a string to its number value
5707 *
5708 * Returns the number value
5709 */
5710double
5711xmlXPathCastStringToNumber(const xmlChar * val) {
5712    return(xmlXPathStringEvalNumber(val));
5713}
5714
5715/**
5716 * xmlXPathCastNodeToNumber:
5717 * @node:  a node
5718 *
5719 * Converts a node to its number value
5720 *
5721 * Returns the number value
5722 */
5723double
5724xmlXPathCastNodeToNumber (xmlNodePtr node) {
5725    xmlChar *strval;
5726    double ret;
5727
5728    if (node == NULL)
5729	return(xmlXPathNAN);
5730    strval = xmlXPathCastNodeToString(node);
5731    if (strval == NULL)
5732	return(xmlXPathNAN);
5733    ret = xmlXPathCastStringToNumber(strval);
5734    xmlFree(strval);
5735
5736    return(ret);
5737}
5738
5739/**
5740 * xmlXPathCastNodeSetToNumber:
5741 * @ns:  a node-set
5742 *
5743 * Converts a node-set to its number value
5744 *
5745 * Returns the number value
5746 */
5747double
5748xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5749    xmlChar *str;
5750    double ret;
5751
5752    if (ns == NULL)
5753	return(xmlXPathNAN);
5754    str = xmlXPathCastNodeSetToString(ns);
5755    ret = xmlXPathCastStringToNumber(str);
5756    xmlFree(str);
5757    return(ret);
5758}
5759
5760/**
5761 * xmlXPathCastToNumber:
5762 * @val:  an XPath object
5763 *
5764 * Converts an XPath object to its number value
5765 *
5766 * Returns the number value
5767 */
5768double
5769xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5770    double ret = 0.0;
5771
5772    if (val == NULL)
5773	return(xmlXPathNAN);
5774    switch (val->type) {
5775    case XPATH_UNDEFINED:
5776#ifdef DEGUB_EXPR
5777	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5778#endif
5779	ret = xmlXPathNAN;
5780	break;
5781    case XPATH_NODESET:
5782    case XPATH_XSLT_TREE:
5783	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5784	break;
5785    case XPATH_STRING:
5786	ret = xmlXPathCastStringToNumber(val->stringval);
5787	break;
5788    case XPATH_NUMBER:
5789	ret = val->floatval;
5790	break;
5791    case XPATH_BOOLEAN:
5792	ret = xmlXPathCastBooleanToNumber(val->boolval);
5793	break;
5794    case XPATH_USERS:
5795    case XPATH_POINT:
5796    case XPATH_RANGE:
5797    case XPATH_LOCATIONSET:
5798	TODO;
5799	ret = xmlXPathNAN;
5800	break;
5801    }
5802    return(ret);
5803}
5804
5805/**
5806 * xmlXPathConvertNumber:
5807 * @val:  an XPath object
5808 *
5809 * Converts an existing object to its number() equivalent
5810 *
5811 * Returns the new object, the old one is freed (or the operation
5812 *         is done directly on @val)
5813 */
5814xmlXPathObjectPtr
5815xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5816    xmlXPathObjectPtr ret;
5817
5818    if (val == NULL)
5819	return(xmlXPathNewFloat(0.0));
5820    if (val->type == XPATH_NUMBER)
5821	return(val);
5822    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5823    xmlXPathFreeObject(val);
5824    return(ret);
5825}
5826
5827/**
5828 * xmlXPathCastNumberToBoolean:
5829 * @val:  a number
5830 *
5831 * Converts a number to its boolean value
5832 *
5833 * Returns the boolean value
5834 */
5835int
5836xmlXPathCastNumberToBoolean (double val) {
5837     if (xmlXPathIsNaN(val) || (val == 0.0))
5838	 return(0);
5839     return(1);
5840}
5841
5842/**
5843 * xmlXPathCastStringToBoolean:
5844 * @val:  a string
5845 *
5846 * Converts a string to its boolean value
5847 *
5848 * Returns the boolean value
5849 */
5850int
5851xmlXPathCastStringToBoolean (const xmlChar *val) {
5852    if ((val == NULL) || (xmlStrlen(val) == 0))
5853	return(0);
5854    return(1);
5855}
5856
5857/**
5858 * xmlXPathCastNodeSetToBoolean:
5859 * @ns:  a node-set
5860 *
5861 * Converts a node-set to its boolean value
5862 *
5863 * Returns the boolean value
5864 */
5865int
5866xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5867    if ((ns == NULL) || (ns->nodeNr == 0))
5868	return(0);
5869    return(1);
5870}
5871
5872/**
5873 * xmlXPathCastToBoolean:
5874 * @val:  an XPath object
5875 *
5876 * Converts an XPath object to its boolean value
5877 *
5878 * Returns the boolean value
5879 */
5880int
5881xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5882    int ret = 0;
5883
5884    if (val == NULL)
5885	return(0);
5886    switch (val->type) {
5887    case XPATH_UNDEFINED:
5888#ifdef DEBUG_EXPR
5889	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5890#endif
5891	ret = 0;
5892	break;
5893    case XPATH_NODESET:
5894    case XPATH_XSLT_TREE:
5895	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5896	break;
5897    case XPATH_STRING:
5898	ret = xmlXPathCastStringToBoolean(val->stringval);
5899	break;
5900    case XPATH_NUMBER:
5901	ret = xmlXPathCastNumberToBoolean(val->floatval);
5902	break;
5903    case XPATH_BOOLEAN:
5904	ret = val->boolval;
5905	break;
5906    case XPATH_USERS:
5907    case XPATH_POINT:
5908    case XPATH_RANGE:
5909    case XPATH_LOCATIONSET:
5910	TODO;
5911	ret = 0;
5912	break;
5913    }
5914    return(ret);
5915}
5916
5917
5918/**
5919 * xmlXPathConvertBoolean:
5920 * @val:  an XPath object
5921 *
5922 * Converts an existing object to its boolean() equivalent
5923 *
5924 * Returns the new object, the old one is freed (or the operation
5925 *         is done directly on @val)
5926 */
5927xmlXPathObjectPtr
5928xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5929    xmlXPathObjectPtr ret;
5930
5931    if (val == NULL)
5932	return(xmlXPathNewBoolean(0));
5933    if (val->type == XPATH_BOOLEAN)
5934	return(val);
5935    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5936    xmlXPathFreeObject(val);
5937    return(ret);
5938}
5939
5940/************************************************************************
5941 *									*
5942 *		Routines to handle XPath contexts			*
5943 *									*
5944 ************************************************************************/
5945
5946/**
5947 * xmlXPathNewContext:
5948 * @doc:  the XML document
5949 *
5950 * Create a new xmlXPathContext
5951 *
5952 * Returns the xmlXPathContext just allocated. The caller will need to free it.
5953 */
5954xmlXPathContextPtr
5955xmlXPathNewContext(xmlDocPtr doc) {
5956    xmlXPathContextPtr ret;
5957
5958    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5959    if (ret == NULL) {
5960        xmlXPathErrMemory(NULL, "creating context\n");
5961	return(NULL);
5962    }
5963    memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5964    ret->doc = doc;
5965    ret->node = NULL;
5966
5967    ret->varHash = NULL;
5968
5969    ret->nb_types = 0;
5970    ret->max_types = 0;
5971    ret->types = NULL;
5972
5973    ret->funcHash = xmlHashCreate(0);
5974
5975    ret->nb_axis = 0;
5976    ret->max_axis = 0;
5977    ret->axis = NULL;
5978
5979    ret->nsHash = NULL;
5980    ret->user = NULL;
5981
5982    ret->contextSize = -1;
5983    ret->proximityPosition = -1;
5984
5985#ifdef XP_DEFAULT_CACHE_ON
5986    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
5987	xmlXPathFreeContext(ret);
5988	return(NULL);
5989    }
5990#endif
5991
5992    xmlXPathRegisterAllFunctions(ret);
5993
5994    return(ret);
5995}
5996
5997/**
5998 * xmlXPathFreeContext:
5999 * @ctxt:  the context to free
6000 *
6001 * Free up an xmlXPathContext
6002 */
6003void
6004xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6005    if (ctxt == NULL) return;
6006
6007    if (ctxt->cache != NULL)
6008	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6009    xmlXPathRegisteredNsCleanup(ctxt);
6010    xmlXPathRegisteredFuncsCleanup(ctxt);
6011    xmlXPathRegisteredVariablesCleanup(ctxt);
6012    xmlResetError(&ctxt->lastError);
6013    xmlFree(ctxt);
6014}
6015
6016/************************************************************************
6017 *									*
6018 *		Routines to handle XPath parser contexts		*
6019 *									*
6020 ************************************************************************/
6021
6022#define CHECK_CTXT(ctxt)						\
6023    if (ctxt == NULL) { 						\
6024	__xmlRaiseError(NULL, NULL, NULL,				\
6025		NULL, NULL, XML_FROM_XPATH,				\
6026		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6027		__FILE__, __LINE__,					\
6028		NULL, NULL, NULL, 0, 0,					\
6029		"NULL context pointer\n");				\
6030	return(NULL);							\
6031    }									\
6032
6033#define CHECK_CTXT_NEG(ctxt)						\
6034    if (ctxt == NULL) { 						\
6035	__xmlRaiseError(NULL, NULL, NULL,				\
6036		NULL, NULL, XML_FROM_XPATH,				\
6037		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6038		__FILE__, __LINE__,					\
6039		NULL, NULL, NULL, 0, 0,					\
6040		"NULL context pointer\n");				\
6041	return(-1);							\
6042    }									\
6043
6044
6045#define CHECK_CONTEXT(ctxt)						\
6046    if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6047        (ctxt->doc->children == NULL)) { 				\
6048	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6049	return(NULL);							\
6050    }
6051
6052
6053/**
6054 * xmlXPathNewParserContext:
6055 * @str:  the XPath expression
6056 * @ctxt:  the XPath context
6057 *
6058 * Create a new xmlXPathParserContext
6059 *
6060 * Returns the xmlXPathParserContext just allocated.
6061 */
6062xmlXPathParserContextPtr
6063xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6064    xmlXPathParserContextPtr ret;
6065
6066    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6067    if (ret == NULL) {
6068        xmlXPathErrMemory(ctxt, "creating parser context\n");
6069	return(NULL);
6070    }
6071    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6072    ret->cur = ret->base = str;
6073    ret->context = ctxt;
6074
6075    ret->comp = xmlXPathNewCompExpr();
6076    if (ret->comp == NULL) {
6077	xmlFree(ret->valueTab);
6078	xmlFree(ret);
6079	return(NULL);
6080    }
6081    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6082        ret->comp->dict = ctxt->dict;
6083	xmlDictReference(ret->comp->dict);
6084    }
6085
6086    return(ret);
6087}
6088
6089/**
6090 * xmlXPathCompParserContext:
6091 * @comp:  the XPath compiled expression
6092 * @ctxt:  the XPath context
6093 *
6094 * Create a new xmlXPathParserContext when processing a compiled expression
6095 *
6096 * Returns the xmlXPathParserContext just allocated.
6097 */
6098static xmlXPathParserContextPtr
6099xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6100    xmlXPathParserContextPtr ret;
6101
6102    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6103    if (ret == NULL) {
6104        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6105	return(NULL);
6106    }
6107    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6108
6109    /* Allocate the value stack */
6110    ret->valueTab = (xmlXPathObjectPtr *)
6111                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6112    if (ret->valueTab == NULL) {
6113	xmlFree(ret);
6114	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6115	return(NULL);
6116    }
6117    ret->valueNr = 0;
6118    ret->valueMax = 10;
6119    ret->value = NULL;
6120
6121    ret->context = ctxt;
6122    ret->comp = comp;
6123
6124    return(ret);
6125}
6126
6127/**
6128 * xmlXPathFreeParserContext:
6129 * @ctxt:  the context to free
6130 *
6131 * Free up an xmlXPathParserContext
6132 */
6133void
6134xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6135    if (ctxt->valueTab != NULL) {
6136        xmlFree(ctxt->valueTab);
6137    }
6138    if (ctxt->comp != NULL) {
6139#ifdef XPATH_STREAMING
6140	if (ctxt->comp->stream != NULL) {
6141	    xmlFreePatternList(ctxt->comp->stream);
6142	    ctxt->comp->stream = NULL;
6143	}
6144#endif
6145	xmlXPathFreeCompExpr(ctxt->comp);
6146    }
6147    xmlFree(ctxt);
6148}
6149
6150/************************************************************************
6151 *									*
6152 *		The implicit core function library			*
6153 *									*
6154 ************************************************************************/
6155
6156/**
6157 * xmlXPathNodeValHash:
6158 * @node:  a node pointer
6159 *
6160 * Function computing the beginning of the string value of the node,
6161 * used to speed up comparisons
6162 *
6163 * Returns an int usable as a hash
6164 */
6165static unsigned int
6166xmlXPathNodeValHash(xmlNodePtr node) {
6167    int len = 2;
6168    const xmlChar * string = NULL;
6169    xmlNodePtr tmp = NULL;
6170    unsigned int ret = 0;
6171
6172    if (node == NULL)
6173	return(0);
6174
6175    if (node->type == XML_DOCUMENT_NODE) {
6176	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6177	if (tmp == NULL)
6178	    node = node->children;
6179	else
6180	    node = tmp;
6181
6182	if (node == NULL)
6183	    return(0);
6184    }
6185
6186    switch (node->type) {
6187	case XML_COMMENT_NODE:
6188	case XML_PI_NODE:
6189	case XML_CDATA_SECTION_NODE:
6190	case XML_TEXT_NODE:
6191	    string = node->content;
6192	    if (string == NULL)
6193		return(0);
6194	    if (string[0] == 0)
6195		return(0);
6196	    return(((unsigned int) string[0]) +
6197		   (((unsigned int) string[1]) << 8));
6198	case XML_NAMESPACE_DECL:
6199	    string = ((xmlNsPtr)node)->href;
6200	    if (string == NULL)
6201		return(0);
6202	    if (string[0] == 0)
6203		return(0);
6204	    return(((unsigned int) string[0]) +
6205		   (((unsigned int) string[1]) << 8));
6206	case XML_ATTRIBUTE_NODE:
6207	    tmp = ((xmlAttrPtr) node)->children;
6208	    break;
6209	case XML_ELEMENT_NODE:
6210	    tmp = node->children;
6211	    break;
6212	default:
6213	    return(0);
6214    }
6215    while (tmp != NULL) {
6216	switch (tmp->type) {
6217	    case XML_COMMENT_NODE:
6218	    case XML_PI_NODE:
6219	    case XML_CDATA_SECTION_NODE:
6220	    case XML_TEXT_NODE:
6221		string = tmp->content;
6222		break;
6223	    case XML_NAMESPACE_DECL:
6224		string = ((xmlNsPtr)tmp)->href;
6225		break;
6226	    default:
6227		break;
6228	}
6229	if ((string != NULL) && (string[0] != 0)) {
6230	    if (len == 1) {
6231		return(ret + (((unsigned int) string[0]) << 8));
6232	    }
6233	    if (string[1] == 0) {
6234		len = 1;
6235		ret = (unsigned int) string[0];
6236	    } else {
6237		return(((unsigned int) string[0]) +
6238		       (((unsigned int) string[1]) << 8));
6239	    }
6240	}
6241	/*
6242	 * Skip to next node
6243	 */
6244	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6245	    if (tmp->children->type != XML_ENTITY_DECL) {
6246		tmp = tmp->children;
6247		continue;
6248	    }
6249	}
6250	if (tmp == node)
6251	    break;
6252
6253	if (tmp->next != NULL) {
6254	    tmp = tmp->next;
6255	    continue;
6256	}
6257
6258	do {
6259	    tmp = tmp->parent;
6260	    if (tmp == NULL)
6261		break;
6262	    if (tmp == node) {
6263		tmp = NULL;
6264		break;
6265	    }
6266	    if (tmp->next != NULL) {
6267		tmp = tmp->next;
6268		break;
6269	    }
6270	} while (tmp != NULL);
6271    }
6272    return(ret);
6273}
6274
6275/**
6276 * xmlXPathStringHash:
6277 * @string:  a string
6278 *
6279 * Function computing the beginning of the string value of the node,
6280 * used to speed up comparisons
6281 *
6282 * Returns an int usable as a hash
6283 */
6284static unsigned int
6285xmlXPathStringHash(const xmlChar * string) {
6286    if (string == NULL)
6287	return((unsigned int) 0);
6288    if (string[0] == 0)
6289	return(0);
6290    return(((unsigned int) string[0]) +
6291	   (((unsigned int) string[1]) << 8));
6292}
6293
6294/**
6295 * xmlXPathCompareNodeSetFloat:
6296 * @ctxt:  the XPath Parser context
6297 * @inf:  less than (1) or greater than (0)
6298 * @strict:  is the comparison strict
6299 * @arg:  the node set
6300 * @f:  the value
6301 *
6302 * Implement the compare operation between a nodeset and a number
6303 *     @ns < @val    (1, 1, ...
6304 *     @ns <= @val   (1, 0, ...
6305 *     @ns > @val    (0, 1, ...
6306 *     @ns >= @val   (0, 0, ...
6307 *
6308 * If one object to be compared is a node-set and the other is a number,
6309 * then the comparison will be true if and only if there is a node in the
6310 * node-set such that the result of performing the comparison on the number
6311 * to be compared and on the result of converting the string-value of that
6312 * node to a number using the number function is true.
6313 *
6314 * Returns 0 or 1 depending on the results of the test.
6315 */
6316static int
6317xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6318	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6319    int i, ret = 0;
6320    xmlNodeSetPtr ns;
6321    xmlChar *str2;
6322
6323    if ((f == NULL) || (arg == NULL) ||
6324	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6325	xmlXPathReleaseObject(ctxt->context, arg);
6326	xmlXPathReleaseObject(ctxt->context, f);
6327        return(0);
6328    }
6329    ns = arg->nodesetval;
6330    if (ns != NULL) {
6331	for (i = 0;i < ns->nodeNr;i++) {
6332	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6333	     if (str2 != NULL) {
6334		 valuePush(ctxt,
6335			   xmlXPathCacheNewString(ctxt->context, str2));
6336		 xmlFree(str2);
6337		 xmlXPathNumberFunction(ctxt, 1);
6338		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6339		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6340		 if (ret)
6341		     break;
6342	     }
6343	}
6344    }
6345    xmlXPathReleaseObject(ctxt->context, arg);
6346    xmlXPathReleaseObject(ctxt->context, f);
6347    return(ret);
6348}
6349
6350/**
6351 * xmlXPathCompareNodeSetString:
6352 * @ctxt:  the XPath Parser context
6353 * @inf:  less than (1) or greater than (0)
6354 * @strict:  is the comparison strict
6355 * @arg:  the node set
6356 * @s:  the value
6357 *
6358 * Implement the compare operation between a nodeset and a string
6359 *     @ns < @val    (1, 1, ...
6360 *     @ns <= @val   (1, 0, ...
6361 *     @ns > @val    (0, 1, ...
6362 *     @ns >= @val   (0, 0, ...
6363 *
6364 * If one object to be compared is a node-set and the other is a string,
6365 * then the comparison will be true if and only if there is a node in
6366 * the node-set such that the result of performing the comparison on the
6367 * string-value of the node and the other string is true.
6368 *
6369 * Returns 0 or 1 depending on the results of the test.
6370 */
6371static int
6372xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6373	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6374    int i, ret = 0;
6375    xmlNodeSetPtr ns;
6376    xmlChar *str2;
6377
6378    if ((s == NULL) || (arg == NULL) ||
6379	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6380	xmlXPathReleaseObject(ctxt->context, arg);
6381	xmlXPathReleaseObject(ctxt->context, s);
6382        return(0);
6383    }
6384    ns = arg->nodesetval;
6385    if (ns != NULL) {
6386	for (i = 0;i < ns->nodeNr;i++) {
6387	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6388	     if (str2 != NULL) {
6389		 valuePush(ctxt,
6390			   xmlXPathCacheNewString(ctxt->context, str2));
6391		 xmlFree(str2);
6392		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6393		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6394		 if (ret)
6395		     break;
6396	     }
6397	}
6398    }
6399    xmlXPathReleaseObject(ctxt->context, arg);
6400    xmlXPathReleaseObject(ctxt->context, s);
6401    return(ret);
6402}
6403
6404/**
6405 * xmlXPathCompareNodeSets:
6406 * @inf:  less than (1) or greater than (0)
6407 * @strict:  is the comparison strict
6408 * @arg1:  the first node set object
6409 * @arg2:  the second node set object
6410 *
6411 * Implement the compare operation on nodesets:
6412 *
6413 * If both objects to be compared are node-sets, then the comparison
6414 * will be true if and only if there is a node in the first node-set
6415 * and a node in the second node-set such that the result of performing
6416 * the comparison on the string-values of the two nodes is true.
6417 * ....
6418 * When neither object to be compared is a node-set and the operator
6419 * is <=, <, >= or >, then the objects are compared by converting both
6420 * objects to numbers and comparing the numbers according to IEEE 754.
6421 * ....
6422 * The number function converts its argument to a number as follows:
6423 *  - a string that consists of optional whitespace followed by an
6424 *    optional minus sign followed by a Number followed by whitespace
6425 *    is converted to the IEEE 754 number that is nearest (according
6426 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6427 *    represented by the string; any other string is converted to NaN
6428 *
6429 * Conclusion all nodes need to be converted first to their string value
6430 * and then the comparison must be done when possible
6431 */
6432static int
6433xmlXPathCompareNodeSets(int inf, int strict,
6434	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6435    int i, j, init = 0;
6436    double val1;
6437    double *values2;
6438    int ret = 0;
6439    xmlNodeSetPtr ns1;
6440    xmlNodeSetPtr ns2;
6441
6442    if ((arg1 == NULL) ||
6443	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6444	xmlXPathFreeObject(arg2);
6445        return(0);
6446    }
6447    if ((arg2 == NULL) ||
6448	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6449	xmlXPathFreeObject(arg1);
6450	xmlXPathFreeObject(arg2);
6451        return(0);
6452    }
6453
6454    ns1 = arg1->nodesetval;
6455    ns2 = arg2->nodesetval;
6456
6457    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6458	xmlXPathFreeObject(arg1);
6459	xmlXPathFreeObject(arg2);
6460	return(0);
6461    }
6462    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6463	xmlXPathFreeObject(arg1);
6464	xmlXPathFreeObject(arg2);
6465	return(0);
6466    }
6467
6468    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6469    if (values2 == NULL) {
6470        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6471	xmlXPathFreeObject(arg1);
6472	xmlXPathFreeObject(arg2);
6473	return(0);
6474    }
6475    for (i = 0;i < ns1->nodeNr;i++) {
6476	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6477	if (xmlXPathIsNaN(val1))
6478	    continue;
6479	for (j = 0;j < ns2->nodeNr;j++) {
6480	    if (init == 0) {
6481		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6482	    }
6483	    if (xmlXPathIsNaN(values2[j]))
6484		continue;
6485	    if (inf && strict)
6486		ret = (val1 < values2[j]);
6487	    else if (inf && !strict)
6488		ret = (val1 <= values2[j]);
6489	    else if (!inf && strict)
6490		ret = (val1 > values2[j]);
6491	    else if (!inf && !strict)
6492		ret = (val1 >= values2[j]);
6493	    if (ret)
6494		break;
6495	}
6496	if (ret)
6497	    break;
6498	init = 1;
6499    }
6500    xmlFree(values2);
6501    xmlXPathFreeObject(arg1);
6502    xmlXPathFreeObject(arg2);
6503    return(ret);
6504}
6505
6506/**
6507 * xmlXPathCompareNodeSetValue:
6508 * @ctxt:  the XPath Parser context
6509 * @inf:  less than (1) or greater than (0)
6510 * @strict:  is the comparison strict
6511 * @arg:  the node set
6512 * @val:  the value
6513 *
6514 * Implement the compare operation between a nodeset and a value
6515 *     @ns < @val    (1, 1, ...
6516 *     @ns <= @val   (1, 0, ...
6517 *     @ns > @val    (0, 1, ...
6518 *     @ns >= @val   (0, 0, ...
6519 *
6520 * If one object to be compared is a node-set and the other is a boolean,
6521 * then the comparison will be true if and only if the result of performing
6522 * the comparison on the boolean and on the result of converting
6523 * the node-set to a boolean using the boolean function is true.
6524 *
6525 * Returns 0 or 1 depending on the results of the test.
6526 */
6527static int
6528xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6529	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6530    if ((val == NULL) || (arg == NULL) ||
6531	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6532        return(0);
6533
6534    switch(val->type) {
6535        case XPATH_NUMBER:
6536	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6537        case XPATH_NODESET:
6538        case XPATH_XSLT_TREE:
6539	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6540        case XPATH_STRING:
6541	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6542        case XPATH_BOOLEAN:
6543	    valuePush(ctxt, arg);
6544	    xmlXPathBooleanFunction(ctxt, 1);
6545	    valuePush(ctxt, val);
6546	    return(xmlXPathCompareValues(ctxt, inf, strict));
6547	default:
6548	    TODO
6549    }
6550    return(0);
6551}
6552
6553/**
6554 * xmlXPathEqualNodeSetString:
6555 * @arg:  the nodeset object argument
6556 * @str:  the string to compare to.
6557 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6558 *
6559 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6560 * If one object to be compared is a node-set and the other is a string,
6561 * then the comparison will be true if and only if there is a node in
6562 * the node-set such that the result of performing the comparison on the
6563 * string-value of the node and the other string is true.
6564 *
6565 * Returns 0 or 1 depending on the results of the test.
6566 */
6567static int
6568xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6569{
6570    int i;
6571    xmlNodeSetPtr ns;
6572    xmlChar *str2;
6573    unsigned int hash;
6574
6575    if ((str == NULL) || (arg == NULL) ||
6576        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6577        return (0);
6578    ns = arg->nodesetval;
6579    /*
6580     * A NULL nodeset compared with a string is always false
6581     * (since there is no node equal, and no node not equal)
6582     */
6583    if ((ns == NULL) || (ns->nodeNr <= 0) )
6584        return (0);
6585    hash = xmlXPathStringHash(str);
6586    for (i = 0; i < ns->nodeNr; i++) {
6587        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6588            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6589            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6590                xmlFree(str2);
6591		if (neq)
6592		    continue;
6593                return (1);
6594	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6595		if (neq)
6596		    continue;
6597                return (1);
6598            } else if (neq) {
6599		if (str2 != NULL)
6600		    xmlFree(str2);
6601		return (1);
6602	    }
6603            if (str2 != NULL)
6604                xmlFree(str2);
6605        } else if (neq)
6606	    return (1);
6607    }
6608    return (0);
6609}
6610
6611/**
6612 * xmlXPathEqualNodeSetFloat:
6613 * @arg:  the nodeset object argument
6614 * @f:  the float to compare to
6615 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6616 *
6617 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6618 * If one object to be compared is a node-set and the other is a number,
6619 * then the comparison will be true if and only if there is a node in
6620 * the node-set such that the result of performing the comparison on the
6621 * number to be compared and on the result of converting the string-value
6622 * of that node to a number using the number function is true.
6623 *
6624 * Returns 0 or 1 depending on the results of the test.
6625 */
6626static int
6627xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6628    xmlXPathObjectPtr arg, double f, int neq) {
6629  int i, ret=0;
6630  xmlNodeSetPtr ns;
6631  xmlChar *str2;
6632  xmlXPathObjectPtr val;
6633  double v;
6634
6635    if ((arg == NULL) ||
6636	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6637        return(0);
6638
6639    ns = arg->nodesetval;
6640    if (ns != NULL) {
6641	for (i=0;i<ns->nodeNr;i++) {
6642	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6643	    if (str2 != NULL) {
6644		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6645		xmlFree(str2);
6646		xmlXPathNumberFunction(ctxt, 1);
6647		val = valuePop(ctxt);
6648		v = val->floatval;
6649		xmlXPathReleaseObject(ctxt->context, val);
6650		if (!xmlXPathIsNaN(v)) {
6651		    if ((!neq) && (v==f)) {
6652			ret = 1;
6653			break;
6654		    } else if ((neq) && (v!=f)) {
6655			ret = 1;
6656			break;
6657		    }
6658		} else {	/* NaN is unequal to any value */
6659		    if (neq)
6660			ret = 1;
6661		}
6662	    }
6663	}
6664    }
6665
6666    return(ret);
6667}
6668
6669
6670/**
6671 * xmlXPathEqualNodeSets:
6672 * @arg1:  first nodeset object argument
6673 * @arg2:  second nodeset object argument
6674 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6675 *
6676 * Implement the equal / not equal operation on XPath nodesets:
6677 * @arg1 == @arg2  or  @arg1 != @arg2
6678 * If both objects to be compared are node-sets, then the comparison
6679 * will be true if and only if there is a node in the first node-set and
6680 * a node in the second node-set such that the result of performing the
6681 * comparison on the string-values of the two nodes is true.
6682 *
6683 * (needless to say, this is a costly operation)
6684 *
6685 * Returns 0 or 1 depending on the results of the test.
6686 */
6687static int
6688xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6689    int i, j;
6690    unsigned int *hashs1;
6691    unsigned int *hashs2;
6692    xmlChar **values1;
6693    xmlChar **values2;
6694    int ret = 0;
6695    xmlNodeSetPtr ns1;
6696    xmlNodeSetPtr ns2;
6697
6698    if ((arg1 == NULL) ||
6699	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6700        return(0);
6701    if ((arg2 == NULL) ||
6702	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6703        return(0);
6704
6705    ns1 = arg1->nodesetval;
6706    ns2 = arg2->nodesetval;
6707
6708    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6709	return(0);
6710    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6711	return(0);
6712
6713    /*
6714     * for equal, check if there is a node pertaining to both sets
6715     */
6716    if (neq == 0)
6717	for (i = 0;i < ns1->nodeNr;i++)
6718	    for (j = 0;j < ns2->nodeNr;j++)
6719		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6720		    return(1);
6721
6722    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6723    if (values1 == NULL) {
6724        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6725	return(0);
6726    }
6727    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6728    if (hashs1 == NULL) {
6729        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6730	xmlFree(values1);
6731	return(0);
6732    }
6733    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6734    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6735    if (values2 == NULL) {
6736        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6737	xmlFree(hashs1);
6738	xmlFree(values1);
6739	return(0);
6740    }
6741    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6742    if (hashs2 == NULL) {
6743        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6744	xmlFree(hashs1);
6745	xmlFree(values1);
6746	xmlFree(values2);
6747	return(0);
6748    }
6749    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6750    for (i = 0;i < ns1->nodeNr;i++) {
6751	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6752	for (j = 0;j < ns2->nodeNr;j++) {
6753	    if (i == 0)
6754		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6755	    if (hashs1[i] != hashs2[j]) {
6756		if (neq) {
6757		    ret = 1;
6758		    break;
6759		}
6760	    }
6761	    else {
6762		if (values1[i] == NULL)
6763		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6764		if (values2[j] == NULL)
6765		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6766		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6767		if (ret)
6768		    break;
6769	    }
6770	}
6771	if (ret)
6772	    break;
6773    }
6774    for (i = 0;i < ns1->nodeNr;i++)
6775	if (values1[i] != NULL)
6776	    xmlFree(values1[i]);
6777    for (j = 0;j < ns2->nodeNr;j++)
6778	if (values2[j] != NULL)
6779	    xmlFree(values2[j]);
6780    xmlFree(values1);
6781    xmlFree(values2);
6782    xmlFree(hashs1);
6783    xmlFree(hashs2);
6784    return(ret);
6785}
6786
6787static int
6788xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6789  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6790    int ret = 0;
6791    /*
6792     *At this point we are assured neither arg1 nor arg2
6793     *is a nodeset, so we can just pick the appropriate routine.
6794     */
6795    switch (arg1->type) {
6796        case XPATH_UNDEFINED:
6797#ifdef DEBUG_EXPR
6798	    xmlGenericError(xmlGenericErrorContext,
6799		    "Equal: undefined\n");
6800#endif
6801	    break;
6802        case XPATH_BOOLEAN:
6803	    switch (arg2->type) {
6804	        case XPATH_UNDEFINED:
6805#ifdef DEBUG_EXPR
6806		    xmlGenericError(xmlGenericErrorContext,
6807			    "Equal: undefined\n");
6808#endif
6809		    break;
6810		case XPATH_BOOLEAN:
6811#ifdef DEBUG_EXPR
6812		    xmlGenericError(xmlGenericErrorContext,
6813			    "Equal: %d boolean %d \n",
6814			    arg1->boolval, arg2->boolval);
6815#endif
6816		    ret = (arg1->boolval == arg2->boolval);
6817		    break;
6818		case XPATH_NUMBER:
6819		    ret = (arg1->boolval ==
6820			   xmlXPathCastNumberToBoolean(arg2->floatval));
6821		    break;
6822		case XPATH_STRING:
6823		    if ((arg2->stringval == NULL) ||
6824			(arg2->stringval[0] == 0)) ret = 0;
6825		    else
6826			ret = 1;
6827		    ret = (arg1->boolval == ret);
6828		    break;
6829		case XPATH_USERS:
6830		case XPATH_POINT:
6831		case XPATH_RANGE:
6832		case XPATH_LOCATIONSET:
6833		    TODO
6834		    break;
6835		case XPATH_NODESET:
6836		case XPATH_XSLT_TREE:
6837		    break;
6838	    }
6839	    break;
6840        case XPATH_NUMBER:
6841	    switch (arg2->type) {
6842	        case XPATH_UNDEFINED:
6843#ifdef DEBUG_EXPR
6844		    xmlGenericError(xmlGenericErrorContext,
6845			    "Equal: undefined\n");
6846#endif
6847		    break;
6848		case XPATH_BOOLEAN:
6849		    ret = (arg2->boolval==
6850			   xmlXPathCastNumberToBoolean(arg1->floatval));
6851		    break;
6852		case XPATH_STRING:
6853		    valuePush(ctxt, arg2);
6854		    xmlXPathNumberFunction(ctxt, 1);
6855		    arg2 = valuePop(ctxt);
6856		    /* no break on purpose */
6857		case XPATH_NUMBER:
6858		    /* Hand check NaN and Infinity equalities */
6859		    if (xmlXPathIsNaN(arg1->floatval) ||
6860		    	    xmlXPathIsNaN(arg2->floatval)) {
6861		        ret = 0;
6862		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6863		        if (xmlXPathIsInf(arg2->floatval) == 1)
6864			    ret = 1;
6865			else
6866			    ret = 0;
6867		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6868			if (xmlXPathIsInf(arg2->floatval) == -1)
6869			    ret = 1;
6870			else
6871			    ret = 0;
6872		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6873			if (xmlXPathIsInf(arg1->floatval) == 1)
6874			    ret = 1;
6875			else
6876			    ret = 0;
6877		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6878			if (xmlXPathIsInf(arg1->floatval) == -1)
6879			    ret = 1;
6880			else
6881			    ret = 0;
6882		    } else {
6883		        ret = (arg1->floatval == arg2->floatval);
6884		    }
6885		    break;
6886		case XPATH_USERS:
6887		case XPATH_POINT:
6888		case XPATH_RANGE:
6889		case XPATH_LOCATIONSET:
6890		    TODO
6891		    break;
6892		case XPATH_NODESET:
6893		case XPATH_XSLT_TREE:
6894		    break;
6895	    }
6896	    break;
6897        case XPATH_STRING:
6898	    switch (arg2->type) {
6899	        case XPATH_UNDEFINED:
6900#ifdef DEBUG_EXPR
6901		    xmlGenericError(xmlGenericErrorContext,
6902			    "Equal: undefined\n");
6903#endif
6904		    break;
6905		case XPATH_BOOLEAN:
6906		    if ((arg1->stringval == NULL) ||
6907			(arg1->stringval[0] == 0)) ret = 0;
6908		    else
6909			ret = 1;
6910		    ret = (arg2->boolval == ret);
6911		    break;
6912		case XPATH_STRING:
6913		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6914		    break;
6915		case XPATH_NUMBER:
6916		    valuePush(ctxt, arg1);
6917		    xmlXPathNumberFunction(ctxt, 1);
6918		    arg1 = valuePop(ctxt);
6919		    /* Hand check NaN and Infinity equalities */
6920		    if (xmlXPathIsNaN(arg1->floatval) ||
6921		    	    xmlXPathIsNaN(arg2->floatval)) {
6922		        ret = 0;
6923		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6924			if (xmlXPathIsInf(arg2->floatval) == 1)
6925			    ret = 1;
6926			else
6927			    ret = 0;
6928		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6929			if (xmlXPathIsInf(arg2->floatval) == -1)
6930			    ret = 1;
6931			else
6932			    ret = 0;
6933		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6934			if (xmlXPathIsInf(arg1->floatval) == 1)
6935			    ret = 1;
6936			else
6937			    ret = 0;
6938		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6939			if (xmlXPathIsInf(arg1->floatval) == -1)
6940			    ret = 1;
6941			else
6942			    ret = 0;
6943		    } else {
6944		        ret = (arg1->floatval == arg2->floatval);
6945		    }
6946		    break;
6947		case XPATH_USERS:
6948		case XPATH_POINT:
6949		case XPATH_RANGE:
6950		case XPATH_LOCATIONSET:
6951		    TODO
6952		    break;
6953		case XPATH_NODESET:
6954		case XPATH_XSLT_TREE:
6955		    break;
6956	    }
6957	    break;
6958        case XPATH_USERS:
6959	case XPATH_POINT:
6960	case XPATH_RANGE:
6961	case XPATH_LOCATIONSET:
6962	    TODO
6963	    break;
6964	case XPATH_NODESET:
6965	case XPATH_XSLT_TREE:
6966	    break;
6967    }
6968    xmlXPathReleaseObject(ctxt->context, arg1);
6969    xmlXPathReleaseObject(ctxt->context, arg2);
6970    return(ret);
6971}
6972
6973/**
6974 * xmlXPathEqualValues:
6975 * @ctxt:  the XPath Parser context
6976 *
6977 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6978 *
6979 * Returns 0 or 1 depending on the results of the test.
6980 */
6981int
6982xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6983    xmlXPathObjectPtr arg1, arg2, argtmp;
6984    int ret = 0;
6985
6986    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6987    arg2 = valuePop(ctxt);
6988    arg1 = valuePop(ctxt);
6989    if ((arg1 == NULL) || (arg2 == NULL)) {
6990	if (arg1 != NULL)
6991	    xmlXPathReleaseObject(ctxt->context, arg1);
6992	else
6993	    xmlXPathReleaseObject(ctxt->context, arg2);
6994	XP_ERROR0(XPATH_INVALID_OPERAND);
6995    }
6996
6997    if (arg1 == arg2) {
6998#ifdef DEBUG_EXPR
6999        xmlGenericError(xmlGenericErrorContext,
7000		"Equal: by pointer\n");
7001#endif
7002	xmlXPathFreeObject(arg1);
7003        return(1);
7004    }
7005
7006    /*
7007     *If either argument is a nodeset, it's a 'special case'
7008     */
7009    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7010      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7011	/*
7012	 *Hack it to assure arg1 is the nodeset
7013	 */
7014	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7015		argtmp = arg2;
7016		arg2 = arg1;
7017		arg1 = argtmp;
7018	}
7019	switch (arg2->type) {
7020	    case XPATH_UNDEFINED:
7021#ifdef DEBUG_EXPR
7022		xmlGenericError(xmlGenericErrorContext,
7023			"Equal: undefined\n");
7024#endif
7025		break;
7026	    case XPATH_NODESET:
7027	    case XPATH_XSLT_TREE:
7028		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7029		break;
7030	    case XPATH_BOOLEAN:
7031		if ((arg1->nodesetval == NULL) ||
7032		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7033		else
7034		    ret = 1;
7035		ret = (ret == arg2->boolval);
7036		break;
7037	    case XPATH_NUMBER:
7038		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7039		break;
7040	    case XPATH_STRING:
7041		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7042		break;
7043	    case XPATH_USERS:
7044	    case XPATH_POINT:
7045	    case XPATH_RANGE:
7046	    case XPATH_LOCATIONSET:
7047		TODO
7048		break;
7049	}
7050	xmlXPathReleaseObject(ctxt->context, arg1);
7051	xmlXPathReleaseObject(ctxt->context, arg2);
7052	return(ret);
7053    }
7054
7055    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7056}
7057
7058/**
7059 * xmlXPathNotEqualValues:
7060 * @ctxt:  the XPath Parser context
7061 *
7062 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7063 *
7064 * Returns 0 or 1 depending on the results of the test.
7065 */
7066int
7067xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7068    xmlXPathObjectPtr arg1, arg2, argtmp;
7069    int ret = 0;
7070
7071    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7072    arg2 = valuePop(ctxt);
7073    arg1 = valuePop(ctxt);
7074    if ((arg1 == NULL) || (arg2 == NULL)) {
7075	if (arg1 != NULL)
7076	    xmlXPathReleaseObject(ctxt->context, arg1);
7077	else
7078	    xmlXPathReleaseObject(ctxt->context, arg2);
7079	XP_ERROR0(XPATH_INVALID_OPERAND);
7080    }
7081
7082    if (arg1 == arg2) {
7083#ifdef DEBUG_EXPR
7084        xmlGenericError(xmlGenericErrorContext,
7085		"NotEqual: by pointer\n");
7086#endif
7087	xmlXPathReleaseObject(ctxt->context, arg1);
7088        return(0);
7089    }
7090
7091    /*
7092     *If either argument is a nodeset, it's a 'special case'
7093     */
7094    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7095      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7096	/*
7097	 *Hack it to assure arg1 is the nodeset
7098	 */
7099	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7100		argtmp = arg2;
7101		arg2 = arg1;
7102		arg1 = argtmp;
7103	}
7104	switch (arg2->type) {
7105	    case XPATH_UNDEFINED:
7106#ifdef DEBUG_EXPR
7107		xmlGenericError(xmlGenericErrorContext,
7108			"NotEqual: undefined\n");
7109#endif
7110		break;
7111	    case XPATH_NODESET:
7112	    case XPATH_XSLT_TREE:
7113		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7114		break;
7115	    case XPATH_BOOLEAN:
7116		if ((arg1->nodesetval == NULL) ||
7117		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7118		else
7119		    ret = 1;
7120		ret = (ret != arg2->boolval);
7121		break;
7122	    case XPATH_NUMBER:
7123		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7124		break;
7125	    case XPATH_STRING:
7126		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7127		break;
7128	    case XPATH_USERS:
7129	    case XPATH_POINT:
7130	    case XPATH_RANGE:
7131	    case XPATH_LOCATIONSET:
7132		TODO
7133		break;
7134	}
7135	xmlXPathReleaseObject(ctxt->context, arg1);
7136	xmlXPathReleaseObject(ctxt->context, arg2);
7137	return(ret);
7138    }
7139
7140    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7141}
7142
7143/**
7144 * xmlXPathCompareValues:
7145 * @ctxt:  the XPath Parser context
7146 * @inf:  less than (1) or greater than (0)
7147 * @strict:  is the comparison strict
7148 *
7149 * Implement the compare operation on XPath objects:
7150 *     @arg1 < @arg2    (1, 1, ...
7151 *     @arg1 <= @arg2   (1, 0, ...
7152 *     @arg1 > @arg2    (0, 1, ...
7153 *     @arg1 >= @arg2   (0, 0, ...
7154 *
7155 * When neither object to be compared is a node-set and the operator is
7156 * <=, <, >=, >, then the objects are compared by converted both objects
7157 * to numbers and comparing the numbers according to IEEE 754. The <
7158 * comparison will be true if and only if the first number is less than the
7159 * second number. The <= comparison will be true if and only if the first
7160 * number is less than or equal to the second number. The > comparison
7161 * will be true if and only if the first number is greater than the second
7162 * number. The >= comparison will be true if and only if the first number
7163 * is greater than or equal to the second number.
7164 *
7165 * Returns 1 if the comparison succeeded, 0 if it failed
7166 */
7167int
7168xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7169    int ret = 0, arg1i = 0, arg2i = 0;
7170    xmlXPathObjectPtr arg1, arg2;
7171
7172    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7173    arg2 = valuePop(ctxt);
7174    arg1 = valuePop(ctxt);
7175    if ((arg1 == NULL) || (arg2 == NULL)) {
7176	if (arg1 != NULL)
7177	    xmlXPathReleaseObject(ctxt->context, arg1);
7178	else
7179	    xmlXPathReleaseObject(ctxt->context, arg2);
7180	XP_ERROR0(XPATH_INVALID_OPERAND);
7181    }
7182
7183    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7184      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7185	/*
7186	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7187	 * are not freed from within this routine; they will be freed from the
7188	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7189	 */
7190	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7191	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7192	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7193	} else {
7194	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7195		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7196			                          arg1, arg2);
7197	    } else {
7198		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7199			                          arg2, arg1);
7200	    }
7201	}
7202	return(ret);
7203    }
7204
7205    if (arg1->type != XPATH_NUMBER) {
7206	valuePush(ctxt, arg1);
7207	xmlXPathNumberFunction(ctxt, 1);
7208	arg1 = valuePop(ctxt);
7209    }
7210    if (arg1->type != XPATH_NUMBER) {
7211	xmlXPathFreeObject(arg1);
7212	xmlXPathFreeObject(arg2);
7213	XP_ERROR0(XPATH_INVALID_OPERAND);
7214    }
7215    if (arg2->type != XPATH_NUMBER) {
7216	valuePush(ctxt, arg2);
7217	xmlXPathNumberFunction(ctxt, 1);
7218	arg2 = valuePop(ctxt);
7219    }
7220    if (arg2->type != XPATH_NUMBER) {
7221	xmlXPathReleaseObject(ctxt->context, arg1);
7222	xmlXPathReleaseObject(ctxt->context, arg2);
7223	XP_ERROR0(XPATH_INVALID_OPERAND);
7224    }
7225    /*
7226     * Add tests for infinity and nan
7227     * => feedback on 3.4 for Inf and NaN
7228     */
7229    /* Hand check NaN and Infinity comparisons */
7230    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7231	ret=0;
7232    } else {
7233	arg1i=xmlXPathIsInf(arg1->floatval);
7234	arg2i=xmlXPathIsInf(arg2->floatval);
7235	if (inf && strict) {
7236	    if ((arg1i == -1 && arg2i != -1) ||
7237		(arg2i == 1 && arg1i != 1)) {
7238		ret = 1;
7239	    } else if (arg1i == 0 && arg2i == 0) {
7240		ret = (arg1->floatval < arg2->floatval);
7241	    } else {
7242		ret = 0;
7243	    }
7244	}
7245	else if (inf && !strict) {
7246	    if (arg1i == -1 || arg2i == 1) {
7247		ret = 1;
7248	    } else if (arg1i == 0 && arg2i == 0) {
7249		ret = (arg1->floatval <= arg2->floatval);
7250	    } else {
7251		ret = 0;
7252	    }
7253	}
7254	else if (!inf && strict) {
7255	    if ((arg1i == 1 && arg2i != 1) ||
7256		(arg2i == -1 && arg1i != -1)) {
7257		ret = 1;
7258	    } else if (arg1i == 0 && arg2i == 0) {
7259		ret = (arg1->floatval > arg2->floatval);
7260	    } else {
7261		ret = 0;
7262	    }
7263	}
7264	else if (!inf && !strict) {
7265	    if (arg1i == 1 || arg2i == -1) {
7266		ret = 1;
7267	    } else if (arg1i == 0 && arg2i == 0) {
7268		ret = (arg1->floatval >= arg2->floatval);
7269	    } else {
7270		ret = 0;
7271	    }
7272	}
7273    }
7274    xmlXPathReleaseObject(ctxt->context, arg1);
7275    xmlXPathReleaseObject(ctxt->context, arg2);
7276    return(ret);
7277}
7278
7279/**
7280 * xmlXPathValueFlipSign:
7281 * @ctxt:  the XPath Parser context
7282 *
7283 * Implement the unary - operation on an XPath object
7284 * The numeric operators convert their operands to numbers as if
7285 * by calling the number function.
7286 */
7287void
7288xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7289    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7290    CAST_TO_NUMBER;
7291    CHECK_TYPE(XPATH_NUMBER);
7292    if (xmlXPathIsNaN(ctxt->value->floatval))
7293        ctxt->value->floatval=xmlXPathNAN;
7294    else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7295        ctxt->value->floatval=xmlXPathNINF;
7296    else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7297        ctxt->value->floatval=xmlXPathPINF;
7298    else if (ctxt->value->floatval == 0) {
7299        if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7300	    ctxt->value->floatval = xmlXPathNZERO;
7301	else
7302	    ctxt->value->floatval = 0;
7303    }
7304    else
7305        ctxt->value->floatval = - ctxt->value->floatval;
7306}
7307
7308/**
7309 * xmlXPathAddValues:
7310 * @ctxt:  the XPath Parser context
7311 *
7312 * Implement the add operation on XPath objects:
7313 * The numeric operators convert their operands to numbers as if
7314 * by calling the number function.
7315 */
7316void
7317xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7318    xmlXPathObjectPtr arg;
7319    double val;
7320
7321    arg = valuePop(ctxt);
7322    if (arg == NULL)
7323	XP_ERROR(XPATH_INVALID_OPERAND);
7324    val = xmlXPathCastToNumber(arg);
7325    xmlXPathReleaseObject(ctxt->context, arg);
7326    CAST_TO_NUMBER;
7327    CHECK_TYPE(XPATH_NUMBER);
7328    ctxt->value->floatval += val;
7329}
7330
7331/**
7332 * xmlXPathSubValues:
7333 * @ctxt:  the XPath Parser context
7334 *
7335 * Implement the subtraction operation on XPath objects:
7336 * The numeric operators convert their operands to numbers as if
7337 * by calling the number function.
7338 */
7339void
7340xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7341    xmlXPathObjectPtr arg;
7342    double val;
7343
7344    arg = valuePop(ctxt);
7345    if (arg == NULL)
7346	XP_ERROR(XPATH_INVALID_OPERAND);
7347    val = xmlXPathCastToNumber(arg);
7348    xmlXPathReleaseObject(ctxt->context, arg);
7349    CAST_TO_NUMBER;
7350    CHECK_TYPE(XPATH_NUMBER);
7351    ctxt->value->floatval -= val;
7352}
7353
7354/**
7355 * xmlXPathMultValues:
7356 * @ctxt:  the XPath Parser context
7357 *
7358 * Implement the multiply operation on XPath objects:
7359 * The numeric operators convert their operands to numbers as if
7360 * by calling the number function.
7361 */
7362void
7363xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7364    xmlXPathObjectPtr arg;
7365    double val;
7366
7367    arg = valuePop(ctxt);
7368    if (arg == NULL)
7369	XP_ERROR(XPATH_INVALID_OPERAND);
7370    val = xmlXPathCastToNumber(arg);
7371    xmlXPathReleaseObject(ctxt->context, arg);
7372    CAST_TO_NUMBER;
7373    CHECK_TYPE(XPATH_NUMBER);
7374    ctxt->value->floatval *= val;
7375}
7376
7377/**
7378 * xmlXPathDivValues:
7379 * @ctxt:  the XPath Parser context
7380 *
7381 * Implement the div operation on XPath objects @arg1 / @arg2:
7382 * The numeric operators convert their operands to numbers as if
7383 * by calling the number function.
7384 */
7385void
7386xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7387    xmlXPathObjectPtr arg;
7388    double val;
7389
7390    arg = valuePop(ctxt);
7391    if (arg == NULL)
7392	XP_ERROR(XPATH_INVALID_OPERAND);
7393    val = xmlXPathCastToNumber(arg);
7394    xmlXPathReleaseObject(ctxt->context, arg);
7395    CAST_TO_NUMBER;
7396    CHECK_TYPE(XPATH_NUMBER);
7397    if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7398	ctxt->value->floatval = xmlXPathNAN;
7399    else if (val == 0 && xmlXPathGetSign(val) != 0) {
7400	if (ctxt->value->floatval == 0)
7401	    ctxt->value->floatval = xmlXPathNAN;
7402	else if (ctxt->value->floatval > 0)
7403	    ctxt->value->floatval = xmlXPathNINF;
7404	else if (ctxt->value->floatval < 0)
7405	    ctxt->value->floatval = xmlXPathPINF;
7406    }
7407    else if (val == 0) {
7408	if (ctxt->value->floatval == 0)
7409	    ctxt->value->floatval = xmlXPathNAN;
7410	else if (ctxt->value->floatval > 0)
7411	    ctxt->value->floatval = xmlXPathPINF;
7412	else if (ctxt->value->floatval < 0)
7413	    ctxt->value->floatval = xmlXPathNINF;
7414    } else
7415	ctxt->value->floatval /= val;
7416}
7417
7418/**
7419 * xmlXPathModValues:
7420 * @ctxt:  the XPath Parser context
7421 *
7422 * Implement the mod operation on XPath objects: @arg1 / @arg2
7423 * The numeric operators convert their operands to numbers as if
7424 * by calling the number function.
7425 */
7426void
7427xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7428    xmlXPathObjectPtr arg;
7429    double arg1, arg2;
7430
7431    arg = valuePop(ctxt);
7432    if (arg == NULL)
7433	XP_ERROR(XPATH_INVALID_OPERAND);
7434    arg2 = xmlXPathCastToNumber(arg);
7435    xmlXPathReleaseObject(ctxt->context, arg);
7436    CAST_TO_NUMBER;
7437    CHECK_TYPE(XPATH_NUMBER);
7438    arg1 = ctxt->value->floatval;
7439    if (arg2 == 0)
7440	ctxt->value->floatval = xmlXPathNAN;
7441    else {
7442	ctxt->value->floatval = fmod(arg1, arg2);
7443    }
7444}
7445
7446/************************************************************************
7447 *									*
7448 *		The traversal functions					*
7449 *									*
7450 ************************************************************************/
7451
7452/*
7453 * A traversal function enumerates nodes along an axis.
7454 * Initially it must be called with NULL, and it indicates
7455 * termination on the axis by returning NULL.
7456 */
7457typedef xmlNodePtr (*xmlXPathTraversalFunction)
7458                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7459
7460/*
7461 * xmlXPathTraversalFunctionExt:
7462 * A traversal function enumerates nodes along an axis.
7463 * Initially it must be called with NULL, and it indicates
7464 * termination on the axis by returning NULL.
7465 * The context node of the traversal is specified via @contextNode.
7466 */
7467typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7468                    (xmlNodePtr cur, xmlNodePtr contextNode);
7469
7470/*
7471 * xmlXPathNodeSetMergeFunction:
7472 * Used for merging node sets in xmlXPathCollectAndTest().
7473 */
7474typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7475		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
7476
7477
7478/**
7479 * xmlXPathNextSelf:
7480 * @ctxt:  the XPath Parser context
7481 * @cur:  the current node in the traversal
7482 *
7483 * Traversal function for the "self" direction
7484 * The self axis contains just the context node itself
7485 *
7486 * Returns the next element following that axis
7487 */
7488xmlNodePtr
7489xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7490    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7491    if (cur == NULL)
7492        return(ctxt->context->node);
7493    return(NULL);
7494}
7495
7496/**
7497 * xmlXPathNextChild:
7498 * @ctxt:  the XPath Parser context
7499 * @cur:  the current node in the traversal
7500 *
7501 * Traversal function for the "child" direction
7502 * The child axis contains the children of the context node in document order.
7503 *
7504 * Returns the next element following that axis
7505 */
7506xmlNodePtr
7507xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7508    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7509    if (cur == NULL) {
7510	if (ctxt->context->node == NULL) return(NULL);
7511	switch (ctxt->context->node->type) {
7512            case XML_ELEMENT_NODE:
7513            case XML_TEXT_NODE:
7514            case XML_CDATA_SECTION_NODE:
7515            case XML_ENTITY_REF_NODE:
7516            case XML_ENTITY_NODE:
7517            case XML_PI_NODE:
7518            case XML_COMMENT_NODE:
7519            case XML_NOTATION_NODE:
7520            case XML_DTD_NODE:
7521		return(ctxt->context->node->children);
7522            case XML_DOCUMENT_NODE:
7523            case XML_DOCUMENT_TYPE_NODE:
7524            case XML_DOCUMENT_FRAG_NODE:
7525            case XML_HTML_DOCUMENT_NODE:
7526#ifdef LIBXML_DOCB_ENABLED
7527	    case XML_DOCB_DOCUMENT_NODE:
7528#endif
7529		return(((xmlDocPtr) ctxt->context->node)->children);
7530	    case XML_ELEMENT_DECL:
7531	    case XML_ATTRIBUTE_DECL:
7532	    case XML_ENTITY_DECL:
7533            case XML_ATTRIBUTE_NODE:
7534	    case XML_NAMESPACE_DECL:
7535	    case XML_XINCLUDE_START:
7536	    case XML_XINCLUDE_END:
7537		return(NULL);
7538	}
7539	return(NULL);
7540    }
7541    if ((cur->type == XML_DOCUMENT_NODE) ||
7542        (cur->type == XML_HTML_DOCUMENT_NODE))
7543	return(NULL);
7544    return(cur->next);
7545}
7546
7547/**
7548 * xmlXPathNextChildElement:
7549 * @ctxt:  the XPath Parser context
7550 * @cur:  the current node in the traversal
7551 *
7552 * Traversal function for the "child" direction and nodes of type element.
7553 * The child axis contains the children of the context node in document order.
7554 *
7555 * Returns the next element following that axis
7556 */
7557static xmlNodePtr
7558xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7559    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7560    if (cur == NULL) {
7561	cur = ctxt->context->node;
7562	if (cur == NULL) return(NULL);
7563	/*
7564	* Get the first element child.
7565	*/
7566	switch (cur->type) {
7567            case XML_ELEMENT_NODE:
7568	    case XML_DOCUMENT_FRAG_NODE:
7569	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7570            case XML_ENTITY_NODE:
7571		cur = cur->children;
7572		if (cur != NULL) {
7573		    if (cur->type == XML_ELEMENT_NODE)
7574			return(cur);
7575		    do {
7576			cur = cur->next;
7577		    } while ((cur != NULL) &&
7578			(cur->type != XML_ELEMENT_NODE));
7579		    return(cur);
7580		}
7581		return(NULL);
7582            case XML_DOCUMENT_NODE:
7583            case XML_HTML_DOCUMENT_NODE:
7584#ifdef LIBXML_DOCB_ENABLED
7585	    case XML_DOCB_DOCUMENT_NODE:
7586#endif
7587		return(xmlDocGetRootElement((xmlDocPtr) cur));
7588	    default:
7589		return(NULL);
7590	}
7591	return(NULL);
7592    }
7593    /*
7594    * Get the next sibling element node.
7595    */
7596    switch (cur->type) {
7597	case XML_ELEMENT_NODE:
7598	case XML_TEXT_NODE:
7599	case XML_ENTITY_REF_NODE:
7600	case XML_ENTITY_NODE:
7601	case XML_CDATA_SECTION_NODE:
7602	case XML_PI_NODE:
7603	case XML_COMMENT_NODE:
7604	case XML_XINCLUDE_END:
7605	    break;
7606	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7607	default:
7608	    return(NULL);
7609    }
7610    if (cur->next != NULL) {
7611	if (cur->next->type == XML_ELEMENT_NODE)
7612	    return(cur->next);
7613	cur = cur->next;
7614	do {
7615	    cur = cur->next;
7616	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7617	return(cur);
7618    }
7619    return(NULL);
7620}
7621
7622/**
7623 * xmlXPathNextDescendantOrSelfElemParent:
7624 * @ctxt:  the XPath Parser context
7625 * @cur:  the current node in the traversal
7626 *
7627 * Traversal function for the "descendant-or-self" axis.
7628 * Additionally it returns only nodes which can be parents of
7629 * element nodes.
7630 *
7631 *
7632 * Returns the next element following that axis
7633 */
7634static xmlNodePtr
7635xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7636				       xmlNodePtr contextNode)
7637{
7638    if (cur == NULL) {
7639	if (contextNode == NULL)
7640	    return(NULL);
7641	switch (contextNode->type) {
7642	    case XML_ELEMENT_NODE:
7643	    case XML_XINCLUDE_START:
7644	    case XML_DOCUMENT_FRAG_NODE:
7645	    case XML_DOCUMENT_NODE:
7646#ifdef LIBXML_DOCB_ENABLED
7647	    case XML_DOCB_DOCUMENT_NODE:
7648#endif
7649	    case XML_HTML_DOCUMENT_NODE:
7650		return(contextNode);
7651	    default:
7652		return(NULL);
7653	}
7654	return(NULL);
7655    } else {
7656	xmlNodePtr start = cur;
7657
7658	while (cur != NULL) {
7659	    switch (cur->type) {
7660		case XML_ELEMENT_NODE:
7661		/* TODO: OK to have XInclude here? */
7662		case XML_XINCLUDE_START:
7663		case XML_DOCUMENT_FRAG_NODE:
7664		    if (cur != start)
7665			return(cur);
7666		    if (cur->children != NULL) {
7667			cur = cur->children;
7668			continue;
7669		    }
7670		    break;
7671#ifdef LIBXML_DOCB_ENABLED
7672		/* Not sure if we need those here. */
7673		case XML_DOCUMENT_NODE:
7674		case XML_DOCB_DOCUMENT_NODE:
7675#endif
7676		case XML_HTML_DOCUMENT_NODE:
7677		    if (cur != start)
7678			return(cur);
7679		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7680		default:
7681		    break;
7682	    }
7683
7684next_sibling:
7685	    if ((cur == NULL) || (cur == contextNode))
7686		return(NULL);
7687	    if (cur->next != NULL) {
7688		cur = cur->next;
7689	    } else {
7690		cur = cur->parent;
7691		goto next_sibling;
7692	    }
7693	}
7694    }
7695    return(NULL);
7696}
7697
7698/**
7699 * xmlXPathNextDescendant:
7700 * @ctxt:  the XPath Parser context
7701 * @cur:  the current node in the traversal
7702 *
7703 * Traversal function for the "descendant" direction
7704 * the descendant axis contains the descendants of the context node in document
7705 * order; a descendant is a child or a child of a child and so on.
7706 *
7707 * Returns the next element following that axis
7708 */
7709xmlNodePtr
7710xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7711    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7712    if (cur == NULL) {
7713	if (ctxt->context->node == NULL)
7714	    return(NULL);
7715	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7716	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7717	    return(NULL);
7718
7719        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7720	    return(ctxt->context->doc->children);
7721        return(ctxt->context->node->children);
7722    }
7723
7724    if (cur->children != NULL) {
7725	/*
7726	 * Do not descend on entities declarations
7727	 */
7728    	if (cur->children->type != XML_ENTITY_DECL) {
7729	    cur = cur->children;
7730	    /*
7731	     * Skip DTDs
7732	     */
7733	    if (cur->type != XML_DTD_NODE)
7734		return(cur);
7735	}
7736    }
7737
7738    if (cur == ctxt->context->node) return(NULL);
7739
7740    while (cur->next != NULL) {
7741	cur = cur->next;
7742	if ((cur->type != XML_ENTITY_DECL) &&
7743	    (cur->type != XML_DTD_NODE))
7744	    return(cur);
7745    }
7746
7747    do {
7748        cur = cur->parent;
7749	if (cur == NULL) break;
7750	if (cur == ctxt->context->node) return(NULL);
7751	if (cur->next != NULL) {
7752	    cur = cur->next;
7753	    return(cur);
7754	}
7755    } while (cur != NULL);
7756    return(cur);
7757}
7758
7759/**
7760 * xmlXPathNextDescendantOrSelf:
7761 * @ctxt:  the XPath Parser context
7762 * @cur:  the current node in the traversal
7763 *
7764 * Traversal function for the "descendant-or-self" direction
7765 * the descendant-or-self axis contains the context node and the descendants
7766 * of the context node in document order; thus the context node is the first
7767 * node on the axis, and the first child of the context node is the second node
7768 * on the axis
7769 *
7770 * Returns the next element following that axis
7771 */
7772xmlNodePtr
7773xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7774    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7775    if (cur == NULL) {
7776	if (ctxt->context->node == NULL)
7777	    return(NULL);
7778	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7779	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7780	    return(NULL);
7781        return(ctxt->context->node);
7782    }
7783
7784    return(xmlXPathNextDescendant(ctxt, cur));
7785}
7786
7787/**
7788 * xmlXPathNextParent:
7789 * @ctxt:  the XPath Parser context
7790 * @cur:  the current node in the traversal
7791 *
7792 * Traversal function for the "parent" direction
7793 * The parent axis contains the parent of the context node, if there is one.
7794 *
7795 * Returns the next element following that axis
7796 */
7797xmlNodePtr
7798xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7799    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7800    /*
7801     * the parent of an attribute or namespace node is the element
7802     * to which the attribute or namespace node is attached
7803     * Namespace handling !!!
7804     */
7805    if (cur == NULL) {
7806	if (ctxt->context->node == NULL) return(NULL);
7807	switch (ctxt->context->node->type) {
7808            case XML_ELEMENT_NODE:
7809            case XML_TEXT_NODE:
7810            case XML_CDATA_SECTION_NODE:
7811            case XML_ENTITY_REF_NODE:
7812            case XML_ENTITY_NODE:
7813            case XML_PI_NODE:
7814            case XML_COMMENT_NODE:
7815            case XML_NOTATION_NODE:
7816            case XML_DTD_NODE:
7817	    case XML_ELEMENT_DECL:
7818	    case XML_ATTRIBUTE_DECL:
7819	    case XML_XINCLUDE_START:
7820	    case XML_XINCLUDE_END:
7821	    case XML_ENTITY_DECL:
7822		if (ctxt->context->node->parent == NULL)
7823		    return((xmlNodePtr) ctxt->context->doc);
7824		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7825		    ((ctxt->context->node->parent->name[0] == ' ') ||
7826		     (xmlStrEqual(ctxt->context->node->parent->name,
7827				 BAD_CAST "fake node libxslt"))))
7828		    return(NULL);
7829		return(ctxt->context->node->parent);
7830            case XML_ATTRIBUTE_NODE: {
7831		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7832
7833		return(att->parent);
7834	    }
7835            case XML_DOCUMENT_NODE:
7836            case XML_DOCUMENT_TYPE_NODE:
7837            case XML_DOCUMENT_FRAG_NODE:
7838            case XML_HTML_DOCUMENT_NODE:
7839#ifdef LIBXML_DOCB_ENABLED
7840	    case XML_DOCB_DOCUMENT_NODE:
7841#endif
7842                return(NULL);
7843	    case XML_NAMESPACE_DECL: {
7844		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7845
7846		if ((ns->next != NULL) &&
7847		    (ns->next->type != XML_NAMESPACE_DECL))
7848		    return((xmlNodePtr) ns->next);
7849                return(NULL);
7850	    }
7851	}
7852    }
7853    return(NULL);
7854}
7855
7856/**
7857 * xmlXPathNextAncestor:
7858 * @ctxt:  the XPath Parser context
7859 * @cur:  the current node in the traversal
7860 *
7861 * Traversal function for the "ancestor" direction
7862 * the ancestor axis contains the ancestors of the context node; the ancestors
7863 * of the context node consist of the parent of context node and the parent's
7864 * parent and so on; the nodes are ordered in reverse document order; thus the
7865 * parent is the first node on the axis, and the parent's parent is the second
7866 * node on the axis
7867 *
7868 * Returns the next element following that axis
7869 */
7870xmlNodePtr
7871xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7872    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7873    /*
7874     * the parent of an attribute or namespace node is the element
7875     * to which the attribute or namespace node is attached
7876     * !!!!!!!!!!!!!
7877     */
7878    if (cur == NULL) {
7879	if (ctxt->context->node == NULL) return(NULL);
7880	switch (ctxt->context->node->type) {
7881            case XML_ELEMENT_NODE:
7882            case XML_TEXT_NODE:
7883            case XML_CDATA_SECTION_NODE:
7884            case XML_ENTITY_REF_NODE:
7885            case XML_ENTITY_NODE:
7886            case XML_PI_NODE:
7887            case XML_COMMENT_NODE:
7888	    case XML_DTD_NODE:
7889	    case XML_ELEMENT_DECL:
7890	    case XML_ATTRIBUTE_DECL:
7891	    case XML_ENTITY_DECL:
7892            case XML_NOTATION_NODE:
7893	    case XML_XINCLUDE_START:
7894	    case XML_XINCLUDE_END:
7895		if (ctxt->context->node->parent == NULL)
7896		    return((xmlNodePtr) ctxt->context->doc);
7897		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7898		    ((ctxt->context->node->parent->name[0] == ' ') ||
7899		     (xmlStrEqual(ctxt->context->node->parent->name,
7900				 BAD_CAST "fake node libxslt"))))
7901		    return(NULL);
7902		return(ctxt->context->node->parent);
7903            case XML_ATTRIBUTE_NODE: {
7904		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7905
7906		return(tmp->parent);
7907	    }
7908            case XML_DOCUMENT_NODE:
7909            case XML_DOCUMENT_TYPE_NODE:
7910            case XML_DOCUMENT_FRAG_NODE:
7911            case XML_HTML_DOCUMENT_NODE:
7912#ifdef LIBXML_DOCB_ENABLED
7913	    case XML_DOCB_DOCUMENT_NODE:
7914#endif
7915                return(NULL);
7916	    case XML_NAMESPACE_DECL: {
7917		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7918
7919		if ((ns->next != NULL) &&
7920		    (ns->next->type != XML_NAMESPACE_DECL))
7921		    return((xmlNodePtr) ns->next);
7922		/* Bad, how did that namespace end up here ? */
7923                return(NULL);
7924	    }
7925	}
7926	return(NULL);
7927    }
7928    if (cur == ctxt->context->doc->children)
7929	return((xmlNodePtr) ctxt->context->doc);
7930    if (cur == (xmlNodePtr) ctxt->context->doc)
7931	return(NULL);
7932    switch (cur->type) {
7933	case XML_ELEMENT_NODE:
7934	case XML_TEXT_NODE:
7935	case XML_CDATA_SECTION_NODE:
7936	case XML_ENTITY_REF_NODE:
7937	case XML_ENTITY_NODE:
7938	case XML_PI_NODE:
7939	case XML_COMMENT_NODE:
7940	case XML_NOTATION_NODE:
7941	case XML_DTD_NODE:
7942        case XML_ELEMENT_DECL:
7943        case XML_ATTRIBUTE_DECL:
7944        case XML_ENTITY_DECL:
7945	case XML_XINCLUDE_START:
7946	case XML_XINCLUDE_END:
7947	    if (cur->parent == NULL)
7948		return(NULL);
7949	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
7950		((cur->parent->name[0] == ' ') ||
7951		 (xmlStrEqual(cur->parent->name,
7952			      BAD_CAST "fake node libxslt"))))
7953		return(NULL);
7954	    return(cur->parent);
7955	case XML_ATTRIBUTE_NODE: {
7956	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7957
7958	    return(att->parent);
7959	}
7960	case XML_NAMESPACE_DECL: {
7961	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7962
7963	    if ((ns->next != NULL) &&
7964	        (ns->next->type != XML_NAMESPACE_DECL))
7965	        return((xmlNodePtr) ns->next);
7966	    /* Bad, how did that namespace end up here ? */
7967            return(NULL);
7968	}
7969	case XML_DOCUMENT_NODE:
7970	case XML_DOCUMENT_TYPE_NODE:
7971	case XML_DOCUMENT_FRAG_NODE:
7972	case XML_HTML_DOCUMENT_NODE:
7973#ifdef LIBXML_DOCB_ENABLED
7974	case XML_DOCB_DOCUMENT_NODE:
7975#endif
7976	    return(NULL);
7977    }
7978    return(NULL);
7979}
7980
7981/**
7982 * xmlXPathNextAncestorOrSelf:
7983 * @ctxt:  the XPath Parser context
7984 * @cur:  the current node in the traversal
7985 *
7986 * Traversal function for the "ancestor-or-self" direction
7987 * he ancestor-or-self axis contains the context node and ancestors of
7988 * the context node in reverse document order; thus the context node is
7989 * the first node on the axis, and the context node's parent the second;
7990 * parent here is defined the same as with the parent axis.
7991 *
7992 * Returns the next element following that axis
7993 */
7994xmlNodePtr
7995xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7996    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7997    if (cur == NULL)
7998        return(ctxt->context->node);
7999    return(xmlXPathNextAncestor(ctxt, cur));
8000}
8001
8002/**
8003 * xmlXPathNextFollowingSibling:
8004 * @ctxt:  the XPath Parser context
8005 * @cur:  the current node in the traversal
8006 *
8007 * Traversal function for the "following-sibling" direction
8008 * The following-sibling axis contains the following siblings of the context
8009 * node in document order.
8010 *
8011 * Returns the next element following that axis
8012 */
8013xmlNodePtr
8014xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8015    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8016    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8017	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8018	return(NULL);
8019    if (cur == (xmlNodePtr) ctxt->context->doc)
8020        return(NULL);
8021    if (cur == NULL)
8022        return(ctxt->context->node->next);
8023    return(cur->next);
8024}
8025
8026/**
8027 * xmlXPathNextPrecedingSibling:
8028 * @ctxt:  the XPath Parser context
8029 * @cur:  the current node in the traversal
8030 *
8031 * Traversal function for the "preceding-sibling" direction
8032 * The preceding-sibling axis contains the preceding siblings of the context
8033 * node in reverse document order; the first preceding sibling is first on the
8034 * axis; the sibling preceding that node is the second on the axis and so on.
8035 *
8036 * Returns the next element following that axis
8037 */
8038xmlNodePtr
8039xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8040    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8041    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8042	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8043	return(NULL);
8044    if (cur == (xmlNodePtr) ctxt->context->doc)
8045        return(NULL);
8046    if (cur == NULL)
8047        return(ctxt->context->node->prev);
8048    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8049	cur = cur->prev;
8050	if (cur == NULL)
8051	    return(ctxt->context->node->prev);
8052    }
8053    return(cur->prev);
8054}
8055
8056/**
8057 * xmlXPathNextFollowing:
8058 * @ctxt:  the XPath Parser context
8059 * @cur:  the current node in the traversal
8060 *
8061 * Traversal function for the "following" direction
8062 * The following axis contains all nodes in the same document as the context
8063 * node that are after the context node in document order, excluding any
8064 * descendants and excluding attribute nodes and namespace nodes; the nodes
8065 * are ordered in document order
8066 *
8067 * Returns the next element following that axis
8068 */
8069xmlNodePtr
8070xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8071    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8072    if (cur != NULL && cur->children != NULL)
8073        return cur->children ;
8074    if (cur == NULL) cur = ctxt->context->node;
8075    if (cur == NULL) return(NULL) ; /* ERROR */
8076    if (cur->next != NULL) return(cur->next) ;
8077    do {
8078        cur = cur->parent;
8079        if (cur == NULL) break;
8080        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8081        if (cur->next != NULL) return(cur->next);
8082    } while (cur != NULL);
8083    return(cur);
8084}
8085
8086/*
8087 * xmlXPathIsAncestor:
8088 * @ancestor:  the ancestor node
8089 * @node:  the current node
8090 *
8091 * Check that @ancestor is a @node's ancestor
8092 *
8093 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8094 */
8095static int
8096xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8097    if ((ancestor == NULL) || (node == NULL)) return(0);
8098    /* nodes need to be in the same document */
8099    if (ancestor->doc != node->doc) return(0);
8100    /* avoid searching if ancestor or node is the root node */
8101    if (ancestor == (xmlNodePtr) node->doc) return(1);
8102    if (node == (xmlNodePtr) ancestor->doc) return(0);
8103    while (node->parent != NULL) {
8104        if (node->parent == ancestor)
8105            return(1);
8106	node = node->parent;
8107    }
8108    return(0);
8109}
8110
8111/**
8112 * xmlXPathNextPreceding:
8113 * @ctxt:  the XPath Parser context
8114 * @cur:  the current node in the traversal
8115 *
8116 * Traversal function for the "preceding" direction
8117 * the preceding axis contains all nodes in the same document as the context
8118 * node that are before the context node in document order, excluding any
8119 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8120 * ordered in reverse document order
8121 *
8122 * Returns the next element following that axis
8123 */
8124xmlNodePtr
8125xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8126{
8127    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8128    if (cur == NULL)
8129        cur = ctxt->context->node;
8130    if (cur == NULL)
8131	return (NULL);
8132    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8133	cur = cur->prev;
8134    do {
8135        if (cur->prev != NULL) {
8136            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8137            return (cur);
8138        }
8139
8140        cur = cur->parent;
8141        if (cur == NULL)
8142            return (NULL);
8143        if (cur == ctxt->context->doc->children)
8144            return (NULL);
8145    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8146    return (cur);
8147}
8148
8149/**
8150 * xmlXPathNextPrecedingInternal:
8151 * @ctxt:  the XPath Parser context
8152 * @cur:  the current node in the traversal
8153 *
8154 * Traversal function for the "preceding" direction
8155 * the preceding axis contains all nodes in the same document as the context
8156 * node that are before the context node in document order, excluding any
8157 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8158 * ordered in reverse document order
8159 * This is a faster implementation but internal only since it requires a
8160 * state kept in the parser context: ctxt->ancestor.
8161 *
8162 * Returns the next element following that axis
8163 */
8164static xmlNodePtr
8165xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8166                              xmlNodePtr cur)
8167{
8168    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8169    if (cur == NULL) {
8170        cur = ctxt->context->node;
8171        if (cur == NULL)
8172            return (NULL);
8173	if (cur->type == XML_NAMESPACE_DECL)
8174	    cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
8175        ctxt->ancestor = cur->parent;
8176    }
8177    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8178	cur = cur->prev;
8179    while (cur->prev == NULL) {
8180        cur = cur->parent;
8181        if (cur == NULL)
8182            return (NULL);
8183        if (cur == ctxt->context->doc->children)
8184            return (NULL);
8185        if (cur != ctxt->ancestor)
8186            return (cur);
8187        ctxt->ancestor = cur->parent;
8188    }
8189    cur = cur->prev;
8190    while (cur->last != NULL)
8191        cur = cur->last;
8192    return (cur);
8193}
8194
8195/**
8196 * xmlXPathNextNamespace:
8197 * @ctxt:  the XPath Parser context
8198 * @cur:  the current attribute in the traversal
8199 *
8200 * Traversal function for the "namespace" direction
8201 * the namespace axis contains the namespace nodes of the context node;
8202 * the order of nodes on this axis is implementation-defined; the axis will
8203 * be empty unless the context node is an element
8204 *
8205 * We keep the XML namespace node at the end of the list.
8206 *
8207 * Returns the next element following that axis
8208 */
8209xmlNodePtr
8210xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8211    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8212    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8213    if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8214        if (ctxt->context->tmpNsList != NULL)
8215	    xmlFree(ctxt->context->tmpNsList);
8216	ctxt->context->tmpNsList =
8217	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8218	ctxt->context->tmpNsNr = 0;
8219	if (ctxt->context->tmpNsList != NULL) {
8220	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8221		ctxt->context->tmpNsNr++;
8222	    }
8223	}
8224	return((xmlNodePtr) xmlXPathXMLNamespace);
8225    }
8226    if (ctxt->context->tmpNsNr > 0) {
8227	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8228    } else {
8229	if (ctxt->context->tmpNsList != NULL)
8230	    xmlFree(ctxt->context->tmpNsList);
8231	ctxt->context->tmpNsList = NULL;
8232	return(NULL);
8233    }
8234}
8235
8236/**
8237 * xmlXPathNextAttribute:
8238 * @ctxt:  the XPath Parser context
8239 * @cur:  the current attribute in the traversal
8240 *
8241 * Traversal function for the "attribute" direction
8242 * TODO: support DTD inherited default attributes
8243 *
8244 * Returns the next element following that axis
8245 */
8246xmlNodePtr
8247xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8248    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8249    if (ctxt->context->node == NULL)
8250	return(NULL);
8251    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8252	return(NULL);
8253    if (cur == NULL) {
8254        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8255	    return(NULL);
8256        return((xmlNodePtr)ctxt->context->node->properties);
8257    }
8258    return((xmlNodePtr)cur->next);
8259}
8260
8261/************************************************************************
8262 *									*
8263 *		NodeTest Functions					*
8264 *									*
8265 ************************************************************************/
8266
8267#define IS_FUNCTION			200
8268
8269
8270/************************************************************************
8271 *									*
8272 *		Implicit tree core function library			*
8273 *									*
8274 ************************************************************************/
8275
8276/**
8277 * xmlXPathRoot:
8278 * @ctxt:  the XPath Parser context
8279 *
8280 * Initialize the context to the root of the document
8281 */
8282void
8283xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8284    if ((ctxt == NULL) || (ctxt->context == NULL))
8285	return;
8286    ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8287    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8288	ctxt->context->node));
8289}
8290
8291/************************************************************************
8292 *									*
8293 *		The explicit core function library			*
8294 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8295 *									*
8296 ************************************************************************/
8297
8298
8299/**
8300 * xmlXPathLastFunction:
8301 * @ctxt:  the XPath Parser context
8302 * @nargs:  the number of arguments
8303 *
8304 * Implement the last() XPath function
8305 *    number last()
8306 * The last function returns the number of nodes in the context node list.
8307 */
8308void
8309xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8310    CHECK_ARITY(0);
8311    if (ctxt->context->contextSize >= 0) {
8312	valuePush(ctxt,
8313	    xmlXPathCacheNewFloat(ctxt->context,
8314		(double) ctxt->context->contextSize));
8315#ifdef DEBUG_EXPR
8316	xmlGenericError(xmlGenericErrorContext,
8317		"last() : %d\n", ctxt->context->contextSize);
8318#endif
8319    } else {
8320	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8321    }
8322}
8323
8324/**
8325 * xmlXPathPositionFunction:
8326 * @ctxt:  the XPath Parser context
8327 * @nargs:  the number of arguments
8328 *
8329 * Implement the position() XPath function
8330 *    number position()
8331 * The position function returns the position of the context node in the
8332 * context node list. The first position is 1, and so the last position
8333 * will be equal to last().
8334 */
8335void
8336xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8337    CHECK_ARITY(0);
8338    if (ctxt->context->proximityPosition >= 0) {
8339	valuePush(ctxt,
8340	      xmlXPathCacheNewFloat(ctxt->context,
8341		(double) ctxt->context->proximityPosition));
8342#ifdef DEBUG_EXPR
8343	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8344		ctxt->context->proximityPosition);
8345#endif
8346    } else {
8347	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8348    }
8349}
8350
8351/**
8352 * xmlXPathCountFunction:
8353 * @ctxt:  the XPath Parser context
8354 * @nargs:  the number of arguments
8355 *
8356 * Implement the count() XPath function
8357 *    number count(node-set)
8358 */
8359void
8360xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8361    xmlXPathObjectPtr cur;
8362
8363    CHECK_ARITY(1);
8364    if ((ctxt->value == NULL) ||
8365	((ctxt->value->type != XPATH_NODESET) &&
8366	 (ctxt->value->type != XPATH_XSLT_TREE)))
8367	XP_ERROR(XPATH_INVALID_TYPE);
8368    cur = valuePop(ctxt);
8369
8370    if ((cur == NULL) || (cur->nodesetval == NULL))
8371	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8372    else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8373	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8374	    (double) cur->nodesetval->nodeNr));
8375    } else {
8376	if ((cur->nodesetval->nodeNr != 1) ||
8377	    (cur->nodesetval->nodeTab == NULL)) {
8378	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8379	} else {
8380	    xmlNodePtr tmp;
8381	    int i = 0;
8382
8383	    tmp = cur->nodesetval->nodeTab[0];
8384	    if (tmp != NULL) {
8385		tmp = tmp->children;
8386		while (tmp != NULL) {
8387		    tmp = tmp->next;
8388		    i++;
8389		}
8390	    }
8391	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8392	}
8393    }
8394    xmlXPathReleaseObject(ctxt->context, cur);
8395}
8396
8397/**
8398 * xmlXPathGetElementsByIds:
8399 * @doc:  the document
8400 * @ids:  a whitespace separated list of IDs
8401 *
8402 * Selects elements by their unique ID.
8403 *
8404 * Returns a node-set of selected elements.
8405 */
8406static xmlNodeSetPtr
8407xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8408    xmlNodeSetPtr ret;
8409    const xmlChar *cur = ids;
8410    xmlChar *ID;
8411    xmlAttrPtr attr;
8412    xmlNodePtr elem = NULL;
8413
8414    if (ids == NULL) return(NULL);
8415
8416    ret = xmlXPathNodeSetCreate(NULL);
8417
8418    while (IS_BLANK_CH(*cur)) cur++;
8419    while (*cur != 0) {
8420	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8421	    cur++;
8422
8423        ID = xmlStrndup(ids, cur - ids);
8424	if (ID != NULL) {
8425	    /*
8426	     * We used to check the fact that the value passed
8427	     * was an NCName, but this generated much troubles for
8428	     * me and Aleksey Sanin, people blatantly violated that
8429	     * constaint, like Visa3D spec.
8430	     * if (xmlValidateNCName(ID, 1) == 0)
8431	     */
8432	    attr = xmlGetID(doc, ID);
8433	    if (attr != NULL) {
8434		if (attr->type == XML_ATTRIBUTE_NODE)
8435		    elem = attr->parent;
8436		else if (attr->type == XML_ELEMENT_NODE)
8437		    elem = (xmlNodePtr) attr;
8438		else
8439		    elem = NULL;
8440		if (elem != NULL)
8441		    xmlXPathNodeSetAdd(ret, elem);
8442	    }
8443	    xmlFree(ID);
8444	}
8445
8446	while (IS_BLANK_CH(*cur)) cur++;
8447	ids = cur;
8448    }
8449    return(ret);
8450}
8451
8452/**
8453 * xmlXPathIdFunction:
8454 * @ctxt:  the XPath Parser context
8455 * @nargs:  the number of arguments
8456 *
8457 * Implement the id() XPath function
8458 *    node-set id(object)
8459 * The id function selects elements by their unique ID
8460 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8461 * then the result is the union of the result of applying id to the
8462 * string value of each of the nodes in the argument node-set. When the
8463 * argument to id is of any other type, the argument is converted to a
8464 * string as if by a call to the string function; the string is split
8465 * into a whitespace-separated list of tokens (whitespace is any sequence
8466 * of characters matching the production S); the result is a node-set
8467 * containing the elements in the same document as the context node that
8468 * have a unique ID equal to any of the tokens in the list.
8469 */
8470void
8471xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8472    xmlChar *tokens;
8473    xmlNodeSetPtr ret;
8474    xmlXPathObjectPtr obj;
8475
8476    CHECK_ARITY(1);
8477    obj = valuePop(ctxt);
8478    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8479    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8480	xmlNodeSetPtr ns;
8481	int i;
8482
8483	ret = xmlXPathNodeSetCreate(NULL);
8484
8485	if (obj->nodesetval != NULL) {
8486	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8487		tokens =
8488		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8489		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8490		ret = xmlXPathNodeSetMerge(ret, ns);
8491		xmlXPathFreeNodeSet(ns);
8492		if (tokens != NULL)
8493		    xmlFree(tokens);
8494	    }
8495	}
8496	xmlXPathReleaseObject(ctxt->context, obj);
8497	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8498	return;
8499    }
8500    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8501    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8502    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8503    xmlXPathReleaseObject(ctxt->context, obj);
8504    return;
8505}
8506
8507/**
8508 * xmlXPathLocalNameFunction:
8509 * @ctxt:  the XPath Parser context
8510 * @nargs:  the number of arguments
8511 *
8512 * Implement the local-name() XPath function
8513 *    string local-name(node-set?)
8514 * The local-name function returns a string containing the local part
8515 * of the name of the node in the argument node-set that is first in
8516 * document order. If the node-set is empty or the first node has no
8517 * name, an empty string is returned. If the argument is omitted it
8518 * defaults to the context node.
8519 */
8520void
8521xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8522    xmlXPathObjectPtr cur;
8523
8524    if (ctxt == NULL) return;
8525
8526    if (nargs == 0) {
8527	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8528	    ctxt->context->node));
8529	nargs = 1;
8530    }
8531
8532    CHECK_ARITY(1);
8533    if ((ctxt->value == NULL) ||
8534	((ctxt->value->type != XPATH_NODESET) &&
8535	 (ctxt->value->type != XPATH_XSLT_TREE)))
8536	XP_ERROR(XPATH_INVALID_TYPE);
8537    cur = valuePop(ctxt);
8538
8539    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8540	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8541    } else {
8542	int i = 0; /* Should be first in document order !!!!! */
8543	switch (cur->nodesetval->nodeTab[i]->type) {
8544	case XML_ELEMENT_NODE:
8545	case XML_ATTRIBUTE_NODE:
8546	case XML_PI_NODE:
8547	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8548		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8549	    else
8550		valuePush(ctxt,
8551		      xmlXPathCacheNewString(ctxt->context,
8552			cur->nodesetval->nodeTab[i]->name));
8553	    break;
8554	case XML_NAMESPACE_DECL:
8555	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8556			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8557	    break;
8558	default:
8559	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8560	}
8561    }
8562    xmlXPathReleaseObject(ctxt->context, cur);
8563}
8564
8565/**
8566 * xmlXPathNamespaceURIFunction:
8567 * @ctxt:  the XPath Parser context
8568 * @nargs:  the number of arguments
8569 *
8570 * Implement the namespace-uri() XPath function
8571 *    string namespace-uri(node-set?)
8572 * The namespace-uri function returns a string containing the
8573 * namespace URI of the expanded name of the node in the argument
8574 * node-set that is first in document order. If the node-set is empty,
8575 * the first node has no name, or the expanded name has no namespace
8576 * URI, an empty string is returned. If the argument is omitted it
8577 * defaults to the context node.
8578 */
8579void
8580xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8581    xmlXPathObjectPtr cur;
8582
8583    if (ctxt == NULL) return;
8584
8585    if (nargs == 0) {
8586	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8587	    ctxt->context->node));
8588	nargs = 1;
8589    }
8590    CHECK_ARITY(1);
8591    if ((ctxt->value == NULL) ||
8592	((ctxt->value->type != XPATH_NODESET) &&
8593	 (ctxt->value->type != XPATH_XSLT_TREE)))
8594	XP_ERROR(XPATH_INVALID_TYPE);
8595    cur = valuePop(ctxt);
8596
8597    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8598	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8599    } else {
8600	int i = 0; /* Should be first in document order !!!!! */
8601	switch (cur->nodesetval->nodeTab[i]->type) {
8602	case XML_ELEMENT_NODE:
8603	case XML_ATTRIBUTE_NODE:
8604	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8605		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8606	    else
8607		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8608			  cur->nodesetval->nodeTab[i]->ns->href));
8609	    break;
8610	default:
8611	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8612	}
8613    }
8614    xmlXPathReleaseObject(ctxt->context, cur);
8615}
8616
8617/**
8618 * xmlXPathNameFunction:
8619 * @ctxt:  the XPath Parser context
8620 * @nargs:  the number of arguments
8621 *
8622 * Implement the name() XPath function
8623 *    string name(node-set?)
8624 * The name function returns a string containing a QName representing
8625 * the name of the node in the argument node-set that is first in document
8626 * order. The QName must represent the name with respect to the namespace
8627 * declarations in effect on the node whose name is being represented.
8628 * Typically, this will be the form in which the name occurred in the XML
8629 * source. This need not be the case if there are namespace declarations
8630 * in effect on the node that associate multiple prefixes with the same
8631 * namespace. However, an implementation may include information about
8632 * the original prefix in its representation of nodes; in this case, an
8633 * implementation can ensure that the returned string is always the same
8634 * as the QName used in the XML source. If the argument it omitted it
8635 * defaults to the context node.
8636 * Libxml keep the original prefix so the "real qualified name" used is
8637 * returned.
8638 */
8639static void
8640xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8641{
8642    xmlXPathObjectPtr cur;
8643
8644    if (nargs == 0) {
8645	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8646	    ctxt->context->node));
8647        nargs = 1;
8648    }
8649
8650    CHECK_ARITY(1);
8651    if ((ctxt->value == NULL) ||
8652        ((ctxt->value->type != XPATH_NODESET) &&
8653         (ctxt->value->type != XPATH_XSLT_TREE)))
8654        XP_ERROR(XPATH_INVALID_TYPE);
8655    cur = valuePop(ctxt);
8656
8657    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8658        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8659    } else {
8660        int i = 0;              /* Should be first in document order !!!!! */
8661
8662        switch (cur->nodesetval->nodeTab[i]->type) {
8663            case XML_ELEMENT_NODE:
8664            case XML_ATTRIBUTE_NODE:
8665		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8666		    valuePush(ctxt,
8667			xmlXPathCacheNewCString(ctxt->context, ""));
8668		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8669                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8670		    valuePush(ctxt,
8671		        xmlXPathCacheNewString(ctxt->context,
8672			    cur->nodesetval->nodeTab[i]->name));
8673		} else {
8674		    xmlChar *fullname;
8675
8676		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8677				     cur->nodesetval->nodeTab[i]->ns->prefix,
8678				     NULL, 0);
8679		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8680			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8681		    if (fullname == NULL) {
8682			XP_ERROR(XPATH_MEMORY_ERROR);
8683		    }
8684		    valuePush(ctxt, xmlXPathCacheWrapString(
8685			ctxt->context, fullname));
8686                }
8687                break;
8688            default:
8689		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8690		    cur->nodesetval->nodeTab[i]));
8691                xmlXPathLocalNameFunction(ctxt, 1);
8692        }
8693    }
8694    xmlXPathReleaseObject(ctxt->context, cur);
8695}
8696
8697
8698/**
8699 * xmlXPathStringFunction:
8700 * @ctxt:  the XPath Parser context
8701 * @nargs:  the number of arguments
8702 *
8703 * Implement the string() XPath function
8704 *    string string(object?)
8705 * The string function converts an object to a string as follows:
8706 *    - A node-set is converted to a string by returning the value of
8707 *      the node in the node-set that is first in document order.
8708 *      If the node-set is empty, an empty string is returned.
8709 *    - A number is converted to a string as follows
8710 *      + NaN is converted to the string NaN
8711 *      + positive zero is converted to the string 0
8712 *      + negative zero is converted to the string 0
8713 *      + positive infinity is converted to the string Infinity
8714 *      + negative infinity is converted to the string -Infinity
8715 *      + if the number is an integer, the number is represented in
8716 *        decimal form as a Number with no decimal point and no leading
8717 *        zeros, preceded by a minus sign (-) if the number is negative
8718 *      + otherwise, the number is represented in decimal form as a
8719 *        Number including a decimal point with at least one digit
8720 *        before the decimal point and at least one digit after the
8721 *        decimal point, preceded by a minus sign (-) if the number
8722 *        is negative; there must be no leading zeros before the decimal
8723 *        point apart possibly from the one required digit immediately
8724 *        before the decimal point; beyond the one required digit
8725 *        after the decimal point there must be as many, but only as
8726 *        many, more digits as are needed to uniquely distinguish the
8727 *        number from all other IEEE 754 numeric values.
8728 *    - The boolean false value is converted to the string false.
8729 *      The boolean true value is converted to the string true.
8730 *
8731 * If the argument is omitted, it defaults to a node-set with the
8732 * context node as its only member.
8733 */
8734void
8735xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8736    xmlXPathObjectPtr cur;
8737
8738    if (ctxt == NULL) return;
8739    if (nargs == 0) {
8740    valuePush(ctxt,
8741	xmlXPathCacheWrapString(ctxt->context,
8742	    xmlXPathCastNodeToString(ctxt->context->node)));
8743	return;
8744    }
8745
8746    CHECK_ARITY(1);
8747    cur = valuePop(ctxt);
8748    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8749    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8750}
8751
8752/**
8753 * xmlXPathStringLengthFunction:
8754 * @ctxt:  the XPath Parser context
8755 * @nargs:  the number of arguments
8756 *
8757 * Implement the string-length() XPath function
8758 *    number string-length(string?)
8759 * The string-length returns the number of characters in the string
8760 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8761 * the context node converted to a string, in other words the value
8762 * of the context node.
8763 */
8764void
8765xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8766    xmlXPathObjectPtr cur;
8767
8768    if (nargs == 0) {
8769        if ((ctxt == NULL) || (ctxt->context == NULL))
8770	    return;
8771	if (ctxt->context->node == NULL) {
8772	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8773	} else {
8774	    xmlChar *content;
8775
8776	    content = xmlXPathCastNodeToString(ctxt->context->node);
8777	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8778		xmlUTF8Strlen(content)));
8779	    xmlFree(content);
8780	}
8781	return;
8782    }
8783    CHECK_ARITY(1);
8784    CAST_TO_STRING;
8785    CHECK_TYPE(XPATH_STRING);
8786    cur = valuePop(ctxt);
8787    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8788	xmlUTF8Strlen(cur->stringval)));
8789    xmlXPathReleaseObject(ctxt->context, cur);
8790}
8791
8792/**
8793 * xmlXPathConcatFunction:
8794 * @ctxt:  the XPath Parser context
8795 * @nargs:  the number of arguments
8796 *
8797 * Implement the concat() XPath function
8798 *    string concat(string, string, string*)
8799 * The concat function returns the concatenation of its arguments.
8800 */
8801void
8802xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8803    xmlXPathObjectPtr cur, newobj;
8804    xmlChar *tmp;
8805
8806    if (ctxt == NULL) return;
8807    if (nargs < 2) {
8808	CHECK_ARITY(2);
8809    }
8810
8811    CAST_TO_STRING;
8812    cur = valuePop(ctxt);
8813    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8814	xmlXPathReleaseObject(ctxt->context, cur);
8815	return;
8816    }
8817    nargs--;
8818
8819    while (nargs > 0) {
8820	CAST_TO_STRING;
8821	newobj = valuePop(ctxt);
8822	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8823	    xmlXPathReleaseObject(ctxt->context, newobj);
8824	    xmlXPathReleaseObject(ctxt->context, cur);
8825	    XP_ERROR(XPATH_INVALID_TYPE);
8826	}
8827	tmp = xmlStrcat(newobj->stringval, cur->stringval);
8828	newobj->stringval = cur->stringval;
8829	cur->stringval = tmp;
8830	xmlXPathReleaseObject(ctxt->context, newobj);
8831	nargs--;
8832    }
8833    valuePush(ctxt, cur);
8834}
8835
8836/**
8837 * xmlXPathContainsFunction:
8838 * @ctxt:  the XPath Parser context
8839 * @nargs:  the number of arguments
8840 *
8841 * Implement the contains() XPath function
8842 *    boolean contains(string, string)
8843 * The contains function returns true if the first argument string
8844 * contains the second argument string, and otherwise returns false.
8845 */
8846void
8847xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8848    xmlXPathObjectPtr hay, needle;
8849
8850    CHECK_ARITY(2);
8851    CAST_TO_STRING;
8852    CHECK_TYPE(XPATH_STRING);
8853    needle = valuePop(ctxt);
8854    CAST_TO_STRING;
8855    hay = valuePop(ctxt);
8856
8857    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8858	xmlXPathReleaseObject(ctxt->context, hay);
8859	xmlXPathReleaseObject(ctxt->context, needle);
8860	XP_ERROR(XPATH_INVALID_TYPE);
8861    }
8862    if (xmlStrstr(hay->stringval, needle->stringval))
8863	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8864    else
8865	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8866    xmlXPathReleaseObject(ctxt->context, hay);
8867    xmlXPathReleaseObject(ctxt->context, needle);
8868}
8869
8870/**
8871 * xmlXPathStartsWithFunction:
8872 * @ctxt:  the XPath Parser context
8873 * @nargs:  the number of arguments
8874 *
8875 * Implement the starts-with() XPath function
8876 *    boolean starts-with(string, string)
8877 * The starts-with function returns true if the first argument string
8878 * starts with the second argument string, and otherwise returns false.
8879 */
8880void
8881xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8882    xmlXPathObjectPtr hay, needle;
8883    int n;
8884
8885    CHECK_ARITY(2);
8886    CAST_TO_STRING;
8887    CHECK_TYPE(XPATH_STRING);
8888    needle = valuePop(ctxt);
8889    CAST_TO_STRING;
8890    hay = valuePop(ctxt);
8891
8892    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8893	xmlXPathReleaseObject(ctxt->context, hay);
8894	xmlXPathReleaseObject(ctxt->context, needle);
8895	XP_ERROR(XPATH_INVALID_TYPE);
8896    }
8897    n = xmlStrlen(needle->stringval);
8898    if (xmlStrncmp(hay->stringval, needle->stringval, n))
8899        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8900    else
8901        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8902    xmlXPathReleaseObject(ctxt->context, hay);
8903    xmlXPathReleaseObject(ctxt->context, needle);
8904}
8905
8906/**
8907 * xmlXPathSubstringFunction:
8908 * @ctxt:  the XPath Parser context
8909 * @nargs:  the number of arguments
8910 *
8911 * Implement the substring() XPath function
8912 *    string substring(string, number, number?)
8913 * The substring function returns the substring of the first argument
8914 * starting at the position specified in the second argument with
8915 * length specified in the third argument. For example,
8916 * substring("12345",2,3) returns "234". If the third argument is not
8917 * specified, it returns the substring starting at the position specified
8918 * in the second argument and continuing to the end of the string. For
8919 * example, substring("12345",2) returns "2345".  More precisely, each
8920 * character in the string (see [3.6 Strings]) is considered to have a
8921 * numeric position: the position of the first character is 1, the position
8922 * of the second character is 2 and so on. The returned substring contains
8923 * those characters for which the position of the character is greater than
8924 * or equal to the second argument and, if the third argument is specified,
8925 * less than the sum of the second and third arguments; the comparisons
8926 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8927 *  - substring("12345", 1.5, 2.6) returns "234"
8928 *  - substring("12345", 0, 3) returns "12"
8929 *  - substring("12345", 0 div 0, 3) returns ""
8930 *  - substring("12345", 1, 0 div 0) returns ""
8931 *  - substring("12345", -42, 1 div 0) returns "12345"
8932 *  - substring("12345", -1 div 0, 1 div 0) returns ""
8933 */
8934void
8935xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8936    xmlXPathObjectPtr str, start, len;
8937    double le=0, in;
8938    int i, l, m;
8939    xmlChar *ret;
8940
8941    if (nargs < 2) {
8942	CHECK_ARITY(2);
8943    }
8944    if (nargs > 3) {
8945	CHECK_ARITY(3);
8946    }
8947    /*
8948     * take care of possible last (position) argument
8949    */
8950    if (nargs == 3) {
8951	CAST_TO_NUMBER;
8952	CHECK_TYPE(XPATH_NUMBER);
8953	len = valuePop(ctxt);
8954	le = len->floatval;
8955	xmlXPathReleaseObject(ctxt->context, len);
8956    }
8957
8958    CAST_TO_NUMBER;
8959    CHECK_TYPE(XPATH_NUMBER);
8960    start = valuePop(ctxt);
8961    in = start->floatval;
8962    xmlXPathReleaseObject(ctxt->context, start);
8963    CAST_TO_STRING;
8964    CHECK_TYPE(XPATH_STRING);
8965    str = valuePop(ctxt);
8966    m = xmlUTF8Strlen((const unsigned char *)str->stringval);
8967
8968    /*
8969     * If last pos not present, calculate last position
8970    */
8971    if (nargs != 3) {
8972	le = (double)m;
8973	if (in < 1.0)
8974	    in = 1.0;
8975    }
8976
8977    /* Need to check for the special cases where either
8978     * the index is NaN, the length is NaN, or both
8979     * arguments are infinity (relying on Inf + -Inf = NaN)
8980     */
8981    if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
8982        /*
8983         * To meet the requirements of the spec, the arguments
8984	 * must be converted to integer format before
8985	 * initial index calculations are done
8986         *
8987         * First we go to integer form, rounding up
8988	 * and checking for special cases
8989         */
8990        i = (int) in;
8991        if (((double)i)+0.5 <= in) i++;
8992
8993	if (xmlXPathIsInf(le) == 1) {
8994	    l = m;
8995	    if (i < 1)
8996		i = 1;
8997	}
8998	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
8999	    l = 0;
9000	else {
9001	    l = (int) le;
9002	    if (((double)l)+0.5 <= le) l++;
9003	}
9004
9005	/* Now we normalize inidices */
9006        i -= 1;
9007        l += i;
9008        if (i < 0)
9009            i = 0;
9010        if (l > m)
9011            l = m;
9012
9013        /* number of chars to copy */
9014        l -= i;
9015
9016        ret = xmlUTF8Strsub(str->stringval, i, l);
9017    }
9018    else {
9019        ret = NULL;
9020    }
9021    if (ret == NULL)
9022	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9023    else {
9024	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9025	xmlFree(ret);
9026    }
9027    xmlXPathReleaseObject(ctxt->context, str);
9028}
9029
9030/**
9031 * xmlXPathSubstringBeforeFunction:
9032 * @ctxt:  the XPath Parser context
9033 * @nargs:  the number of arguments
9034 *
9035 * Implement the substring-before() XPath function
9036 *    string substring-before(string, string)
9037 * The substring-before function returns the substring of the first
9038 * argument string that precedes the first occurrence of the second
9039 * argument string in the first argument string, or the empty string
9040 * if the first argument string does not contain the second argument
9041 * string. For example, substring-before("1999/04/01","/") returns 1999.
9042 */
9043void
9044xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9045  xmlXPathObjectPtr str;
9046  xmlXPathObjectPtr find;
9047  xmlBufferPtr target;
9048  const xmlChar *point;
9049  int offset;
9050
9051  CHECK_ARITY(2);
9052  CAST_TO_STRING;
9053  find = valuePop(ctxt);
9054  CAST_TO_STRING;
9055  str = valuePop(ctxt);
9056
9057  target = xmlBufferCreate();
9058  if (target) {
9059    point = xmlStrstr(str->stringval, find->stringval);
9060    if (point) {
9061      offset = (int)(point - str->stringval);
9062      xmlBufferAdd(target, str->stringval, offset);
9063    }
9064    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9065	xmlBufferContent(target)));
9066    xmlBufferFree(target);
9067  }
9068  xmlXPathReleaseObject(ctxt->context, str);
9069  xmlXPathReleaseObject(ctxt->context, find);
9070}
9071
9072/**
9073 * xmlXPathSubstringAfterFunction:
9074 * @ctxt:  the XPath Parser context
9075 * @nargs:  the number of arguments
9076 *
9077 * Implement the substring-after() XPath function
9078 *    string substring-after(string, string)
9079 * The substring-after function returns the substring of the first
9080 * argument string that follows the first occurrence of the second
9081 * argument string in the first argument string, or the empty stringi
9082 * if the first argument string does not contain the second argument
9083 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9084 * and substring-after("1999/04/01","19") returns 99/04/01.
9085 */
9086void
9087xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9088  xmlXPathObjectPtr str;
9089  xmlXPathObjectPtr find;
9090  xmlBufferPtr target;
9091  const xmlChar *point;
9092  int offset;
9093
9094  CHECK_ARITY(2);
9095  CAST_TO_STRING;
9096  find = valuePop(ctxt);
9097  CAST_TO_STRING;
9098  str = valuePop(ctxt);
9099
9100  target = xmlBufferCreate();
9101  if (target) {
9102    point = xmlStrstr(str->stringval, find->stringval);
9103    if (point) {
9104      offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9105      xmlBufferAdd(target, &str->stringval[offset],
9106		   xmlStrlen(str->stringval) - offset);
9107    }
9108    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9109	xmlBufferContent(target)));
9110    xmlBufferFree(target);
9111  }
9112  xmlXPathReleaseObject(ctxt->context, str);
9113  xmlXPathReleaseObject(ctxt->context, find);
9114}
9115
9116/**
9117 * xmlXPathNormalizeFunction:
9118 * @ctxt:  the XPath Parser context
9119 * @nargs:  the number of arguments
9120 *
9121 * Implement the normalize-space() XPath function
9122 *    string normalize-space(string?)
9123 * The normalize-space function returns the argument string with white
9124 * space normalized by stripping leading and trailing whitespace
9125 * and replacing sequences of whitespace characters by a single
9126 * space. Whitespace characters are the same allowed by the S production
9127 * in XML. If the argument is omitted, it defaults to the context
9128 * node converted to a string, in other words the value of the context node.
9129 */
9130void
9131xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9132  xmlXPathObjectPtr obj = NULL;
9133  xmlChar *source = NULL;
9134  xmlBufferPtr target;
9135  xmlChar blank;
9136
9137  if (ctxt == NULL) return;
9138  if (nargs == 0) {
9139    /* Use current context node */
9140      valuePush(ctxt,
9141	  xmlXPathCacheWrapString(ctxt->context,
9142	    xmlXPathCastNodeToString(ctxt->context->node)));
9143    nargs = 1;
9144  }
9145
9146  CHECK_ARITY(1);
9147  CAST_TO_STRING;
9148  CHECK_TYPE(XPATH_STRING);
9149  obj = valuePop(ctxt);
9150  source = obj->stringval;
9151
9152  target = xmlBufferCreate();
9153  if (target && source) {
9154
9155    /* Skip leading whitespaces */
9156    while (IS_BLANK_CH(*source))
9157      source++;
9158
9159    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9160    blank = 0;
9161    while (*source) {
9162      if (IS_BLANK_CH(*source)) {
9163	blank = 0x20;
9164      } else {
9165	if (blank) {
9166	  xmlBufferAdd(target, &blank, 1);
9167	  blank = 0;
9168	}
9169	xmlBufferAdd(target, source, 1);
9170      }
9171      source++;
9172    }
9173    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9174	xmlBufferContent(target)));
9175    xmlBufferFree(target);
9176  }
9177  xmlXPathReleaseObject(ctxt->context, obj);
9178}
9179
9180/**
9181 * xmlXPathTranslateFunction:
9182 * @ctxt:  the XPath Parser context
9183 * @nargs:  the number of arguments
9184 *
9185 * Implement the translate() XPath function
9186 *    string translate(string, string, string)
9187 * The translate function returns the first argument string with
9188 * occurrences of characters in the second argument string replaced
9189 * by the character at the corresponding position in the third argument
9190 * string. For example, translate("bar","abc","ABC") returns the string
9191 * BAr. If there is a character in the second argument string with no
9192 * character at a corresponding position in the third argument string
9193 * (because the second argument string is longer than the third argument
9194 * string), then occurrences of that character in the first argument
9195 * string are removed. For example, translate("--aaa--","abc-","ABC")
9196 * returns "AAA". If a character occurs more than once in second
9197 * argument string, then the first occurrence determines the replacement
9198 * character. If the third argument string is longer than the second
9199 * argument string, then excess characters are ignored.
9200 */
9201void
9202xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9203    xmlXPathObjectPtr str;
9204    xmlXPathObjectPtr from;
9205    xmlXPathObjectPtr to;
9206    xmlBufferPtr target;
9207    int offset, max;
9208    xmlChar ch;
9209    const xmlChar *point;
9210    xmlChar *cptr;
9211
9212    CHECK_ARITY(3);
9213
9214    CAST_TO_STRING;
9215    to = valuePop(ctxt);
9216    CAST_TO_STRING;
9217    from = valuePop(ctxt);
9218    CAST_TO_STRING;
9219    str = valuePop(ctxt);
9220
9221    target = xmlBufferCreate();
9222    if (target) {
9223	max = xmlUTF8Strlen(to->stringval);
9224	for (cptr = str->stringval; (ch=*cptr); ) {
9225	    offset = xmlUTF8Strloc(from->stringval, cptr);
9226	    if (offset >= 0) {
9227		if (offset < max) {
9228		    point = xmlUTF8Strpos(to->stringval, offset);
9229		    if (point)
9230			xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9231		}
9232	    } else
9233		xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9234
9235	    /* Step to next character in input */
9236	    cptr++;
9237	    if ( ch & 0x80 ) {
9238		/* if not simple ascii, verify proper format */
9239		if ( (ch & 0xc0) != 0xc0 ) {
9240		    xmlGenericError(xmlGenericErrorContext,
9241			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9242		    break;
9243		}
9244		/* then skip over remaining bytes for this char */
9245		while ( (ch <<= 1) & 0x80 )
9246		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9247			xmlGenericError(xmlGenericErrorContext,
9248			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9249			break;
9250		    }
9251		if (ch & 0x80) /* must have had error encountered */
9252		    break;
9253	    }
9254	}
9255    }
9256    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9257	xmlBufferContent(target)));
9258    xmlBufferFree(target);
9259    xmlXPathReleaseObject(ctxt->context, str);
9260    xmlXPathReleaseObject(ctxt->context, from);
9261    xmlXPathReleaseObject(ctxt->context, to);
9262}
9263
9264/**
9265 * xmlXPathBooleanFunction:
9266 * @ctxt:  the XPath Parser context
9267 * @nargs:  the number of arguments
9268 *
9269 * Implement the boolean() XPath function
9270 *    boolean boolean(object)
9271 * The boolean function converts its argument to a boolean as follows:
9272 *    - a number is true if and only if it is neither positive or
9273 *      negative zero nor NaN
9274 *    - a node-set is true if and only if it is non-empty
9275 *    - a string is true if and only if its length is non-zero
9276 */
9277void
9278xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9279    xmlXPathObjectPtr cur;
9280
9281    CHECK_ARITY(1);
9282    cur = valuePop(ctxt);
9283    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9284    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9285    valuePush(ctxt, cur);
9286}
9287
9288/**
9289 * xmlXPathNotFunction:
9290 * @ctxt:  the XPath Parser context
9291 * @nargs:  the number of arguments
9292 *
9293 * Implement the not() XPath function
9294 *    boolean not(boolean)
9295 * The not function returns true if its argument is false,
9296 * and false otherwise.
9297 */
9298void
9299xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9300    CHECK_ARITY(1);
9301    CAST_TO_BOOLEAN;
9302    CHECK_TYPE(XPATH_BOOLEAN);
9303    ctxt->value->boolval = ! ctxt->value->boolval;
9304}
9305
9306/**
9307 * xmlXPathTrueFunction:
9308 * @ctxt:  the XPath Parser context
9309 * @nargs:  the number of arguments
9310 *
9311 * Implement the true() XPath function
9312 *    boolean true()
9313 */
9314void
9315xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9316    CHECK_ARITY(0);
9317    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9318}
9319
9320/**
9321 * xmlXPathFalseFunction:
9322 * @ctxt:  the XPath Parser context
9323 * @nargs:  the number of arguments
9324 *
9325 * Implement the false() XPath function
9326 *    boolean false()
9327 */
9328void
9329xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9330    CHECK_ARITY(0);
9331    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9332}
9333
9334/**
9335 * xmlXPathLangFunction:
9336 * @ctxt:  the XPath Parser context
9337 * @nargs:  the number of arguments
9338 *
9339 * Implement the lang() XPath function
9340 *    boolean lang(string)
9341 * The lang function returns true or false depending on whether the
9342 * language of the context node as specified by xml:lang attributes
9343 * is the same as or is a sublanguage of the language specified by
9344 * the argument string. The language of the context node is determined
9345 * by the value of the xml:lang attribute on the context node, or, if
9346 * the context node has no xml:lang attribute, by the value of the
9347 * xml:lang attribute on the nearest ancestor of the context node that
9348 * has an xml:lang attribute. If there is no such attribute, then lang
9349 * returns false. If there is such an attribute, then lang returns
9350 * true if the attribute value is equal to the argument ignoring case,
9351 * or if there is some suffix starting with - such that the attribute
9352 * value is equal to the argument ignoring that suffix of the attribute
9353 * value and ignoring case.
9354 */
9355void
9356xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9357    xmlXPathObjectPtr val = NULL;
9358    const xmlChar *theLang = NULL;
9359    const xmlChar *lang;
9360    int ret = 0;
9361    int i;
9362
9363    CHECK_ARITY(1);
9364    CAST_TO_STRING;
9365    CHECK_TYPE(XPATH_STRING);
9366    val = valuePop(ctxt);
9367    lang = val->stringval;
9368    theLang = xmlNodeGetLang(ctxt->context->node);
9369    if ((theLang != NULL) && (lang != NULL)) {
9370        for (i = 0;lang[i] != 0;i++)
9371	    if (toupper(lang[i]) != toupper(theLang[i]))
9372	        goto not_equal;
9373	if ((theLang[i] == 0) || (theLang[i] == '-'))
9374	    ret = 1;
9375    }
9376not_equal:
9377    if (theLang != NULL)
9378	xmlFree((void *)theLang);
9379
9380    xmlXPathReleaseObject(ctxt->context, val);
9381    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9382}
9383
9384/**
9385 * xmlXPathNumberFunction:
9386 * @ctxt:  the XPath Parser context
9387 * @nargs:  the number of arguments
9388 *
9389 * Implement the number() XPath function
9390 *    number number(object?)
9391 */
9392void
9393xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9394    xmlXPathObjectPtr cur;
9395    double res;
9396
9397    if (ctxt == NULL) return;
9398    if (nargs == 0) {
9399	if (ctxt->context->node == NULL) {
9400	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9401	} else {
9402	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9403
9404	    res = xmlXPathStringEvalNumber(content);
9405	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9406	    xmlFree(content);
9407	}
9408	return;
9409    }
9410
9411    CHECK_ARITY(1);
9412    cur = valuePop(ctxt);
9413    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9414}
9415
9416/**
9417 * xmlXPathSumFunction:
9418 * @ctxt:  the XPath Parser context
9419 * @nargs:  the number of arguments
9420 *
9421 * Implement the sum() XPath function
9422 *    number sum(node-set)
9423 * The sum function returns the sum of the values of the nodes in
9424 * the argument node-set.
9425 */
9426void
9427xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9428    xmlXPathObjectPtr cur;
9429    int i;
9430    double res = 0.0;
9431
9432    CHECK_ARITY(1);
9433    if ((ctxt->value == NULL) ||
9434	((ctxt->value->type != XPATH_NODESET) &&
9435	 (ctxt->value->type != XPATH_XSLT_TREE)))
9436	XP_ERROR(XPATH_INVALID_TYPE);
9437    cur = valuePop(ctxt);
9438
9439    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9440	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9441	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9442	}
9443    }
9444    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9445    xmlXPathReleaseObject(ctxt->context, cur);
9446}
9447
9448/*
9449 * To assure working code on multiple platforms, we want to only depend
9450 * upon the characteristic truncation of converting a floating point value
9451 * to an integer.  Unfortunately, because of the different storage sizes
9452 * of our internal floating point value (double) and integer (int), we
9453 * can't directly convert (see bug 301162).  This macro is a messy
9454 * 'workaround'
9455 */
9456#define XTRUNC(f, v)            \
9457    f = fmod((v), INT_MAX);     \
9458    f = (v) - (f) + (double)((int)(f));
9459
9460/**
9461 * xmlXPathFloorFunction:
9462 * @ctxt:  the XPath Parser context
9463 * @nargs:  the number of arguments
9464 *
9465 * Implement the floor() XPath function
9466 *    number floor(number)
9467 * The floor function returns the largest (closest to positive infinity)
9468 * number that is not greater than the argument and that is an integer.
9469 */
9470void
9471xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9472    double f;
9473
9474    CHECK_ARITY(1);
9475    CAST_TO_NUMBER;
9476    CHECK_TYPE(XPATH_NUMBER);
9477
9478    XTRUNC(f, ctxt->value->floatval);
9479    if (f != ctxt->value->floatval) {
9480	if (ctxt->value->floatval > 0)
9481	    ctxt->value->floatval = f;
9482	else
9483	    ctxt->value->floatval = f - 1;
9484    }
9485}
9486
9487/**
9488 * xmlXPathCeilingFunction:
9489 * @ctxt:  the XPath Parser context
9490 * @nargs:  the number of arguments
9491 *
9492 * Implement the ceiling() XPath function
9493 *    number ceiling(number)
9494 * The ceiling function returns the smallest (closest to negative infinity)
9495 * number that is not less than the argument and that is an integer.
9496 */
9497void
9498xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9499    double f;
9500
9501    CHECK_ARITY(1);
9502    CAST_TO_NUMBER;
9503    CHECK_TYPE(XPATH_NUMBER);
9504
9505#if 0
9506    ctxt->value->floatval = ceil(ctxt->value->floatval);
9507#else
9508    XTRUNC(f, ctxt->value->floatval);
9509    if (f != ctxt->value->floatval) {
9510	if (ctxt->value->floatval > 0)
9511	    ctxt->value->floatval = f + 1;
9512	else {
9513	    if (ctxt->value->floatval < 0 && f == 0)
9514	        ctxt->value->floatval = xmlXPathNZERO;
9515	    else
9516	        ctxt->value->floatval = f;
9517	}
9518
9519    }
9520#endif
9521}
9522
9523/**
9524 * xmlXPathRoundFunction:
9525 * @ctxt:  the XPath Parser context
9526 * @nargs:  the number of arguments
9527 *
9528 * Implement the round() XPath function
9529 *    number round(number)
9530 * The round function returns the number that is closest to the
9531 * argument and that is an integer. If there are two such numbers,
9532 * then the one that is even is returned.
9533 */
9534void
9535xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9536    double f;
9537
9538    CHECK_ARITY(1);
9539    CAST_TO_NUMBER;
9540    CHECK_TYPE(XPATH_NUMBER);
9541
9542    if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9543	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9544	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9545	(ctxt->value->floatval == 0.0))
9546	return;
9547
9548    XTRUNC(f, ctxt->value->floatval);
9549    if (ctxt->value->floatval < 0) {
9550	if (ctxt->value->floatval < f - 0.5)
9551	    ctxt->value->floatval = f - 1;
9552	else
9553	    ctxt->value->floatval = f;
9554	if (ctxt->value->floatval == 0)
9555	    ctxt->value->floatval = xmlXPathNZERO;
9556    } else {
9557	if (ctxt->value->floatval < f + 0.5)
9558	    ctxt->value->floatval = f;
9559	else
9560	    ctxt->value->floatval = f + 1;
9561    }
9562}
9563
9564/************************************************************************
9565 *									*
9566 *			The Parser					*
9567 *									*
9568 ************************************************************************/
9569
9570/*
9571 * a few forward declarations since we use a recursive call based
9572 * implementation.
9573 */
9574static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9575static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9576static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9577static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9578static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9579	                                  int qualified);
9580
9581/**
9582 * xmlXPathCurrentChar:
9583 * @ctxt:  the XPath parser context
9584 * @cur:  pointer to the beginning of the char
9585 * @len:  pointer to the length of the char read
9586 *
9587 * The current char value, if using UTF-8 this may actually span multiple
9588 * bytes in the input buffer.
9589 *
9590 * Returns the current char value and its length
9591 */
9592
9593static int
9594xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9595    unsigned char c;
9596    unsigned int val;
9597    const xmlChar *cur;
9598
9599    if (ctxt == NULL)
9600	return(0);
9601    cur = ctxt->cur;
9602
9603    /*
9604     * We are supposed to handle UTF8, check it's valid
9605     * From rfc2044: encoding of the Unicode values on UTF-8:
9606     *
9607     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9608     * 0000 0000-0000 007F   0xxxxxxx
9609     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9610     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9611     *
9612     * Check for the 0x110000 limit too
9613     */
9614    c = *cur;
9615    if (c & 0x80) {
9616	if ((cur[1] & 0xc0) != 0x80)
9617	    goto encoding_error;
9618	if ((c & 0xe0) == 0xe0) {
9619
9620	    if ((cur[2] & 0xc0) != 0x80)
9621		goto encoding_error;
9622	    if ((c & 0xf0) == 0xf0) {
9623		if (((c & 0xf8) != 0xf0) ||
9624		    ((cur[3] & 0xc0) != 0x80))
9625		    goto encoding_error;
9626		/* 4-byte code */
9627		*len = 4;
9628		val = (cur[0] & 0x7) << 18;
9629		val |= (cur[1] & 0x3f) << 12;
9630		val |= (cur[2] & 0x3f) << 6;
9631		val |= cur[3] & 0x3f;
9632	    } else {
9633	      /* 3-byte code */
9634		*len = 3;
9635		val = (cur[0] & 0xf) << 12;
9636		val |= (cur[1] & 0x3f) << 6;
9637		val |= cur[2] & 0x3f;
9638	    }
9639	} else {
9640	  /* 2-byte code */
9641	    *len = 2;
9642	    val = (cur[0] & 0x1f) << 6;
9643	    val |= cur[1] & 0x3f;
9644	}
9645	if (!IS_CHAR(val)) {
9646	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9647	}
9648	return(val);
9649    } else {
9650	/* 1-byte code */
9651	*len = 1;
9652	return((int) *cur);
9653    }
9654encoding_error:
9655    /*
9656     * If we detect an UTF8 error that probably means that the
9657     * input encoding didn't get properly advertised in the
9658     * declaration header. Report the error and switch the encoding
9659     * to ISO-Latin-1 (if you don't like this policy, just declare the
9660     * encoding !)
9661     */
9662    *len = 0;
9663    XP_ERROR0(XPATH_ENCODING_ERROR);
9664}
9665
9666/**
9667 * xmlXPathParseNCName:
9668 * @ctxt:  the XPath Parser context
9669 *
9670 * parse an XML namespace non qualified name.
9671 *
9672 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9673 *
9674 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9675 *                       CombiningChar | Extender
9676 *
9677 * Returns the namespace name or NULL
9678 */
9679
9680xmlChar *
9681xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9682    const xmlChar *in;
9683    xmlChar *ret;
9684    int count = 0;
9685
9686    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9687    /*
9688     * Accelerator for simple ASCII names
9689     */
9690    in = ctxt->cur;
9691    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9692	((*in >= 0x41) && (*in <= 0x5A)) ||
9693	(*in == '_')) {
9694	in++;
9695	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9696	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9697	       ((*in >= 0x30) && (*in <= 0x39)) ||
9698	       (*in == '_') || (*in == '.') ||
9699	       (*in == '-'))
9700	    in++;
9701	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9702            (*in == '[') || (*in == ']') || (*in == ':') ||
9703            (*in == '@') || (*in == '*')) {
9704	    count = in - ctxt->cur;
9705	    if (count == 0)
9706		return(NULL);
9707	    ret = xmlStrndup(ctxt->cur, count);
9708	    ctxt->cur = in;
9709	    return(ret);
9710	}
9711    }
9712    return(xmlXPathParseNameComplex(ctxt, 0));
9713}
9714
9715
9716/**
9717 * xmlXPathParseQName:
9718 * @ctxt:  the XPath Parser context
9719 * @prefix:  a xmlChar **
9720 *
9721 * parse an XML qualified name
9722 *
9723 * [NS 5] QName ::= (Prefix ':')? LocalPart
9724 *
9725 * [NS 6] Prefix ::= NCName
9726 *
9727 * [NS 7] LocalPart ::= NCName
9728 *
9729 * Returns the function returns the local part, and prefix is updated
9730 *   to get the Prefix if any.
9731 */
9732
9733static xmlChar *
9734xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9735    xmlChar *ret = NULL;
9736
9737    *prefix = NULL;
9738    ret = xmlXPathParseNCName(ctxt);
9739    if (CUR == ':') {
9740        *prefix = ret;
9741	NEXT;
9742	ret = xmlXPathParseNCName(ctxt);
9743    }
9744    return(ret);
9745}
9746
9747/**
9748 * xmlXPathParseName:
9749 * @ctxt:  the XPath Parser context
9750 *
9751 * parse an XML name
9752 *
9753 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9754 *                  CombiningChar | Extender
9755 *
9756 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9757 *
9758 * Returns the namespace name or NULL
9759 */
9760
9761xmlChar *
9762xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9763    const xmlChar *in;
9764    xmlChar *ret;
9765    int count = 0;
9766
9767    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9768    /*
9769     * Accelerator for simple ASCII names
9770     */
9771    in = ctxt->cur;
9772    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9773	((*in >= 0x41) && (*in <= 0x5A)) ||
9774	(*in == '_') || (*in == ':')) {
9775	in++;
9776	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9777	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9778	       ((*in >= 0x30) && (*in <= 0x39)) ||
9779	       (*in == '_') || (*in == '-') ||
9780	       (*in == ':') || (*in == '.'))
9781	    in++;
9782	if ((*in > 0) && (*in < 0x80)) {
9783	    count = in - ctxt->cur;
9784	    ret = xmlStrndup(ctxt->cur, count);
9785	    ctxt->cur = in;
9786	    return(ret);
9787	}
9788    }
9789    return(xmlXPathParseNameComplex(ctxt, 1));
9790}
9791
9792static xmlChar *
9793xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9794    xmlChar buf[XML_MAX_NAMELEN + 5];
9795    int len = 0, l;
9796    int c;
9797
9798    /*
9799     * Handler for more complex cases
9800     */
9801    c = CUR_CHAR(l);
9802    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9803        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9804        (c == '*') || /* accelerators */
9805	(!IS_LETTER(c) && (c != '_') &&
9806         ((qualified) && (c != ':')))) {
9807	return(NULL);
9808    }
9809
9810    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9811	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9812            (c == '.') || (c == '-') ||
9813	    (c == '_') || ((qualified) && (c == ':')) ||
9814	    (IS_COMBINING(c)) ||
9815	    (IS_EXTENDER(c)))) {
9816	COPY_BUF(l,buf,len,c);
9817	NEXTL(l);
9818	c = CUR_CHAR(l);
9819	if (len >= XML_MAX_NAMELEN) {
9820	    /*
9821	     * Okay someone managed to make a huge name, so he's ready to pay
9822	     * for the processing speed.
9823	     */
9824	    xmlChar *buffer;
9825	    int max = len * 2;
9826
9827	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9828	    if (buffer == NULL) {
9829		XP_ERRORNULL(XPATH_MEMORY_ERROR);
9830	    }
9831	    memcpy(buffer, buf, len);
9832	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9833		   (c == '.') || (c == '-') ||
9834		   (c == '_') || ((qualified) && (c == ':')) ||
9835		   (IS_COMBINING(c)) ||
9836		   (IS_EXTENDER(c))) {
9837		if (len + 10 > max) {
9838		    max *= 2;
9839		    buffer = (xmlChar *) xmlRealloc(buffer,
9840			                            max * sizeof(xmlChar));
9841		    if (buffer == NULL) {
9842			XP_ERRORNULL(XPATH_MEMORY_ERROR);
9843		    }
9844		}
9845		COPY_BUF(l,buffer,len,c);
9846		NEXTL(l);
9847		c = CUR_CHAR(l);
9848	    }
9849	    buffer[len] = 0;
9850	    return(buffer);
9851	}
9852    }
9853    if (len == 0)
9854	return(NULL);
9855    return(xmlStrndup(buf, len));
9856}
9857
9858#define MAX_FRAC 20
9859
9860/*
9861 * These are used as divisors for the fractional part of a number.
9862 * Since the table includes 1.0 (representing '0' fractional digits),
9863 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9864 */
9865static double my_pow10[MAX_FRAC+1] = {
9866    1.0, 10.0, 100.0, 1000.0, 10000.0,
9867    100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9868    10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9869    100000000000000.0,
9870    1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9871    1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9872};
9873
9874/**
9875 * xmlXPathStringEvalNumber:
9876 * @str:  A string to scan
9877 *
9878 *  [30a]  Float  ::= Number ('e' Digits?)?
9879 *
9880 *  [30]   Number ::=   Digits ('.' Digits?)?
9881 *                    | '.' Digits
9882 *  [31]   Digits ::=   [0-9]+
9883 *
9884 * Compile a Number in the string
9885 * In complement of the Number expression, this function also handles
9886 * negative values : '-' Number.
9887 *
9888 * Returns the double value.
9889 */
9890double
9891xmlXPathStringEvalNumber(const xmlChar *str) {
9892    const xmlChar *cur = str;
9893    double ret;
9894    int ok = 0;
9895    int isneg = 0;
9896    int exponent = 0;
9897    int is_exponent_negative = 0;
9898#ifdef __GNUC__
9899    unsigned long tmp = 0;
9900    double temp;
9901#endif
9902    if (cur == NULL) return(0);
9903    while (IS_BLANK_CH(*cur)) cur++;
9904    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9905        return(xmlXPathNAN);
9906    }
9907    if (*cur == '-') {
9908	isneg = 1;
9909	cur++;
9910    }
9911
9912#ifdef __GNUC__
9913    /*
9914     * tmp/temp is a workaround against a gcc compiler bug
9915     * http://veillard.com/gcc.bug
9916     */
9917    ret = 0;
9918    while ((*cur >= '0') && (*cur <= '9')) {
9919	ret = ret * 10;
9920	tmp = (*cur - '0');
9921	ok = 1;
9922	cur++;
9923	temp = (double) tmp;
9924	ret = ret + temp;
9925    }
9926#else
9927    ret = 0;
9928    while ((*cur >= '0') && (*cur <= '9')) {
9929	ret = ret * 10 + (*cur - '0');
9930	ok = 1;
9931	cur++;
9932    }
9933#endif
9934
9935    if (*cur == '.') {
9936	int v, frac = 0;
9937	double fraction = 0;
9938
9939        cur++;
9940	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9941	    return(xmlXPathNAN);
9942	}
9943	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9944	    v = (*cur - '0');
9945	    fraction = fraction * 10 + v;
9946	    frac = frac + 1;
9947	    cur++;
9948	}
9949	fraction /= my_pow10[frac];
9950	ret = ret + fraction;
9951	while ((*cur >= '0') && (*cur <= '9'))
9952	    cur++;
9953    }
9954    if ((*cur == 'e') || (*cur == 'E')) {
9955      cur++;
9956      if (*cur == '-') {
9957	is_exponent_negative = 1;
9958	cur++;
9959      } else if (*cur == '+') {
9960        cur++;
9961      }
9962      while ((*cur >= '0') && (*cur <= '9')) {
9963	exponent = exponent * 10 + (*cur - '0');
9964	cur++;
9965      }
9966    }
9967    while (IS_BLANK_CH(*cur)) cur++;
9968    if (*cur != 0) return(xmlXPathNAN);
9969    if (isneg) ret = -ret;
9970    if (is_exponent_negative) exponent = -exponent;
9971    ret *= pow(10.0, (double)exponent);
9972    return(ret);
9973}
9974
9975/**
9976 * xmlXPathCompNumber:
9977 * @ctxt:  the XPath Parser context
9978 *
9979 *  [30]   Number ::=   Digits ('.' Digits?)?
9980 *                    | '.' Digits
9981 *  [31]   Digits ::=   [0-9]+
9982 *
9983 * Compile a Number, then push it on the stack
9984 *
9985 */
9986static void
9987xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9988{
9989    double ret = 0.0;
9990    double mult = 1;
9991    int ok = 0;
9992    int exponent = 0;
9993    int is_exponent_negative = 0;
9994#ifdef __GNUC__
9995    unsigned long tmp = 0;
9996    double temp;
9997#endif
9998
9999    CHECK_ERROR;
10000    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10001        XP_ERROR(XPATH_NUMBER_ERROR);
10002    }
10003#ifdef __GNUC__
10004    /*
10005     * tmp/temp is a workaround against a gcc compiler bug
10006     * http://veillard.com/gcc.bug
10007     */
10008    ret = 0;
10009    while ((CUR >= '0') && (CUR <= '9')) {
10010	ret = ret * 10;
10011	tmp = (CUR - '0');
10012        ok = 1;
10013        NEXT;
10014	temp = (double) tmp;
10015	ret = ret + temp;
10016    }
10017#else
10018    ret = 0;
10019    while ((CUR >= '0') && (CUR <= '9')) {
10020	ret = ret * 10 + (CUR - '0');
10021	ok = 1;
10022	NEXT;
10023    }
10024#endif
10025    if (CUR == '.') {
10026        NEXT;
10027        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10028            XP_ERROR(XPATH_NUMBER_ERROR);
10029        }
10030        while ((CUR >= '0') && (CUR <= '9')) {
10031            mult /= 10;
10032            ret = ret + (CUR - '0') * mult;
10033            NEXT;
10034        }
10035    }
10036    if ((CUR == 'e') || (CUR == 'E')) {
10037        NEXT;
10038        if (CUR == '-') {
10039            is_exponent_negative = 1;
10040            NEXT;
10041        } else if (CUR == '+') {
10042	    NEXT;
10043	}
10044        while ((CUR >= '0') && (CUR <= '9')) {
10045            exponent = exponent * 10 + (CUR - '0');
10046            NEXT;
10047        }
10048        if (is_exponent_negative)
10049            exponent = -exponent;
10050        ret *= pow(10.0, (double) exponent);
10051    }
10052    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10053                   xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10054}
10055
10056/**
10057 * xmlXPathParseLiteral:
10058 * @ctxt:  the XPath Parser context
10059 *
10060 * Parse a Literal
10061 *
10062 *  [29]   Literal ::=   '"' [^"]* '"'
10063 *                    | "'" [^']* "'"
10064 *
10065 * Returns the value found or NULL in case of error
10066 */
10067static xmlChar *
10068xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10069    const xmlChar *q;
10070    xmlChar *ret = NULL;
10071
10072    if (CUR == '"') {
10073        NEXT;
10074	q = CUR_PTR;
10075	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10076	    NEXT;
10077	if (!IS_CHAR_CH(CUR)) {
10078	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10079	} else {
10080	    ret = xmlStrndup(q, CUR_PTR - q);
10081	    NEXT;
10082        }
10083    } else if (CUR == '\'') {
10084        NEXT;
10085	q = CUR_PTR;
10086	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10087	    NEXT;
10088	if (!IS_CHAR_CH(CUR)) {
10089	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10090	} else {
10091	    ret = xmlStrndup(q, CUR_PTR - q);
10092	    NEXT;
10093        }
10094    } else {
10095	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10096    }
10097    return(ret);
10098}
10099
10100/**
10101 * xmlXPathCompLiteral:
10102 * @ctxt:  the XPath Parser context
10103 *
10104 * Parse a Literal and push it on the stack.
10105 *
10106 *  [29]   Literal ::=   '"' [^"]* '"'
10107 *                    | "'" [^']* "'"
10108 *
10109 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10110 */
10111static void
10112xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10113    const xmlChar *q;
10114    xmlChar *ret = NULL;
10115
10116    if (CUR == '"') {
10117        NEXT;
10118	q = CUR_PTR;
10119	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10120	    NEXT;
10121	if (!IS_CHAR_CH(CUR)) {
10122	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10123	} else {
10124	    ret = xmlStrndup(q, CUR_PTR - q);
10125	    NEXT;
10126        }
10127    } else if (CUR == '\'') {
10128        NEXT;
10129	q = CUR_PTR;
10130	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10131	    NEXT;
10132	if (!IS_CHAR_CH(CUR)) {
10133	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10134	} else {
10135	    ret = xmlStrndup(q, CUR_PTR - q);
10136	    NEXT;
10137        }
10138    } else {
10139	XP_ERROR(XPATH_START_LITERAL_ERROR);
10140    }
10141    if (ret == NULL) return;
10142    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10143	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10144    xmlFree(ret);
10145}
10146
10147/**
10148 * xmlXPathCompVariableReference:
10149 * @ctxt:  the XPath Parser context
10150 *
10151 * Parse a VariableReference, evaluate it and push it on the stack.
10152 *
10153 * The variable bindings consist of a mapping from variable names
10154 * to variable values. The value of a variable is an object, which can be
10155 * of any of the types that are possible for the value of an expression,
10156 * and may also be of additional types not specified here.
10157 *
10158 * Early evaluation is possible since:
10159 * The variable bindings [...] used to evaluate a subexpression are
10160 * always the same as those used to evaluate the containing expression.
10161 *
10162 *  [36]   VariableReference ::=   '$' QName
10163 */
10164static void
10165xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10166    xmlChar *name;
10167    xmlChar *prefix;
10168
10169    SKIP_BLANKS;
10170    if (CUR != '$') {
10171	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10172    }
10173    NEXT;
10174    name = xmlXPathParseQName(ctxt, &prefix);
10175    if (name == NULL) {
10176	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10177    }
10178    ctxt->comp->last = -1;
10179    PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10180	           name, prefix);
10181    SKIP_BLANKS;
10182    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10183	XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10184    }
10185}
10186
10187/**
10188 * xmlXPathIsNodeType:
10189 * @name:  a name string
10190 *
10191 * Is the name given a NodeType one.
10192 *
10193 *  [38]   NodeType ::=   'comment'
10194 *                    | 'text'
10195 *                    | 'processing-instruction'
10196 *                    | 'node'
10197 *
10198 * Returns 1 if true 0 otherwise
10199 */
10200int
10201xmlXPathIsNodeType(const xmlChar *name) {
10202    if (name == NULL)
10203	return(0);
10204
10205    if (xmlStrEqual(name, BAD_CAST "node"))
10206	return(1);
10207    if (xmlStrEqual(name, BAD_CAST "text"))
10208	return(1);
10209    if (xmlStrEqual(name, BAD_CAST "comment"))
10210	return(1);
10211    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10212	return(1);
10213    return(0);
10214}
10215
10216/**
10217 * xmlXPathCompFunctionCall:
10218 * @ctxt:  the XPath Parser context
10219 *
10220 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10221 *  [17]   Argument ::=   Expr
10222 *
10223 * Compile a function call, the evaluation of all arguments are
10224 * pushed on the stack
10225 */
10226static void
10227xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10228    xmlChar *name;
10229    xmlChar *prefix;
10230    int nbargs = 0;
10231    int sort = 1;
10232
10233    name = xmlXPathParseQName(ctxt, &prefix);
10234    if (name == NULL) {
10235	XP_ERROR(XPATH_EXPR_ERROR);
10236    }
10237    SKIP_BLANKS;
10238#ifdef DEBUG_EXPR
10239    if (prefix == NULL)
10240	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10241			name);
10242    else
10243	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10244			prefix, name);
10245#endif
10246
10247    if (CUR != '(') {
10248	XP_ERROR(XPATH_EXPR_ERROR);
10249    }
10250    NEXT;
10251    SKIP_BLANKS;
10252
10253    /*
10254    * Optimization for count(): we don't need the node-set to be sorted.
10255    */
10256    if ((prefix == NULL) && (name[0] == 'c') &&
10257	xmlStrEqual(name, BAD_CAST "count"))
10258    {
10259	sort = 0;
10260    }
10261    ctxt->comp->last = -1;
10262    if (CUR != ')') {
10263	while (CUR != 0) {
10264	    int op1 = ctxt->comp->last;
10265	    ctxt->comp->last = -1;
10266	    xmlXPathCompileExpr(ctxt, sort);
10267	    CHECK_ERROR;
10268	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10269	    nbargs++;
10270	    if (CUR == ')') break;
10271	    if (CUR != ',') {
10272		XP_ERROR(XPATH_EXPR_ERROR);
10273	    }
10274	    NEXT;
10275	    SKIP_BLANKS;
10276	}
10277    }
10278    PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10279	           name, prefix);
10280    NEXT;
10281    SKIP_BLANKS;
10282}
10283
10284/**
10285 * xmlXPathCompPrimaryExpr:
10286 * @ctxt:  the XPath Parser context
10287 *
10288 *  [15]   PrimaryExpr ::=   VariableReference
10289 *                | '(' Expr ')'
10290 *                | Literal
10291 *                | Number
10292 *                | FunctionCall
10293 *
10294 * Compile a primary expression.
10295 */
10296static void
10297xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10298    SKIP_BLANKS;
10299    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10300    else if (CUR == '(') {
10301	NEXT;
10302	SKIP_BLANKS;
10303	xmlXPathCompileExpr(ctxt, 1);
10304	CHECK_ERROR;
10305	if (CUR != ')') {
10306	    XP_ERROR(XPATH_EXPR_ERROR);
10307	}
10308	NEXT;
10309	SKIP_BLANKS;
10310    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10311	xmlXPathCompNumber(ctxt);
10312    } else if ((CUR == '\'') || (CUR == '"')) {
10313	xmlXPathCompLiteral(ctxt);
10314    } else {
10315	xmlXPathCompFunctionCall(ctxt);
10316    }
10317    SKIP_BLANKS;
10318}
10319
10320/**
10321 * xmlXPathCompFilterExpr:
10322 * @ctxt:  the XPath Parser context
10323 *
10324 *  [20]   FilterExpr ::=   PrimaryExpr
10325 *               | FilterExpr Predicate
10326 *
10327 * Compile a filter expression.
10328 * Square brackets are used to filter expressions in the same way that
10329 * they are used in location paths. It is an error if the expression to
10330 * be filtered does not evaluate to a node-set. The context node list
10331 * used for evaluating the expression in square brackets is the node-set
10332 * to be filtered listed in document order.
10333 */
10334
10335static void
10336xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10337    xmlXPathCompPrimaryExpr(ctxt);
10338    CHECK_ERROR;
10339    SKIP_BLANKS;
10340
10341    while (CUR == '[') {
10342	xmlXPathCompPredicate(ctxt, 1);
10343	SKIP_BLANKS;
10344    }
10345
10346
10347}
10348
10349/**
10350 * xmlXPathScanName:
10351 * @ctxt:  the XPath Parser context
10352 *
10353 * Trickery: parse an XML name but without consuming the input flow
10354 * Needed to avoid insanity in the parser state.
10355 *
10356 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10357 *                  CombiningChar | Extender
10358 *
10359 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10360 *
10361 * [6] Names ::= Name (S Name)*
10362 *
10363 * Returns the Name parsed or NULL
10364 */
10365
10366static xmlChar *
10367xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10368    int len = 0, l;
10369    int c;
10370    const xmlChar *cur;
10371    xmlChar *ret;
10372
10373    cur = ctxt->cur;
10374
10375    c = CUR_CHAR(l);
10376    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10377	(!IS_LETTER(c) && (c != '_') &&
10378         (c != ':'))) {
10379	return(NULL);
10380    }
10381
10382    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10383	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10384            (c == '.') || (c == '-') ||
10385	    (c == '_') || (c == ':') ||
10386	    (IS_COMBINING(c)) ||
10387	    (IS_EXTENDER(c)))) {
10388	len += l;
10389	NEXTL(l);
10390	c = CUR_CHAR(l);
10391    }
10392    ret = xmlStrndup(cur, ctxt->cur - cur);
10393    ctxt->cur = cur;
10394    return(ret);
10395}
10396
10397/**
10398 * xmlXPathCompPathExpr:
10399 * @ctxt:  the XPath Parser context
10400 *
10401 *  [19]   PathExpr ::=   LocationPath
10402 *               | FilterExpr
10403 *               | FilterExpr '/' RelativeLocationPath
10404 *               | FilterExpr '//' RelativeLocationPath
10405 *
10406 * Compile a path expression.
10407 * The / operator and // operators combine an arbitrary expression
10408 * and a relative location path. It is an error if the expression
10409 * does not evaluate to a node-set.
10410 * The / operator does composition in the same way as when / is
10411 * used in a location path. As in location paths, // is short for
10412 * /descendant-or-self::node()/.
10413 */
10414
10415static void
10416xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10417    int lc = 1;           /* Should we branch to LocationPath ?         */
10418    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10419
10420    SKIP_BLANKS;
10421    if ((CUR == '$') || (CUR == '(') ||
10422    	(IS_ASCII_DIGIT(CUR)) ||
10423        (CUR == '\'') || (CUR == '"') ||
10424	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10425	lc = 0;
10426    } else if (CUR == '*') {
10427	/* relative or absolute location path */
10428	lc = 1;
10429    } else if (CUR == '/') {
10430	/* relative or absolute location path */
10431	lc = 1;
10432    } else if (CUR == '@') {
10433	/* relative abbreviated attribute location path */
10434	lc = 1;
10435    } else if (CUR == '.') {
10436	/* relative abbreviated attribute location path */
10437	lc = 1;
10438    } else {
10439	/*
10440	 * Problem is finding if we have a name here whether it's:
10441	 *   - a nodetype
10442	 *   - a function call in which case it's followed by '('
10443	 *   - an axis in which case it's followed by ':'
10444	 *   - a element name
10445	 * We do an a priori analysis here rather than having to
10446	 * maintain parsed token content through the recursive function
10447	 * calls. This looks uglier but makes the code easier to
10448	 * read/write/debug.
10449	 */
10450	SKIP_BLANKS;
10451	name = xmlXPathScanName(ctxt);
10452	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10453#ifdef DEBUG_STEP
10454	    xmlGenericError(xmlGenericErrorContext,
10455		    "PathExpr: Axis\n");
10456#endif
10457	    lc = 1;
10458	    xmlFree(name);
10459	} else if (name != NULL) {
10460	    int len =xmlStrlen(name);
10461
10462
10463	    while (NXT(len) != 0) {
10464		if (NXT(len) == '/') {
10465		    /* element name */
10466#ifdef DEBUG_STEP
10467		    xmlGenericError(xmlGenericErrorContext,
10468			    "PathExpr: AbbrRelLocation\n");
10469#endif
10470		    lc = 1;
10471		    break;
10472		} else if (IS_BLANK_CH(NXT(len))) {
10473		    /* ignore blanks */
10474		    ;
10475		} else if (NXT(len) == ':') {
10476#ifdef DEBUG_STEP
10477		    xmlGenericError(xmlGenericErrorContext,
10478			    "PathExpr: AbbrRelLocation\n");
10479#endif
10480		    lc = 1;
10481		    break;
10482		} else if ((NXT(len) == '(')) {
10483		    /* Note Type or Function */
10484		    if (xmlXPathIsNodeType(name)) {
10485#ifdef DEBUG_STEP
10486		        xmlGenericError(xmlGenericErrorContext,
10487				"PathExpr: Type search\n");
10488#endif
10489			lc = 1;
10490		    } else {
10491#ifdef DEBUG_STEP
10492		        xmlGenericError(xmlGenericErrorContext,
10493				"PathExpr: function call\n");
10494#endif
10495			lc = 0;
10496		    }
10497                    break;
10498		} else if ((NXT(len) == '[')) {
10499		    /* element name */
10500#ifdef DEBUG_STEP
10501		    xmlGenericError(xmlGenericErrorContext,
10502			    "PathExpr: AbbrRelLocation\n");
10503#endif
10504		    lc = 1;
10505		    break;
10506		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10507			   (NXT(len) == '=')) {
10508		    lc = 1;
10509		    break;
10510		} else {
10511		    lc = 1;
10512		    break;
10513		}
10514		len++;
10515	    }
10516	    if (NXT(len) == 0) {
10517#ifdef DEBUG_STEP
10518		xmlGenericError(xmlGenericErrorContext,
10519			"PathExpr: AbbrRelLocation\n");
10520#endif
10521		/* element name */
10522		lc = 1;
10523	    }
10524	    xmlFree(name);
10525	} else {
10526	    /* make sure all cases are covered explicitly */
10527	    XP_ERROR(XPATH_EXPR_ERROR);
10528	}
10529    }
10530
10531    if (lc) {
10532	if (CUR == '/') {
10533	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10534	} else {
10535	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10536	}
10537	xmlXPathCompLocationPath(ctxt);
10538    } else {
10539	xmlXPathCompFilterExpr(ctxt);
10540	CHECK_ERROR;
10541	if ((CUR == '/') && (NXT(1) == '/')) {
10542	    SKIP(2);
10543	    SKIP_BLANKS;
10544
10545	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10546		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10547	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10548
10549	    xmlXPathCompRelativeLocationPath(ctxt);
10550	} else if (CUR == '/') {
10551	    xmlXPathCompRelativeLocationPath(ctxt);
10552	}
10553    }
10554    SKIP_BLANKS;
10555}
10556
10557/**
10558 * xmlXPathCompUnionExpr:
10559 * @ctxt:  the XPath Parser context
10560 *
10561 *  [18]   UnionExpr ::=   PathExpr
10562 *               | UnionExpr '|' PathExpr
10563 *
10564 * Compile an union expression.
10565 */
10566
10567static void
10568xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10569    xmlXPathCompPathExpr(ctxt);
10570    CHECK_ERROR;
10571    SKIP_BLANKS;
10572    while (CUR == '|') {
10573	int op1 = ctxt->comp->last;
10574	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10575
10576	NEXT;
10577	SKIP_BLANKS;
10578	xmlXPathCompPathExpr(ctxt);
10579
10580	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10581
10582	SKIP_BLANKS;
10583    }
10584}
10585
10586/**
10587 * xmlXPathCompUnaryExpr:
10588 * @ctxt:  the XPath Parser context
10589 *
10590 *  [27]   UnaryExpr ::=   UnionExpr
10591 *                   | '-' UnaryExpr
10592 *
10593 * Compile an unary expression.
10594 */
10595
10596static void
10597xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10598    int minus = 0;
10599    int found = 0;
10600
10601    SKIP_BLANKS;
10602    while (CUR == '-') {
10603        minus = 1 - minus;
10604	found = 1;
10605	NEXT;
10606	SKIP_BLANKS;
10607    }
10608
10609    xmlXPathCompUnionExpr(ctxt);
10610    CHECK_ERROR;
10611    if (found) {
10612	if (minus)
10613	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10614	else
10615	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10616    }
10617}
10618
10619/**
10620 * xmlXPathCompMultiplicativeExpr:
10621 * @ctxt:  the XPath Parser context
10622 *
10623 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10624 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10625 *                   | MultiplicativeExpr 'div' UnaryExpr
10626 *                   | MultiplicativeExpr 'mod' UnaryExpr
10627 *  [34]   MultiplyOperator ::=   '*'
10628 *
10629 * Compile an Additive expression.
10630 */
10631
10632static void
10633xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10634    xmlXPathCompUnaryExpr(ctxt);
10635    CHECK_ERROR;
10636    SKIP_BLANKS;
10637    while ((CUR == '*') ||
10638           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10639           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10640	int op = -1;
10641	int op1 = ctxt->comp->last;
10642
10643        if (CUR == '*') {
10644	    op = 0;
10645	    NEXT;
10646	} else if (CUR == 'd') {
10647	    op = 1;
10648	    SKIP(3);
10649	} else if (CUR == 'm') {
10650	    op = 2;
10651	    SKIP(3);
10652	}
10653	SKIP_BLANKS;
10654        xmlXPathCompUnaryExpr(ctxt);
10655	CHECK_ERROR;
10656	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10657	SKIP_BLANKS;
10658    }
10659}
10660
10661/**
10662 * xmlXPathCompAdditiveExpr:
10663 * @ctxt:  the XPath Parser context
10664 *
10665 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10666 *                   | AdditiveExpr '+' MultiplicativeExpr
10667 *                   | AdditiveExpr '-' MultiplicativeExpr
10668 *
10669 * Compile an Additive expression.
10670 */
10671
10672static void
10673xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10674
10675    xmlXPathCompMultiplicativeExpr(ctxt);
10676    CHECK_ERROR;
10677    SKIP_BLANKS;
10678    while ((CUR == '+') || (CUR == '-')) {
10679	int plus;
10680	int op1 = ctxt->comp->last;
10681
10682        if (CUR == '+') plus = 1;
10683	else plus = 0;
10684	NEXT;
10685	SKIP_BLANKS;
10686        xmlXPathCompMultiplicativeExpr(ctxt);
10687	CHECK_ERROR;
10688	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10689	SKIP_BLANKS;
10690    }
10691}
10692
10693/**
10694 * xmlXPathCompRelationalExpr:
10695 * @ctxt:  the XPath Parser context
10696 *
10697 *  [24]   RelationalExpr ::=   AdditiveExpr
10698 *                 | RelationalExpr '<' AdditiveExpr
10699 *                 | RelationalExpr '>' AdditiveExpr
10700 *                 | RelationalExpr '<=' AdditiveExpr
10701 *                 | RelationalExpr '>=' AdditiveExpr
10702 *
10703 *  A <= B > C is allowed ? Answer from James, yes with
10704 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10705 *  which is basically what got implemented.
10706 *
10707 * Compile a Relational expression, then push the result
10708 * on the stack
10709 */
10710
10711static void
10712xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10713    xmlXPathCompAdditiveExpr(ctxt);
10714    CHECK_ERROR;
10715    SKIP_BLANKS;
10716    while ((CUR == '<') ||
10717           (CUR == '>') ||
10718           ((CUR == '<') && (NXT(1) == '=')) ||
10719           ((CUR == '>') && (NXT(1) == '='))) {
10720	int inf, strict;
10721	int op1 = ctxt->comp->last;
10722
10723        if (CUR == '<') inf = 1;
10724	else inf = 0;
10725	if (NXT(1) == '=') strict = 0;
10726	else strict = 1;
10727	NEXT;
10728	if (!strict) NEXT;
10729	SKIP_BLANKS;
10730        xmlXPathCompAdditiveExpr(ctxt);
10731	CHECK_ERROR;
10732	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10733	SKIP_BLANKS;
10734    }
10735}
10736
10737/**
10738 * xmlXPathCompEqualityExpr:
10739 * @ctxt:  the XPath Parser context
10740 *
10741 *  [23]   EqualityExpr ::=   RelationalExpr
10742 *                 | EqualityExpr '=' RelationalExpr
10743 *                 | EqualityExpr '!=' RelationalExpr
10744 *
10745 *  A != B != C is allowed ? Answer from James, yes with
10746 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10747 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10748 *  which is basically what got implemented.
10749 *
10750 * Compile an Equality expression.
10751 *
10752 */
10753static void
10754xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10755    xmlXPathCompRelationalExpr(ctxt);
10756    CHECK_ERROR;
10757    SKIP_BLANKS;
10758    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10759	int eq;
10760	int op1 = ctxt->comp->last;
10761
10762        if (CUR == '=') eq = 1;
10763	else eq = 0;
10764	NEXT;
10765	if (!eq) NEXT;
10766	SKIP_BLANKS;
10767        xmlXPathCompRelationalExpr(ctxt);
10768	CHECK_ERROR;
10769	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10770	SKIP_BLANKS;
10771    }
10772}
10773
10774/**
10775 * xmlXPathCompAndExpr:
10776 * @ctxt:  the XPath Parser context
10777 *
10778 *  [22]   AndExpr ::=   EqualityExpr
10779 *                 | AndExpr 'and' EqualityExpr
10780 *
10781 * Compile an AND expression.
10782 *
10783 */
10784static void
10785xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10786    xmlXPathCompEqualityExpr(ctxt);
10787    CHECK_ERROR;
10788    SKIP_BLANKS;
10789    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10790	int op1 = ctxt->comp->last;
10791        SKIP(3);
10792	SKIP_BLANKS;
10793        xmlXPathCompEqualityExpr(ctxt);
10794	CHECK_ERROR;
10795	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10796	SKIP_BLANKS;
10797    }
10798}
10799
10800/**
10801 * xmlXPathCompileExpr:
10802 * @ctxt:  the XPath Parser context
10803 *
10804 *  [14]   Expr ::=   OrExpr
10805 *  [21]   OrExpr ::=   AndExpr
10806 *                 | OrExpr 'or' AndExpr
10807 *
10808 * Parse and compile an expression
10809 */
10810static void
10811xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10812    xmlXPathCompAndExpr(ctxt);
10813    CHECK_ERROR;
10814    SKIP_BLANKS;
10815    while ((CUR == 'o') && (NXT(1) == 'r')) {
10816	int op1 = ctxt->comp->last;
10817        SKIP(2);
10818	SKIP_BLANKS;
10819        xmlXPathCompAndExpr(ctxt);
10820	CHECK_ERROR;
10821	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10822	op1 = ctxt->comp->nbStep;
10823	SKIP_BLANKS;
10824    }
10825    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10826	/* more ops could be optimized too */
10827	/*
10828	* This is the main place to eliminate sorting for
10829	* operations which don't require a sorted node-set.
10830	* E.g. count().
10831	*/
10832	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10833    }
10834}
10835
10836/**
10837 * xmlXPathCompPredicate:
10838 * @ctxt:  the XPath Parser context
10839 * @filter:  act as a filter
10840 *
10841 *  [8]   Predicate ::=   '[' PredicateExpr ']'
10842 *  [9]   PredicateExpr ::=   Expr
10843 *
10844 * Compile a predicate expression
10845 */
10846static void
10847xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10848    int op1 = ctxt->comp->last;
10849
10850    SKIP_BLANKS;
10851    if (CUR != '[') {
10852	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10853    }
10854    NEXT;
10855    SKIP_BLANKS;
10856
10857    ctxt->comp->last = -1;
10858    /*
10859    * This call to xmlXPathCompileExpr() will deactivate sorting
10860    * of the predicate result.
10861    * TODO: Sorting is still activated for filters, since I'm not
10862    *  sure if needed. Normally sorting should not be needed, since
10863    *  a filter can only diminish the number of items in a sequence,
10864    *  but won't change its order; so if the initial sequence is sorted,
10865    *  subsequent sorting is not needed.
10866    */
10867    if (! filter)
10868	xmlXPathCompileExpr(ctxt, 0);
10869    else
10870	xmlXPathCompileExpr(ctxt, 1);
10871    CHECK_ERROR;
10872
10873    if (CUR != ']') {
10874	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10875    }
10876
10877    if (filter)
10878	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10879    else
10880	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10881
10882    NEXT;
10883    SKIP_BLANKS;
10884}
10885
10886/**
10887 * xmlXPathCompNodeTest:
10888 * @ctxt:  the XPath Parser context
10889 * @test:  pointer to a xmlXPathTestVal
10890 * @type:  pointer to a xmlXPathTypeVal
10891 * @prefix:  placeholder for a possible name prefix
10892 *
10893 * [7] NodeTest ::=   NameTest
10894 *		    | NodeType '(' ')'
10895 *		    | 'processing-instruction' '(' Literal ')'
10896 *
10897 * [37] NameTest ::=  '*'
10898 *		    | NCName ':' '*'
10899 *		    | QName
10900 * [38] NodeType ::= 'comment'
10901 *		   | 'text'
10902 *		   | 'processing-instruction'
10903 *		   | 'node'
10904 *
10905 * Returns the name found and updates @test, @type and @prefix appropriately
10906 */
10907static xmlChar *
10908xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10909	             xmlXPathTypeVal *type, const xmlChar **prefix,
10910		     xmlChar *name) {
10911    int blanks;
10912
10913    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10914	STRANGE;
10915	return(NULL);
10916    }
10917    *type = (xmlXPathTypeVal) 0;
10918    *test = (xmlXPathTestVal) 0;
10919    *prefix = NULL;
10920    SKIP_BLANKS;
10921
10922    if ((name == NULL) && (CUR == '*')) {
10923	/*
10924	 * All elements
10925	 */
10926	NEXT;
10927	*test = NODE_TEST_ALL;
10928	return(NULL);
10929    }
10930
10931    if (name == NULL)
10932	name = xmlXPathParseNCName(ctxt);
10933    if (name == NULL) {
10934	XP_ERRORNULL(XPATH_EXPR_ERROR);
10935    }
10936
10937    blanks = IS_BLANK_CH(CUR);
10938    SKIP_BLANKS;
10939    if (CUR == '(') {
10940	NEXT;
10941	/*
10942	 * NodeType or PI search
10943	 */
10944	if (xmlStrEqual(name, BAD_CAST "comment"))
10945	    *type = NODE_TYPE_COMMENT;
10946	else if (xmlStrEqual(name, BAD_CAST "node"))
10947	    *type = NODE_TYPE_NODE;
10948	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10949	    *type = NODE_TYPE_PI;
10950	else if (xmlStrEqual(name, BAD_CAST "text"))
10951	    *type = NODE_TYPE_TEXT;
10952	else {
10953	    if (name != NULL)
10954		xmlFree(name);
10955	    XP_ERRORNULL(XPATH_EXPR_ERROR);
10956	}
10957
10958	*test = NODE_TEST_TYPE;
10959
10960	SKIP_BLANKS;
10961	if (*type == NODE_TYPE_PI) {
10962	    /*
10963	     * Specific case: search a PI by name.
10964	     */
10965	    if (name != NULL)
10966		xmlFree(name);
10967	    name = NULL;
10968	    if (CUR != ')') {
10969		name = xmlXPathParseLiteral(ctxt);
10970		CHECK_ERROR NULL;
10971		*test = NODE_TEST_PI;
10972		SKIP_BLANKS;
10973	    }
10974	}
10975	if (CUR != ')') {
10976	    if (name != NULL)
10977		xmlFree(name);
10978	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
10979	}
10980	NEXT;
10981	return(name);
10982    }
10983    *test = NODE_TEST_NAME;
10984    if ((!blanks) && (CUR == ':')) {
10985	NEXT;
10986
10987	/*
10988	 * Since currently the parser context don't have a
10989	 * namespace list associated:
10990	 * The namespace name for this prefix can be computed
10991	 * only at evaluation time. The compilation is done
10992	 * outside of any context.
10993	 */
10994#if 0
10995	*prefix = xmlXPathNsLookup(ctxt->context, name);
10996	if (name != NULL)
10997	    xmlFree(name);
10998	if (*prefix == NULL) {
10999	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11000	}
11001#else
11002	*prefix = name;
11003#endif
11004
11005	if (CUR == '*') {
11006	    /*
11007	     * All elements
11008	     */
11009	    NEXT;
11010	    *test = NODE_TEST_ALL;
11011	    return(NULL);
11012	}
11013
11014	name = xmlXPathParseNCName(ctxt);
11015	if (name == NULL) {
11016	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11017	}
11018    }
11019    return(name);
11020}
11021
11022/**
11023 * xmlXPathIsAxisName:
11024 * @name:  a preparsed name token
11025 *
11026 * [6] AxisName ::=   'ancestor'
11027 *                  | 'ancestor-or-self'
11028 *                  | 'attribute'
11029 *                  | 'child'
11030 *                  | 'descendant'
11031 *                  | 'descendant-or-self'
11032 *                  | 'following'
11033 *                  | 'following-sibling'
11034 *                  | 'namespace'
11035 *                  | 'parent'
11036 *                  | 'preceding'
11037 *                  | 'preceding-sibling'
11038 *                  | 'self'
11039 *
11040 * Returns the axis or 0
11041 */
11042static xmlXPathAxisVal
11043xmlXPathIsAxisName(const xmlChar *name) {
11044    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11045    switch (name[0]) {
11046	case 'a':
11047	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11048		ret = AXIS_ANCESTOR;
11049	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11050		ret = AXIS_ANCESTOR_OR_SELF;
11051	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11052		ret = AXIS_ATTRIBUTE;
11053	    break;
11054	case 'c':
11055	    if (xmlStrEqual(name, BAD_CAST "child"))
11056		ret = AXIS_CHILD;
11057	    break;
11058	case 'd':
11059	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11060		ret = AXIS_DESCENDANT;
11061	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11062		ret = AXIS_DESCENDANT_OR_SELF;
11063	    break;
11064	case 'f':
11065	    if (xmlStrEqual(name, BAD_CAST "following"))
11066		ret = AXIS_FOLLOWING;
11067	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11068		ret = AXIS_FOLLOWING_SIBLING;
11069	    break;
11070	case 'n':
11071	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11072		ret = AXIS_NAMESPACE;
11073	    break;
11074	case 'p':
11075	    if (xmlStrEqual(name, BAD_CAST "parent"))
11076		ret = AXIS_PARENT;
11077	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11078		ret = AXIS_PRECEDING;
11079	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11080		ret = AXIS_PRECEDING_SIBLING;
11081	    break;
11082	case 's':
11083	    if (xmlStrEqual(name, BAD_CAST "self"))
11084		ret = AXIS_SELF;
11085	    break;
11086    }
11087    return(ret);
11088}
11089
11090/**
11091 * xmlXPathCompStep:
11092 * @ctxt:  the XPath Parser context
11093 *
11094 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11095 *                  | AbbreviatedStep
11096 *
11097 * [12] AbbreviatedStep ::=   '.' | '..'
11098 *
11099 * [5] AxisSpecifier ::= AxisName '::'
11100 *                  | AbbreviatedAxisSpecifier
11101 *
11102 * [13] AbbreviatedAxisSpecifier ::= '@'?
11103 *
11104 * Modified for XPtr range support as:
11105 *
11106 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11107 *                     | AbbreviatedStep
11108 *                     | 'range-to' '(' Expr ')' Predicate*
11109 *
11110 * Compile one step in a Location Path
11111 * A location step of . is short for self::node(). This is
11112 * particularly useful in conjunction with //. For example, the
11113 * location path .//para is short for
11114 * self::node()/descendant-or-self::node()/child::para
11115 * and so will select all para descendant elements of the context
11116 * node.
11117 * Similarly, a location step of .. is short for parent::node().
11118 * For example, ../title is short for parent::node()/child::title
11119 * and so will select the title children of the parent of the context
11120 * node.
11121 */
11122static void
11123xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11124#ifdef LIBXML_XPTR_ENABLED
11125    int rangeto = 0;
11126    int op2 = -1;
11127#endif
11128
11129    SKIP_BLANKS;
11130    if ((CUR == '.') && (NXT(1) == '.')) {
11131	SKIP(2);
11132	SKIP_BLANKS;
11133	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11134		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11135    } else if (CUR == '.') {
11136	NEXT;
11137	SKIP_BLANKS;
11138    } else {
11139	xmlChar *name = NULL;
11140	const xmlChar *prefix = NULL;
11141	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11142	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11143	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11144	int op1;
11145
11146	/*
11147	 * The modification needed for XPointer change to the production
11148	 */
11149#ifdef LIBXML_XPTR_ENABLED
11150	if (ctxt->xptr) {
11151	    name = xmlXPathParseNCName(ctxt);
11152	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11153                op2 = ctxt->comp->last;
11154		xmlFree(name);
11155		SKIP_BLANKS;
11156		if (CUR != '(') {
11157		    XP_ERROR(XPATH_EXPR_ERROR);
11158		}
11159		NEXT;
11160		SKIP_BLANKS;
11161
11162		xmlXPathCompileExpr(ctxt, 1);
11163		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11164		CHECK_ERROR;
11165
11166		SKIP_BLANKS;
11167		if (CUR != ')') {
11168		    XP_ERROR(XPATH_EXPR_ERROR);
11169		}
11170		NEXT;
11171		rangeto = 1;
11172		goto eval_predicates;
11173	    }
11174	}
11175#endif
11176	if (CUR == '*') {
11177	    axis = AXIS_CHILD;
11178	} else {
11179	    if (name == NULL)
11180		name = xmlXPathParseNCName(ctxt);
11181	    if (name != NULL) {
11182		axis = xmlXPathIsAxisName(name);
11183		if (axis != 0) {
11184		    SKIP_BLANKS;
11185		    if ((CUR == ':') && (NXT(1) == ':')) {
11186			SKIP(2);
11187			xmlFree(name);
11188			name = NULL;
11189		    } else {
11190			/* an element name can conflict with an axis one :-\ */
11191			axis = AXIS_CHILD;
11192		    }
11193		} else {
11194		    axis = AXIS_CHILD;
11195		}
11196	    } else if (CUR == '@') {
11197		NEXT;
11198		axis = AXIS_ATTRIBUTE;
11199	    } else {
11200		axis = AXIS_CHILD;
11201	    }
11202	}
11203
11204	CHECK_ERROR;
11205
11206	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11207	if (test == 0)
11208	    return;
11209
11210        if ((prefix != NULL) && (ctxt->context != NULL) &&
11211	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11212	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11213		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11214	    }
11215	}
11216#ifdef DEBUG_STEP
11217	xmlGenericError(xmlGenericErrorContext,
11218		"Basis : computing new set\n");
11219#endif
11220
11221#ifdef DEBUG_STEP
11222	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11223	if (ctxt->value == NULL)
11224	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11225	else if (ctxt->value->nodesetval == NULL)
11226	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11227	else
11228	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11229#endif
11230
11231#ifdef LIBXML_XPTR_ENABLED
11232eval_predicates:
11233#endif
11234	op1 = ctxt->comp->last;
11235	ctxt->comp->last = -1;
11236
11237	SKIP_BLANKS;
11238	while (CUR == '[') {
11239	    xmlXPathCompPredicate(ctxt, 0);
11240	}
11241
11242#ifdef LIBXML_XPTR_ENABLED
11243	if (rangeto) {
11244	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11245	} else
11246#endif
11247	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11248			   test, type, (void *)prefix, (void *)name);
11249
11250    }
11251#ifdef DEBUG_STEP
11252    xmlGenericError(xmlGenericErrorContext, "Step : ");
11253    if (ctxt->value == NULL)
11254	xmlGenericError(xmlGenericErrorContext, "no value\n");
11255    else if (ctxt->value->nodesetval == NULL)
11256	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11257    else
11258	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11259		ctxt->value->nodesetval);
11260#endif
11261}
11262
11263/**
11264 * xmlXPathCompRelativeLocationPath:
11265 * @ctxt:  the XPath Parser context
11266 *
11267 *  [3]   RelativeLocationPath ::=   Step
11268 *                     | RelativeLocationPath '/' Step
11269 *                     | AbbreviatedRelativeLocationPath
11270 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11271 *
11272 * Compile a relative location path.
11273 */
11274static void
11275xmlXPathCompRelativeLocationPath
11276(xmlXPathParserContextPtr ctxt) {
11277    SKIP_BLANKS;
11278    if ((CUR == '/') && (NXT(1) == '/')) {
11279	SKIP(2);
11280	SKIP_BLANKS;
11281	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11282		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11283    } else if (CUR == '/') {
11284	    NEXT;
11285	SKIP_BLANKS;
11286    }
11287    xmlXPathCompStep(ctxt);
11288    SKIP_BLANKS;
11289    while (CUR == '/') {
11290	if ((CUR == '/') && (NXT(1) == '/')) {
11291	    SKIP(2);
11292	    SKIP_BLANKS;
11293	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11294			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11295	    xmlXPathCompStep(ctxt);
11296	} else if (CUR == '/') {
11297	    NEXT;
11298	    SKIP_BLANKS;
11299	    xmlXPathCompStep(ctxt);
11300	}
11301	SKIP_BLANKS;
11302    }
11303}
11304
11305/**
11306 * xmlXPathCompLocationPath:
11307 * @ctxt:  the XPath Parser context
11308 *
11309 *  [1]   LocationPath ::=   RelativeLocationPath
11310 *                     | AbsoluteLocationPath
11311 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11312 *                     | AbbreviatedAbsoluteLocationPath
11313 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11314 *                           '//' RelativeLocationPath
11315 *
11316 * Compile a location path
11317 *
11318 * // is short for /descendant-or-self::node()/. For example,
11319 * //para is short for /descendant-or-self::node()/child::para and
11320 * so will select any para element in the document (even a para element
11321 * that is a document element will be selected by //para since the
11322 * document element node is a child of the root node); div//para is
11323 * short for div/descendant-or-self::node()/child::para and so will
11324 * select all para descendants of div children.
11325 */
11326static void
11327xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11328    SKIP_BLANKS;
11329    if (CUR != '/') {
11330        xmlXPathCompRelativeLocationPath(ctxt);
11331    } else {
11332	while (CUR == '/') {
11333	    if ((CUR == '/') && (NXT(1) == '/')) {
11334		SKIP(2);
11335		SKIP_BLANKS;
11336		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11337			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11338		xmlXPathCompRelativeLocationPath(ctxt);
11339	    } else if (CUR == '/') {
11340		NEXT;
11341		SKIP_BLANKS;
11342		if ((CUR != 0 ) &&
11343		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11344		     (CUR == '@') || (CUR == '*')))
11345		    xmlXPathCompRelativeLocationPath(ctxt);
11346	    }
11347	}
11348    }
11349}
11350
11351/************************************************************************
11352 *									*
11353 * 		XPath precompiled expression evaluation			*
11354 *									*
11355 ************************************************************************/
11356
11357static int
11358xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11359
11360#ifdef DEBUG_STEP
11361static void
11362xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,
11363			  xmlXPathTestVal test,
11364			  int nbNodes)
11365{
11366    xmlGenericError(xmlGenericErrorContext, "new step : ");
11367    switch (axis) {
11368        case AXIS_ANCESTOR:
11369            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11370            break;
11371        case AXIS_ANCESTOR_OR_SELF:
11372            xmlGenericError(xmlGenericErrorContext,
11373                            "axis 'ancestors-or-self' ");
11374            break;
11375        case AXIS_ATTRIBUTE:
11376            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11377            break;
11378        case AXIS_CHILD:
11379            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11380            break;
11381        case AXIS_DESCENDANT:
11382            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11383            break;
11384        case AXIS_DESCENDANT_OR_SELF:
11385            xmlGenericError(xmlGenericErrorContext,
11386                            "axis 'descendant-or-self' ");
11387            break;
11388        case AXIS_FOLLOWING:
11389            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11390            break;
11391        case AXIS_FOLLOWING_SIBLING:
11392            xmlGenericError(xmlGenericErrorContext,
11393                            "axis 'following-siblings' ");
11394            break;
11395        case AXIS_NAMESPACE:
11396            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11397            break;
11398        case AXIS_PARENT:
11399            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11400            break;
11401        case AXIS_PRECEDING:
11402            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11403            break;
11404        case AXIS_PRECEDING_SIBLING:
11405            xmlGenericError(xmlGenericErrorContext,
11406                            "axis 'preceding-sibling' ");
11407            break;
11408        case AXIS_SELF:
11409            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11410            break;
11411    }
11412    xmlGenericError(xmlGenericErrorContext,
11413	" context contains %d nodes\n", nbNodes);
11414    switch (test) {
11415        case NODE_TEST_NONE:
11416            xmlGenericError(xmlGenericErrorContext,
11417                            "           searching for none !!!\n");
11418            break;
11419        case NODE_TEST_TYPE:
11420            xmlGenericError(xmlGenericErrorContext,
11421                            "           searching for type %d\n", type);
11422            break;
11423        case NODE_TEST_PI:
11424            xmlGenericError(xmlGenericErrorContext,
11425                            "           searching for PI !!!\n");
11426            break;
11427        case NODE_TEST_ALL:
11428            xmlGenericError(xmlGenericErrorContext,
11429                            "           searching for *\n");
11430            break;
11431        case NODE_TEST_NS:
11432            xmlGenericError(xmlGenericErrorContext,
11433                            "           searching for namespace %s\n",
11434                            prefix);
11435            break;
11436        case NODE_TEST_NAME:
11437            xmlGenericError(xmlGenericErrorContext,
11438                            "           searching for name %s\n", name);
11439            if (prefix != NULL)
11440                xmlGenericError(xmlGenericErrorContext,
11441                                "           with namespace %s\n", prefix);
11442            break;
11443    }
11444    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11445}
11446#endif /* DEBUG_STEP */
11447
11448static int
11449xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11450			    xmlXPathStepOpPtr op,
11451			    xmlNodeSetPtr set,
11452			    int contextSize,
11453			    int hasNsNodes)
11454{
11455    if (op->ch1 != -1) {
11456	xmlXPathCompExprPtr comp = ctxt->comp;
11457	/*
11458	* Process inner predicates first.
11459	*/
11460	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11461	    /*
11462	    * TODO: raise an internal error.
11463	    */
11464	}
11465	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11466	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11467	CHECK_ERROR0;
11468	if (contextSize <= 0)
11469	    return(0);
11470    }
11471    if (op->ch2 != -1) {
11472	xmlXPathContextPtr xpctxt = ctxt->context;
11473	xmlNodePtr contextNode, oldContextNode;
11474	xmlDocPtr oldContextDoc;
11475	int i, res, contextPos = 0, newContextSize;
11476	xmlXPathStepOpPtr exprOp;
11477	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11478
11479#ifdef LIBXML_XPTR_ENABLED
11480	/*
11481	* URGENT TODO: Check the following:
11482	*  We don't expect location sets if evaluating prediates, right?
11483	*  Only filters should expect location sets, right?
11484	*/
11485#endif
11486	/*
11487	* SPEC XPath 1.0:
11488	*  "For each node in the node-set to be filtered, the
11489	*  PredicateExpr is evaluated with that node as the
11490	*  context node, with the number of nodes in the
11491	*  node-set as the context size, and with the proximity
11492	*  position of the node in the node-set with respect to
11493	*  the axis as the context position;"
11494	* @oldset is the node-set" to be filtered.
11495	*
11496	* SPEC XPath 1.0:
11497	*  "only predicates change the context position and
11498	*  context size (see [2.4 Predicates])."
11499	* Example:
11500	*   node-set  context pos
11501	*    nA         1
11502	*    nB         2
11503	*    nC         3
11504	*   After applying predicate [position() > 1] :
11505	*   node-set  context pos
11506	*    nB         1
11507	*    nC         2
11508	*/
11509	oldContextNode = xpctxt->node;
11510	oldContextDoc = xpctxt->doc;
11511	/*
11512	* Get the expression of this predicate.
11513	*/
11514	exprOp = &ctxt->comp->steps[op->ch2];
11515	newContextSize = 0;
11516	for (i = 0; i < set->nodeNr; i++) {
11517	    if (set->nodeTab[i] == NULL)
11518		continue;
11519
11520	    contextNode = set->nodeTab[i];
11521	    xpctxt->node = contextNode;
11522	    xpctxt->contextSize = contextSize;
11523	    xpctxt->proximityPosition = ++contextPos;
11524
11525	    /*
11526	    * Also set the xpath document in case things like
11527	    * key() are evaluated in the predicate.
11528	    */
11529	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11530		(contextNode->doc != NULL))
11531		xpctxt->doc = contextNode->doc;
11532	    /*
11533	    * Evaluate the predicate expression with 1 context node
11534	    * at a time; this node is packaged into a node set; this
11535	    * node set is handed over to the evaluation mechanism.
11536	    */
11537	    if (contextObj == NULL)
11538		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11539	    else
11540		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11541		    contextNode);
11542
11543	    valuePush(ctxt, contextObj);
11544
11545	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11546
11547	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
11548		goto evaluation_error;
11549
11550	    if (res != 0) {
11551		newContextSize++;
11552	    } else {
11553		/*
11554		* Remove the entry from the initial node set.
11555		*/
11556		set->nodeTab[i] = NULL;
11557		if (contextNode->type == XML_NAMESPACE_DECL)
11558		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11559	    }
11560	    if (ctxt->value == contextObj) {
11561		/*
11562		* Don't free the temporary XPath object holding the
11563		* context node, in order to avoid massive recreation
11564		* inside this loop.
11565		*/
11566		valuePop(ctxt);
11567		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11568	    } else {
11569		/*
11570		* TODO: The object was lost in the evaluation machinery.
11571		*  Can this happen? Maybe in internal-error cases.
11572		*/
11573		contextObj = NULL;
11574	    }
11575	}
11576	goto evaluation_exit;
11577
11578evaluation_error:
11579	xmlXPathNodeSetClear(set, hasNsNodes);
11580	newContextSize = 0;
11581
11582evaluation_exit:
11583	if (contextObj != NULL) {
11584	    if (ctxt->value == contextObj)
11585		valuePop(ctxt);
11586	    xmlXPathReleaseObject(xpctxt, contextObj);
11587	}
11588	if (exprRes != NULL)
11589	    xmlXPathReleaseObject(ctxt->context, exprRes);
11590	/*
11591	* Reset/invalidate the context.
11592	*/
11593	xpctxt->node = oldContextNode;
11594	xpctxt->doc = oldContextDoc;
11595	xpctxt->contextSize = -1;
11596	xpctxt->proximityPosition = -1;
11597	return(newContextSize);
11598    }
11599    return(contextSize);
11600}
11601
11602static int
11603xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11604				      xmlXPathStepOpPtr op,
11605				      xmlNodeSetPtr set,
11606				      int contextSize,
11607				      int minPos,
11608				      int maxPos,
11609				      int hasNsNodes)
11610{
11611    if (op->ch1 != -1) {
11612	xmlXPathCompExprPtr comp = ctxt->comp;
11613	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11614	    /*
11615	    * TODO: raise an internal error.
11616	    */
11617	}
11618	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11619	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11620	CHECK_ERROR0;
11621	if (contextSize <= 0)
11622	    return(0);
11623    }
11624    /*
11625    * Check if the node set contains a sufficient number of nodes for
11626    * the requested range.
11627    */
11628    if (contextSize < minPos) {
11629	xmlXPathNodeSetClear(set, hasNsNodes);
11630	return(0);
11631    }
11632    if (op->ch2 == -1) {
11633	/*
11634	* TODO: Can this ever happen?
11635	*/
11636	return (contextSize);
11637    } else {
11638	xmlDocPtr oldContextDoc;
11639	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11640	xmlXPathStepOpPtr exprOp;
11641	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11642	xmlNodePtr oldContextNode, contextNode = NULL;
11643	xmlXPathContextPtr xpctxt = ctxt->context;
11644
11645#ifdef LIBXML_XPTR_ENABLED
11646	    /*
11647	    * URGENT TODO: Check the following:
11648	    *  We don't expect location sets if evaluating prediates, right?
11649	    *  Only filters should expect location sets, right?
11650	*/
11651#endif /* LIBXML_XPTR_ENABLED */
11652
11653	/*
11654	* Save old context.
11655	*/
11656	oldContextNode = xpctxt->node;
11657	oldContextDoc = xpctxt->doc;
11658	/*
11659	* Get the expression of this predicate.
11660	*/
11661	exprOp = &ctxt->comp->steps[op->ch2];
11662	for (i = 0; i < set->nodeNr; i++) {
11663	    if (set->nodeTab[i] == NULL)
11664		continue;
11665
11666	    contextNode = set->nodeTab[i];
11667	    xpctxt->node = contextNode;
11668	    xpctxt->contextSize = contextSize;
11669	    xpctxt->proximityPosition = ++contextPos;
11670
11671	    /*
11672	    * Initialize the new set.
11673	    * Also set the xpath document in case things like
11674	    * key() evaluation are attempted on the predicate
11675	    */
11676	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11677		(contextNode->doc != NULL))
11678		xpctxt->doc = contextNode->doc;
11679	    /*
11680	    * Evaluate the predicate expression with 1 context node
11681	    * at a time; this node is packaged into a node set; this
11682	    * node set is handed over to the evaluation mechanism.
11683	    */
11684	    if (contextObj == NULL)
11685		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11686	    else
11687		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11688		    contextNode);
11689
11690	    valuePush(ctxt, contextObj);
11691	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11692
11693	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
11694		goto evaluation_error;
11695
11696	    if (res)
11697		pos++;
11698
11699	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11700		/*
11701		* Fits in the requested range.
11702		*/
11703		newContextSize++;
11704		if (minPos == maxPos) {
11705		    /*
11706		    * Only 1 node was requested.
11707		    */
11708		    if (contextNode->type == XML_NAMESPACE_DECL) {
11709			/*
11710			* As always: take care of those nasty
11711			* namespace nodes.
11712			*/
11713			set->nodeTab[i] = NULL;
11714		    }
11715		    xmlXPathNodeSetClear(set, hasNsNodes);
11716		    set->nodeNr = 1;
11717		    set->nodeTab[0] = contextNode;
11718		    goto evaluation_exit;
11719		}
11720		if (pos == maxPos) {
11721		    /*
11722		    * We are done.
11723		    */
11724		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11725		    goto evaluation_exit;
11726		}
11727	    } else {
11728		/*
11729		* Remove the entry from the initial node set.
11730		*/
11731		set->nodeTab[i] = NULL;
11732		if (contextNode->type == XML_NAMESPACE_DECL)
11733		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11734	    }
11735	    if (exprRes != NULL) {
11736		xmlXPathReleaseObject(ctxt->context, exprRes);
11737		exprRes = NULL;
11738	    }
11739	    if (ctxt->value == contextObj) {
11740		/*
11741		* Don't free the temporary XPath object holding the
11742		* context node, in order to avoid massive recreation
11743		* inside this loop.
11744		*/
11745		valuePop(ctxt);
11746		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11747	    } else {
11748		/*
11749		* The object was lost in the evaluation machinery.
11750		* Can this happen? Maybe in case of internal-errors.
11751		*/
11752		contextObj = NULL;
11753	    }
11754	}
11755	goto evaluation_exit;
11756
11757evaluation_error:
11758	xmlXPathNodeSetClear(set, hasNsNodes);
11759	newContextSize = 0;
11760
11761evaluation_exit:
11762	if (contextObj != NULL) {
11763	    if (ctxt->value == contextObj)
11764		valuePop(ctxt);
11765	    xmlXPathReleaseObject(xpctxt, contextObj);
11766	}
11767	if (exprRes != NULL)
11768	    xmlXPathReleaseObject(ctxt->context, exprRes);
11769	/*
11770	* Reset/invalidate the context.
11771	*/
11772	xpctxt->node = oldContextNode;
11773	xpctxt->doc = oldContextDoc;
11774	xpctxt->contextSize = -1;
11775	xpctxt->proximityPosition = -1;
11776	return(newContextSize);
11777    }
11778    return(contextSize);
11779}
11780
11781static int
11782xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11783			    xmlXPathStepOpPtr op,
11784			    int *maxPos)
11785{
11786
11787    xmlXPathStepOpPtr exprOp;
11788
11789    /*
11790    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11791    */
11792
11793    /*
11794    * If not -1, then ch1 will point to:
11795    * 1) For predicates (XPATH_OP_PREDICATE):
11796    *    - an inner predicate operator
11797    * 2) For filters (XPATH_OP_FILTER):
11798    *    - an inner filter operater OR
11799    *    - an expression selecting the node set.
11800    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11801    */
11802    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11803	return(0);
11804
11805    if (op->ch2 != -1) {
11806	exprOp = &ctxt->comp->steps[op->ch2];
11807    } else
11808	return(0);
11809
11810    if ((exprOp != NULL) &&
11811	(exprOp->op == XPATH_OP_VALUE) &&
11812	(exprOp->value4 != NULL) &&
11813	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11814    {
11815	/*
11816	* We have a "[n]" predicate here.
11817	* TODO: Unfortunately this simplistic test here is not
11818	* able to detect a position() predicate in compound
11819	* expressions like "[@attr = 'a" and position() = 1],
11820	* and even not the usage of position() in
11821	* "[position() = 1]"; thus - obviously - a position-range,
11822	* like it "[position() < 5]", is also not detected.
11823	* Maybe we could rewrite the AST to ease the optimization.
11824	*/
11825	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11826
11827	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11828	    (float) *maxPos)
11829	{
11830	    return(1);
11831	}
11832    }
11833    return(0);
11834}
11835
11836static int
11837xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11838                           xmlXPathStepOpPtr op,
11839			   xmlNodePtr * first, xmlNodePtr * last,
11840			   int toBool)
11841{
11842
11843#define XP_TEST_HIT \
11844    if (hasAxisRange != 0) { \
11845	if (++pos == maxPos) { \
11846	    addNode(seq, cur); \
11847	goto axis_range_end; } \
11848    } else { \
11849	addNode(seq, cur); \
11850	if (breakOnFirstHit) goto first_hit; }
11851
11852#define XP_TEST_HIT_NS \
11853    if (hasAxisRange != 0) { \
11854	if (++pos == maxPos) { \
11855	    hasNsNodes = 1; \
11856	    xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11857	goto axis_range_end; } \
11858    } else { \
11859	hasNsNodes = 1; \
11860	xmlXPathNodeSetAddNs(seq, \
11861	xpctxt->node, (xmlNsPtr) cur); \
11862	if (breakOnFirstHit) goto first_hit; }
11863
11864    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11865    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11866    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11867    const xmlChar *prefix = op->value4;
11868    const xmlChar *name = op->value5;
11869    const xmlChar *URI = NULL;
11870
11871#ifdef DEBUG_STEP
11872    int nbMatches = 0, prevMatches = 0;
11873#endif
11874    int total = 0, hasNsNodes = 0;
11875    /* The popped object holding the context nodes */
11876    xmlXPathObjectPtr obj;
11877    /* The set of context nodes for the node tests */
11878    xmlNodeSetPtr contextSeq;
11879    int contextIdx;
11880    xmlNodePtr contextNode;
11881    /* The context node for a compound traversal */
11882    xmlNodePtr outerContextNode;
11883    /* The final resulting node set wrt to all context nodes */
11884    xmlNodeSetPtr outSeq;
11885    /*
11886    * The temporary resulting node set wrt 1 context node.
11887    * Used to feed predicate evaluation.
11888    */
11889    xmlNodeSetPtr seq;
11890    xmlNodePtr cur;
11891    /* First predicate operator */
11892    xmlXPathStepOpPtr predOp;
11893    int maxPos; /* The requested position() (when a "[n]" predicate) */
11894    int hasPredicateRange, hasAxisRange, pos, size, newSize;
11895    int breakOnFirstHit;
11896
11897    xmlXPathTraversalFunction next = NULL;
11898    /* compound axis traversal */
11899    xmlXPathTraversalFunctionExt outerNext = NULL;
11900    void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11901    xmlXPathNodeSetMergeFunction mergeAndClear;
11902    xmlNodePtr oldContextNode;
11903    xmlXPathContextPtr xpctxt = ctxt->context;
11904
11905
11906    CHECK_TYPE0(XPATH_NODESET);
11907    obj = valuePop(ctxt);
11908    /*
11909    * Setup namespaces.
11910    */
11911    if (prefix != NULL) {
11912        URI = xmlXPathNsLookup(xpctxt, prefix);
11913        if (URI == NULL) {
11914	    xmlXPathReleaseObject(xpctxt, obj);
11915            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11916	}
11917    }
11918    /*
11919    * Setup axis.
11920    *
11921    * MAYBE FUTURE TODO: merging optimizations:
11922    * - If the nodes to be traversed wrt to the initial nodes and
11923    *   the current axis cannot overlap, then we could avoid searching
11924    *   for duplicates during the merge.
11925    *   But the question is how/when to evaluate if they cannot overlap.
11926    *   Example: if we know that for two initial nodes, the one is
11927    *   not in the ancestor-or-self axis of the other, then we could safely
11928    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11929    *   the descendant-or-self axis.
11930    */
11931    addNode = xmlXPathNodeSetAdd;
11932    mergeAndClear = xmlXPathNodeSetMergeAndClear;
11933    switch (axis) {
11934        case AXIS_ANCESTOR:
11935            first = NULL;
11936            next = xmlXPathNextAncestor;
11937            break;
11938        case AXIS_ANCESTOR_OR_SELF:
11939            first = NULL;
11940            next = xmlXPathNextAncestorOrSelf;
11941            break;
11942        case AXIS_ATTRIBUTE:
11943            first = NULL;
11944	    last = NULL;
11945            next = xmlXPathNextAttribute;
11946	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11947            break;
11948        case AXIS_CHILD:
11949	    last = NULL;
11950	    if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11951		/*
11952		* This iterator will give us only nodes which can
11953		* hold element nodes.
11954		*/
11955		outerNext = xmlXPathNextDescendantOrSelfElemParent;
11956	    }
11957	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11958		(type == NODE_TYPE_NODE))
11959	    {
11960		/*
11961		* Optimization if an element node type is 'element'.
11962		*/
11963		next = xmlXPathNextChildElement;
11964	    } else
11965		next = xmlXPathNextChild;
11966	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11967            break;
11968        case AXIS_DESCENDANT:
11969	    last = NULL;
11970            next = xmlXPathNextDescendant;
11971            break;
11972        case AXIS_DESCENDANT_OR_SELF:
11973	    last = NULL;
11974            next = xmlXPathNextDescendantOrSelf;
11975            break;
11976        case AXIS_FOLLOWING:
11977	    last = NULL;
11978            next = xmlXPathNextFollowing;
11979            break;
11980        case AXIS_FOLLOWING_SIBLING:
11981	    last = NULL;
11982            next = xmlXPathNextFollowingSibling;
11983            break;
11984        case AXIS_NAMESPACE:
11985            first = NULL;
11986	    last = NULL;
11987            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11988	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11989            break;
11990        case AXIS_PARENT:
11991            first = NULL;
11992            next = xmlXPathNextParent;
11993            break;
11994        case AXIS_PRECEDING:
11995            first = NULL;
11996            next = xmlXPathNextPrecedingInternal;
11997            break;
11998        case AXIS_PRECEDING_SIBLING:
11999            first = NULL;
12000            next = xmlXPathNextPrecedingSibling;
12001            break;
12002        case AXIS_SELF:
12003            first = NULL;
12004	    last = NULL;
12005            next = xmlXPathNextSelf;
12006	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12007            break;
12008    }
12009
12010#ifdef DEBUG_STEP
12011    xmlXPathDebugDumpStepAxis(axis, test,
12012	(obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0);
12013#endif
12014
12015    if (next == NULL) {
12016	xmlXPathReleaseObject(xpctxt, obj);
12017        return(0);
12018    }
12019    contextSeq = obj->nodesetval;
12020    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12021	xmlXPathReleaseObject(xpctxt, obj);
12022        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12023        return(0);
12024    }
12025    /*
12026    * Predicate optimization ---------------------------------------------
12027    * If this step has a last predicate, which contains a position(),
12028    * then we'll optimize (although not exactly "position()", but only
12029    * the  short-hand form, i.e., "[n]".
12030    *
12031    * Example - expression "/foo[parent::bar][1]":
12032    *
12033    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12034    *   ROOT                               -- op->ch1
12035    *   PREDICATE                          -- op->ch2 (predOp)
12036    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12037    *       SORT
12038    *         COLLECT  'parent' 'name' 'node' bar
12039    *           NODE
12040    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12041    *
12042    */
12043    maxPos = 0;
12044    predOp = NULL;
12045    hasPredicateRange = 0;
12046    hasAxisRange = 0;
12047    if (op->ch2 != -1) {
12048	/*
12049	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12050	*/
12051	predOp = &ctxt->comp->steps[op->ch2];
12052	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12053	    if (predOp->ch1 != -1) {
12054		/*
12055		* Use the next inner predicate operator.
12056		*/
12057		predOp = &ctxt->comp->steps[predOp->ch1];
12058		hasPredicateRange = 1;
12059	    } else {
12060		/*
12061		* There's no other predicate than the [n] predicate.
12062		*/
12063		predOp = NULL;
12064		hasAxisRange = 1;
12065	    }
12066	}
12067    }
12068    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12069    /*
12070    * Axis traversal -----------------------------------------------------
12071    */
12072    /*
12073     * 2.3 Node Tests
12074     *  - For the attribute axis, the principal node type is attribute.
12075     *  - For the namespace axis, the principal node type is namespace.
12076     *  - For other axes, the principal node type is element.
12077     *
12078     * A node test * is true for any node of the
12079     * principal node type. For example, child::* will
12080     * select all element children of the context node
12081     */
12082    oldContextNode = xpctxt->node;
12083    addNode = xmlXPathNodeSetAddUnique;
12084    outSeq = NULL;
12085    seq = NULL;
12086    outerContextNode = NULL;
12087    contextNode = NULL;
12088    contextIdx = 0;
12089
12090
12091    while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12092	if (outerNext != NULL) {
12093	    /*
12094	    * This is a compound traversal.
12095	    */
12096	    if (contextNode == NULL) {
12097		/*
12098		* Set the context for the outer traversal.
12099		*/
12100		outerContextNode = contextSeq->nodeTab[contextIdx++];
12101		contextNode = outerNext(NULL, outerContextNode);
12102	    } else
12103		contextNode = outerNext(contextNode, outerContextNode);
12104	    if (contextNode == NULL)
12105		continue;
12106	    /*
12107	    * Set the context for the main traversal.
12108	    */
12109	    xpctxt->node = contextNode;
12110	} else
12111	    xpctxt->node = contextSeq->nodeTab[contextIdx++];
12112
12113	if (seq == NULL) {
12114	    seq = xmlXPathNodeSetCreate(NULL);
12115	    if (seq == NULL) {
12116		total = 0;
12117		goto error;
12118	    }
12119	}
12120	/*
12121	* Traverse the axis and test the nodes.
12122	*/
12123	pos = 0;
12124	cur = NULL;
12125	hasNsNodes = 0;
12126        do {
12127            cur = next(ctxt, cur);
12128            if (cur == NULL)
12129                break;
12130
12131	    /*
12132	    * QUESTION TODO: What does the "first" and "last" stuff do?
12133	    */
12134            if ((first != NULL) && (*first != NULL)) {
12135		if (*first == cur)
12136		    break;
12137		if (((total % 256) == 0) &&
12138#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12139		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12140#else
12141		    (xmlXPathCmpNodes(*first, cur) >= 0))
12142#endif
12143		{
12144		    break;
12145		}
12146	    }
12147	    if ((last != NULL) && (*last != NULL)) {
12148		if (*last == cur)
12149		    break;
12150		if (((total % 256) == 0) &&
12151#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12152		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12153#else
12154		    (xmlXPathCmpNodes(cur, *last) >= 0))
12155#endif
12156		{
12157		    break;
12158		}
12159	    }
12160
12161            total++;
12162
12163#ifdef DEBUG_STEP
12164            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12165#endif
12166	    switch (test) {
12167                case NODE_TEST_NONE:
12168		    total = 0;
12169                    STRANGE
12170		    goto error;
12171                case NODE_TEST_TYPE:
12172		    /*
12173		    * TODO: Don't we need to use
12174		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
12175		    *  Surprisingly, some c14n tests fail, if we do this.
12176		    */
12177		    if (type == NODE_TYPE_NODE) {
12178			switch (cur->type) {
12179			    case XML_DOCUMENT_NODE:
12180			    case XML_HTML_DOCUMENT_NODE:
12181#ifdef LIBXML_DOCB_ENABLED
12182			    case XML_DOCB_DOCUMENT_NODE:
12183#endif
12184			    case XML_ELEMENT_NODE:
12185			    case XML_ATTRIBUTE_NODE:
12186			    case XML_PI_NODE:
12187			    case XML_COMMENT_NODE:
12188			    case XML_CDATA_SECTION_NODE:
12189			    case XML_TEXT_NODE:
12190			    case XML_NAMESPACE_DECL:
12191				XP_TEST_HIT
12192				break;
12193			    default:
12194				break;
12195			}
12196		    } else if (cur->type == type) {
12197			if (type == XML_NAMESPACE_DECL)
12198			    XP_TEST_HIT_NS
12199			else
12200			    XP_TEST_HIT
12201		    } else if ((type == NODE_TYPE_TEXT) &&
12202			 (cur->type == XML_CDATA_SECTION_NODE))
12203		    {
12204			XP_TEST_HIT
12205		    }
12206		    break;
12207                case NODE_TEST_PI:
12208                    if ((cur->type == XML_PI_NODE) &&
12209                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12210		    {
12211			XP_TEST_HIT
12212                    }
12213                    break;
12214                case NODE_TEST_ALL:
12215                    if (axis == AXIS_ATTRIBUTE) {
12216                        if (cur->type == XML_ATTRIBUTE_NODE)
12217			{
12218			    XP_TEST_HIT
12219                        }
12220                    } else if (axis == AXIS_NAMESPACE) {
12221                        if (cur->type == XML_NAMESPACE_DECL)
12222			{
12223			    XP_TEST_HIT_NS
12224                        }
12225                    } else {
12226                        if (cur->type == XML_ELEMENT_NODE) {
12227                            if (prefix == NULL)
12228			    {
12229				XP_TEST_HIT
12230
12231                            } else if ((cur->ns != NULL) &&
12232				(xmlStrEqual(URI, cur->ns->href)))
12233			    {
12234				XP_TEST_HIT
12235                            }
12236                        }
12237                    }
12238                    break;
12239                case NODE_TEST_NS:{
12240                        TODO;
12241                        break;
12242                    }
12243                case NODE_TEST_NAME:
12244                    switch (cur->type) {
12245                        case XML_ELEMENT_NODE:
12246                            if (xmlStrEqual(name, cur->name)) {
12247                                if (prefix == NULL) {
12248                                    if (cur->ns == NULL)
12249				    {
12250					XP_TEST_HIT
12251                                    }
12252                                } else {
12253                                    if ((cur->ns != NULL) &&
12254                                        (xmlStrEqual(URI, cur->ns->href)))
12255				    {
12256					XP_TEST_HIT
12257                                    }
12258                                }
12259                            }
12260                            break;
12261                        case XML_ATTRIBUTE_NODE:{
12262                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12263
12264                                if (xmlStrEqual(name, attr->name)) {
12265                                    if (prefix == NULL) {
12266                                        if ((attr->ns == NULL) ||
12267                                            (attr->ns->prefix == NULL))
12268					{
12269					    XP_TEST_HIT
12270                                        }
12271                                    } else {
12272                                        if ((attr->ns != NULL) &&
12273                                            (xmlStrEqual(URI,
12274					      attr->ns->href)))
12275					{
12276					    XP_TEST_HIT
12277                                        }
12278                                    }
12279                                }
12280                                break;
12281                            }
12282                        case XML_NAMESPACE_DECL:
12283                            if (cur->type == XML_NAMESPACE_DECL) {
12284                                xmlNsPtr ns = (xmlNsPtr) cur;
12285
12286                                if ((ns->prefix != NULL) && (name != NULL)
12287                                    && (xmlStrEqual(ns->prefix, name)))
12288				{
12289				    XP_TEST_HIT_NS
12290                                }
12291                            }
12292                            break;
12293                        default:
12294                            break;
12295                    }
12296                    break;
12297	    } /* switch(test) */
12298        } while (cur != NULL);
12299
12300	goto apply_predicates;
12301
12302axis_range_end: /* ----------------------------------------------------- */
12303	/*
12304	* We have a "/foo[n]", and position() = n was reached.
12305	* Note that we can have as well "/foo/::parent::foo[1]", so
12306	* a duplicate-aware merge is still needed.
12307	* Merge with the result.
12308	*/
12309	if (outSeq == NULL) {
12310	    outSeq = seq;
12311	    seq = NULL;
12312	} else
12313	    outSeq = mergeAndClear(outSeq, seq, 0);
12314	/*
12315	* Break if only a true/false result was requested.
12316	*/
12317	if (toBool)
12318	    break;
12319	continue;
12320
12321first_hit: /* ---------------------------------------------------------- */
12322	/*
12323	* Break if only a true/false result was requested and
12324	* no predicates existed and a node test succeeded.
12325	*/
12326	if (outSeq == NULL) {
12327	    outSeq = seq;
12328	    seq = NULL;
12329	} else
12330	    outSeq = mergeAndClear(outSeq, seq, 0);
12331	break;
12332
12333#ifdef DEBUG_STEP
12334	if (seq != NULL)
12335	    nbMatches += seq->nodeNr;
12336#endif
12337
12338apply_predicates: /* --------------------------------------------------- */
12339        /*
12340	* Apply predicates.
12341	*/
12342        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12343	    /*
12344	    * E.g. when we have a "/foo[some expression][n]".
12345	    */
12346	    /*
12347	    * QUESTION TODO: The old predicate evaluation took into
12348	    *  account location-sets.
12349	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12350	    *  Do we expect such a set here?
12351	    *  All what I learned now from the evaluation semantics
12352	    *  does not indicate that a location-set will be processed
12353	    *  here, so this looks OK.
12354	    */
12355	    /*
12356	    * Iterate over all predicates, starting with the outermost
12357	    * predicate.
12358	    * TODO: Problem: we cannot execute the inner predicates first
12359	    *  since we cannot go back *up* the operator tree!
12360	    *  Options we have:
12361	    *  1) Use of recursive functions (like is it currently done
12362	    *     via xmlXPathCompOpEval())
12363	    *  2) Add a predicate evaluation information stack to the
12364	    *     context struct
12365	    *  3) Change the way the operators are linked; we need a
12366	    *     "parent" field on xmlXPathStepOp
12367	    *
12368	    * For the moment, I'll try to solve this with a recursive
12369	    * function: xmlXPathCompOpEvalPredicate().
12370	    */
12371	    size = seq->nodeNr;
12372	    if (hasPredicateRange != 0)
12373		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12374		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12375	    else
12376		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12377		    predOp, seq, size, hasNsNodes);
12378
12379	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12380		total = 0;
12381		goto error;
12382	    }
12383	    /*
12384	    * Add the filtered set of nodes to the result node set.
12385	    */
12386	    if (newSize == 0) {
12387		/*
12388		* The predicates filtered all nodes out.
12389		*/
12390		xmlXPathNodeSetClear(seq, hasNsNodes);
12391	    } else if (seq->nodeNr > 0) {
12392		/*
12393		* Add to result set.
12394		*/
12395		if (outSeq == NULL) {
12396		    if (size != newSize) {
12397			/*
12398			* We need to merge and clear here, since
12399			* the sequence will contained NULLed entries.
12400			*/
12401			outSeq = mergeAndClear(NULL, seq, 1);
12402		    } else {
12403			outSeq = seq;
12404			seq = NULL;
12405		    }
12406		} else
12407		    outSeq = mergeAndClear(outSeq, seq,
12408			(size != newSize) ? 1: 0);
12409		/*
12410		* Break if only a true/false result was requested.
12411		*/
12412		if (toBool)
12413		    break;
12414	    }
12415        } else if (seq->nodeNr > 0) {
12416	    /*
12417	    * Add to result set.
12418	    */
12419	    if (outSeq == NULL) {
12420		outSeq = seq;
12421		seq = NULL;
12422	    } else {
12423		outSeq = mergeAndClear(outSeq, seq, 0);
12424	    }
12425	}
12426    }
12427
12428error:
12429    if ((obj->boolval) && (obj->user != NULL)) {
12430	/*
12431	* QUESTION TODO: What does this do and why?
12432	* TODO: Do we have to do this also for the "error"
12433	* cleanup further down?
12434	*/
12435	ctxt->value->boolval = 1;
12436	ctxt->value->user = obj->user;
12437	obj->user = NULL;
12438	obj->boolval = 0;
12439    }
12440    xmlXPathReleaseObject(xpctxt, obj);
12441
12442    /*
12443    * Ensure we return at least an emtpy set.
12444    */
12445    if (outSeq == NULL) {
12446	if ((seq != NULL) && (seq->nodeNr == 0))
12447	    outSeq = seq;
12448	else
12449	    outSeq = xmlXPathNodeSetCreate(NULL);
12450    }
12451    if ((seq != NULL) && (seq != outSeq)) {
12452	 xmlXPathFreeNodeSet(seq);
12453    }
12454    /*
12455    * Hand over the result. Better to push the set also in
12456    * case of errors.
12457    */
12458    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12459    /*
12460    * Reset the context node.
12461    */
12462    xpctxt->node = oldContextNode;
12463
12464#ifdef DEBUG_STEP
12465    xmlGenericError(xmlGenericErrorContext,
12466	"\nExamined %d nodes, found %d nodes at that step\n",
12467	total, nbMatches);
12468#endif
12469
12470    return(total);
12471}
12472
12473static int
12474xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12475			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12476
12477/**
12478 * xmlXPathCompOpEvalFirst:
12479 * @ctxt:  the XPath parser context with the compiled expression
12480 * @op:  an XPath compiled operation
12481 * @first:  the first elem found so far
12482 *
12483 * Evaluate the Precompiled XPath operation searching only the first
12484 * element in document order
12485 *
12486 * Returns the number of examined objects.
12487 */
12488static int
12489xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12490                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12491{
12492    int total = 0, cur;
12493    xmlXPathCompExprPtr comp;
12494    xmlXPathObjectPtr arg1, arg2;
12495
12496    CHECK_ERROR0;
12497    comp = ctxt->comp;
12498    switch (op->op) {
12499        case XPATH_OP_END:
12500            return (0);
12501        case XPATH_OP_UNION:
12502            total =
12503                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12504                                        first);
12505	    CHECK_ERROR0;
12506            if ((ctxt->value != NULL)
12507                && (ctxt->value->type == XPATH_NODESET)
12508                && (ctxt->value->nodesetval != NULL)
12509                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12510                /*
12511                 * limit tree traversing to first node in the result
12512                 */
12513		/*
12514		* OPTIMIZE TODO: This implicitely sorts
12515		*  the result, even if not needed. E.g. if the argument
12516		*  of the count() function, no sorting is needed.
12517		* OPTIMIZE TODO: How do we know if the node-list wasn't
12518		*  aready sorted?
12519		*/
12520		if (ctxt->value->nodesetval->nodeNr > 1)
12521		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12522                *first = ctxt->value->nodesetval->nodeTab[0];
12523            }
12524            cur =
12525                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12526                                        first);
12527	    CHECK_ERROR0;
12528            CHECK_TYPE0(XPATH_NODESET);
12529            arg2 = valuePop(ctxt);
12530
12531            CHECK_TYPE0(XPATH_NODESET);
12532            arg1 = valuePop(ctxt);
12533
12534            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12535                                                    arg2->nodesetval);
12536            valuePush(ctxt, arg1);
12537	    xmlXPathReleaseObject(ctxt->context, arg2);
12538            /* optimizer */
12539	    if (total > cur)
12540		xmlXPathCompSwap(op);
12541            return (total + cur);
12542        case XPATH_OP_ROOT:
12543            xmlXPathRoot(ctxt);
12544            return (0);
12545        case XPATH_OP_NODE:
12546            if (op->ch1 != -1)
12547                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12548	    CHECK_ERROR0;
12549            if (op->ch2 != -1)
12550                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12551	    CHECK_ERROR0;
12552	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12553		ctxt->context->node));
12554            return (total);
12555        case XPATH_OP_RESET:
12556            if (op->ch1 != -1)
12557                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12558	    CHECK_ERROR0;
12559            if (op->ch2 != -1)
12560                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12561	    CHECK_ERROR0;
12562            ctxt->context->node = NULL;
12563            return (total);
12564        case XPATH_OP_COLLECT:{
12565                if (op->ch1 == -1)
12566                    return (total);
12567
12568                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12569		CHECK_ERROR0;
12570
12571                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12572                return (total);
12573            }
12574        case XPATH_OP_VALUE:
12575            valuePush(ctxt,
12576                      xmlXPathCacheObjectCopy(ctxt->context,
12577			(xmlXPathObjectPtr) op->value4));
12578            return (0);
12579        case XPATH_OP_SORT:
12580            if (op->ch1 != -1)
12581                total +=
12582                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12583                                            first);
12584	    CHECK_ERROR0;
12585            if ((ctxt->value != NULL)
12586                && (ctxt->value->type == XPATH_NODESET)
12587                && (ctxt->value->nodesetval != NULL)
12588		&& (ctxt->value->nodesetval->nodeNr > 1))
12589                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12590            return (total);
12591#ifdef XP_OPTIMIZED_FILTER_FIRST
12592	case XPATH_OP_FILTER:
12593                total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12594            return (total);
12595#endif
12596        default:
12597            return (xmlXPathCompOpEval(ctxt, op));
12598    }
12599}
12600
12601/**
12602 * xmlXPathCompOpEvalLast:
12603 * @ctxt:  the XPath parser context with the compiled expression
12604 * @op:  an XPath compiled operation
12605 * @last:  the last elem found so far
12606 *
12607 * Evaluate the Precompiled XPath operation searching only the last
12608 * element in document order
12609 *
12610 * Returns the number of nodes traversed
12611 */
12612static int
12613xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12614                       xmlNodePtr * last)
12615{
12616    int total = 0, cur;
12617    xmlXPathCompExprPtr comp;
12618    xmlXPathObjectPtr arg1, arg2;
12619    xmlNodePtr bak;
12620    xmlDocPtr bakd;
12621    int pp;
12622    int cs;
12623
12624    CHECK_ERROR0;
12625    comp = ctxt->comp;
12626    switch (op->op) {
12627        case XPATH_OP_END:
12628            return (0);
12629        case XPATH_OP_UNION:
12630	    bakd = ctxt->context->doc;
12631	    bak = ctxt->context->node;
12632	    pp = ctxt->context->proximityPosition;
12633	    cs = ctxt->context->contextSize;
12634            total =
12635                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12636	    CHECK_ERROR0;
12637            if ((ctxt->value != NULL)
12638                && (ctxt->value->type == XPATH_NODESET)
12639                && (ctxt->value->nodesetval != NULL)
12640                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12641                /*
12642                 * limit tree traversing to first node in the result
12643                 */
12644		if (ctxt->value->nodesetval->nodeNr > 1)
12645		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12646                *last =
12647                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12648                                                     nodesetval->nodeNr -
12649                                                     1];
12650            }
12651	    ctxt->context->doc = bakd;
12652	    ctxt->context->node = bak;
12653	    ctxt->context->proximityPosition = pp;
12654	    ctxt->context->contextSize = cs;
12655            cur =
12656                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12657	    CHECK_ERROR0;
12658            if ((ctxt->value != NULL)
12659                && (ctxt->value->type == XPATH_NODESET)
12660                && (ctxt->value->nodesetval != NULL)
12661                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12662            }
12663            CHECK_TYPE0(XPATH_NODESET);
12664            arg2 = valuePop(ctxt);
12665
12666            CHECK_TYPE0(XPATH_NODESET);
12667            arg1 = valuePop(ctxt);
12668
12669            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12670                                                    arg2->nodesetval);
12671            valuePush(ctxt, arg1);
12672	    xmlXPathReleaseObject(ctxt->context, arg2);
12673            /* optimizer */
12674	    if (total > cur)
12675		xmlXPathCompSwap(op);
12676            return (total + cur);
12677        case XPATH_OP_ROOT:
12678            xmlXPathRoot(ctxt);
12679            return (0);
12680        case XPATH_OP_NODE:
12681            if (op->ch1 != -1)
12682                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12683	    CHECK_ERROR0;
12684            if (op->ch2 != -1)
12685                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12686	    CHECK_ERROR0;
12687	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12688		ctxt->context->node));
12689            return (total);
12690        case XPATH_OP_RESET:
12691            if (op->ch1 != -1)
12692                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12693	    CHECK_ERROR0;
12694            if (op->ch2 != -1)
12695                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12696	    CHECK_ERROR0;
12697            ctxt->context->node = NULL;
12698            return (total);
12699        case XPATH_OP_COLLECT:{
12700                if (op->ch1 == -1)
12701                    return (0);
12702
12703                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12704		CHECK_ERROR0;
12705
12706                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12707                return (total);
12708            }
12709        case XPATH_OP_VALUE:
12710            valuePush(ctxt,
12711                      xmlXPathCacheObjectCopy(ctxt->context,
12712			(xmlXPathObjectPtr) op->value4));
12713            return (0);
12714        case XPATH_OP_SORT:
12715            if (op->ch1 != -1)
12716                total +=
12717                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12718                                           last);
12719	    CHECK_ERROR0;
12720            if ((ctxt->value != NULL)
12721                && (ctxt->value->type == XPATH_NODESET)
12722                && (ctxt->value->nodesetval != NULL)
12723		&& (ctxt->value->nodesetval->nodeNr > 1))
12724                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12725            return (total);
12726        default:
12727            return (xmlXPathCompOpEval(ctxt, op));
12728    }
12729}
12730
12731#ifdef XP_OPTIMIZED_FILTER_FIRST
12732static int
12733xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12734			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12735{
12736    int total = 0;
12737    xmlXPathCompExprPtr comp;
12738    xmlXPathObjectPtr res;
12739    xmlXPathObjectPtr obj;
12740    xmlNodeSetPtr oldset;
12741    xmlNodePtr oldnode;
12742    xmlDocPtr oldDoc;
12743    int i;
12744
12745    CHECK_ERROR0;
12746    comp = ctxt->comp;
12747    /*
12748    * Optimization for ()[last()] selection i.e. the last elem
12749    */
12750    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12751	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12752	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12753	int f = comp->steps[op->ch2].ch1;
12754
12755	if ((f != -1) &&
12756	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12757	    (comp->steps[f].value5 == NULL) &&
12758	    (comp->steps[f].value == 0) &&
12759	    (comp->steps[f].value4 != NULL) &&
12760	    (xmlStrEqual
12761	    (comp->steps[f].value4, BAD_CAST "last"))) {
12762	    xmlNodePtr last = NULL;
12763
12764	    total +=
12765		xmlXPathCompOpEvalLast(ctxt,
12766		    &comp->steps[op->ch1],
12767		    &last);
12768	    CHECK_ERROR0;
12769	    /*
12770	    * The nodeset should be in document order,
12771	    * Keep only the last value
12772	    */
12773	    if ((ctxt->value != NULL) &&
12774		(ctxt->value->type == XPATH_NODESET) &&
12775		(ctxt->value->nodesetval != NULL) &&
12776		(ctxt->value->nodesetval->nodeTab != NULL) &&
12777		(ctxt->value->nodesetval->nodeNr > 1)) {
12778		ctxt->value->nodesetval->nodeTab[0] =
12779		    ctxt->value->nodesetval->nodeTab[ctxt->
12780		    value->
12781		    nodesetval->
12782		    nodeNr -
12783		    1];
12784		ctxt->value->nodesetval->nodeNr = 1;
12785		*first = *(ctxt->value->nodesetval->nodeTab);
12786	    }
12787	    return (total);
12788	}
12789    }
12790
12791    if (op->ch1 != -1)
12792	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12793    CHECK_ERROR0;
12794    if (op->ch2 == -1)
12795	return (total);
12796    if (ctxt->value == NULL)
12797	return (total);
12798
12799#ifdef LIBXML_XPTR_ENABLED
12800    oldnode = ctxt->context->node;
12801    /*
12802    * Hum are we filtering the result of an XPointer expression
12803    */
12804    if (ctxt->value->type == XPATH_LOCATIONSET) {
12805	xmlXPathObjectPtr tmp = NULL;
12806	xmlLocationSetPtr newlocset = NULL;
12807	xmlLocationSetPtr oldlocset;
12808
12809	/*
12810	* Extract the old locset, and then evaluate the result of the
12811	* expression for all the element in the locset. use it to grow
12812	* up a new locset.
12813	*/
12814	CHECK_TYPE0(XPATH_LOCATIONSET);
12815	obj = valuePop(ctxt);
12816	oldlocset = obj->user;
12817	ctxt->context->node = NULL;
12818
12819	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12820	    ctxt->context->contextSize = 0;
12821	    ctxt->context->proximityPosition = 0;
12822	    if (op->ch2 != -1)
12823		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12824	    res = valuePop(ctxt);
12825	    if (res != NULL) {
12826		xmlXPathReleaseObject(ctxt->context, res);
12827	    }
12828	    valuePush(ctxt, obj);
12829	    CHECK_ERROR0;
12830	    return (total);
12831	}
12832	newlocset = xmlXPtrLocationSetCreate(NULL);
12833
12834	for (i = 0; i < oldlocset->locNr; i++) {
12835	    /*
12836	    * Run the evaluation with a node list made of a
12837	    * single item in the nodelocset.
12838	    */
12839	    ctxt->context->node = oldlocset->locTab[i]->user;
12840	    ctxt->context->contextSize = oldlocset->locNr;
12841	    ctxt->context->proximityPosition = i + 1;
12842	    if (tmp == NULL) {
12843		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12844		    ctxt->context->node);
12845	    } else {
12846		xmlXPathNodeSetAddUnique(tmp->nodesetval,
12847		    ctxt->context->node);
12848	    }
12849	    valuePush(ctxt, tmp);
12850	    if (op->ch2 != -1)
12851		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12852	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12853		xmlXPathFreeObject(obj);
12854		return(0);
12855	    }
12856	    /*
12857	    * The result of the evaluation need to be tested to
12858	    * decided whether the filter succeeded or not
12859	    */
12860	    res = valuePop(ctxt);
12861	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12862		xmlXPtrLocationSetAdd(newlocset,
12863		    xmlXPathCacheObjectCopy(ctxt->context,
12864			oldlocset->locTab[i]));
12865	    }
12866	    /*
12867	    * Cleanup
12868	    */
12869	    if (res != NULL) {
12870		xmlXPathReleaseObject(ctxt->context, res);
12871	    }
12872	    if (ctxt->value == tmp) {
12873		valuePop(ctxt);
12874		xmlXPathNodeSetClear(tmp->nodesetval, 1);
12875		/*
12876		* REVISIT TODO: Don't create a temporary nodeset
12877		* for everly iteration.
12878		*/
12879		/* OLD: xmlXPathFreeObject(res); */
12880	    } else
12881		tmp = NULL;
12882	    ctxt->context->node = NULL;
12883	    /*
12884	    * Only put the first node in the result, then leave.
12885	    */
12886	    if (newlocset->locNr > 0) {
12887		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
12888		break;
12889	    }
12890	}
12891	if (tmp != NULL) {
12892	    xmlXPathReleaseObject(ctxt->context, tmp);
12893	}
12894	/*
12895	* The result is used as the new evaluation locset.
12896	*/
12897	xmlXPathReleaseObject(ctxt->context, obj);
12898	ctxt->context->node = NULL;
12899	ctxt->context->contextSize = -1;
12900	ctxt->context->proximityPosition = -1;
12901	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12902	ctxt->context->node = oldnode;
12903	return (total);
12904    }
12905#endif /* LIBXML_XPTR_ENABLED */
12906
12907    /*
12908    * Extract the old set, and then evaluate the result of the
12909    * expression for all the element in the set. use it to grow
12910    * up a new set.
12911    */
12912    CHECK_TYPE0(XPATH_NODESET);
12913    obj = valuePop(ctxt);
12914    oldset = obj->nodesetval;
12915
12916    oldnode = ctxt->context->node;
12917    oldDoc = ctxt->context->doc;
12918    ctxt->context->node = NULL;
12919
12920    if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12921	ctxt->context->contextSize = 0;
12922	ctxt->context->proximityPosition = 0;
12923	/* QUESTION TODO: Why was this code commented out?
12924	    if (op->ch2 != -1)
12925		total +=
12926		    xmlXPathCompOpEval(ctxt,
12927			&comp->steps[op->ch2]);
12928	    CHECK_ERROR0;
12929	    res = valuePop(ctxt);
12930	    if (res != NULL)
12931		xmlXPathFreeObject(res);
12932	*/
12933	valuePush(ctxt, obj);
12934	ctxt->context->node = oldnode;
12935	CHECK_ERROR0;
12936    } else {
12937	xmlNodeSetPtr newset;
12938	xmlXPathObjectPtr tmp = NULL;
12939	/*
12940	* Initialize the new set.
12941	* Also set the xpath document in case things like
12942	* key() evaluation are attempted on the predicate
12943	*/
12944	newset = xmlXPathNodeSetCreate(NULL);
12945
12946	for (i = 0; i < oldset->nodeNr; i++) {
12947	    /*
12948	    * Run the evaluation with a node list made of
12949	    * a single item in the nodeset.
12950	    */
12951	    ctxt->context->node = oldset->nodeTab[i];
12952	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12953		(oldset->nodeTab[i]->doc != NULL))
12954		ctxt->context->doc = oldset->nodeTab[i]->doc;
12955	    if (tmp == NULL) {
12956		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12957		    ctxt->context->node);
12958	    } else {
12959		xmlXPathNodeSetAddUnique(tmp->nodesetval,
12960		    ctxt->context->node);
12961	    }
12962	    valuePush(ctxt, tmp);
12963	    ctxt->context->contextSize = oldset->nodeNr;
12964	    ctxt->context->proximityPosition = i + 1;
12965	    if (op->ch2 != -1)
12966		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12967	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12968		xmlXPathFreeNodeSet(newset);
12969		xmlXPathFreeObject(obj);
12970		return(0);
12971	    }
12972	    /*
12973	    * The result of the evaluation needs to be tested to
12974	    * decide whether the filter succeeded or not
12975	    */
12976	    res = valuePop(ctxt);
12977	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12978		xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
12979	    }
12980	    /*
12981	    * Cleanup
12982	    */
12983	    if (res != NULL) {
12984		xmlXPathReleaseObject(ctxt->context, res);
12985	    }
12986	    if (ctxt->value == tmp) {
12987		valuePop(ctxt);
12988		/*
12989		* Don't free the temporary nodeset
12990		* in order to avoid massive recreation inside this
12991		* loop.
12992		*/
12993		xmlXPathNodeSetClear(tmp->nodesetval, 1);
12994	    } else
12995		tmp = NULL;
12996	    ctxt->context->node = NULL;
12997	    /*
12998	    * Only put the first node in the result, then leave.
12999	    */
13000	    if (newset->nodeNr > 0) {
13001		*first = *(newset->nodeTab);
13002		break;
13003	    }
13004	}
13005	if (tmp != NULL) {
13006	    xmlXPathReleaseObject(ctxt->context, tmp);
13007	}
13008	/*
13009	* The result is used as the new evaluation set.
13010	*/
13011	xmlXPathReleaseObject(ctxt->context, obj);
13012	ctxt->context->node = NULL;
13013	ctxt->context->contextSize = -1;
13014	ctxt->context->proximityPosition = -1;
13015	/* may want to move this past the '}' later */
13016	ctxt->context->doc = oldDoc;
13017	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13018    }
13019    ctxt->context->node = oldnode;
13020    return(total);
13021}
13022#endif /* XP_OPTIMIZED_FILTER_FIRST */
13023
13024/**
13025 * xmlXPathCompOpEval:
13026 * @ctxt:  the XPath parser context with the compiled expression
13027 * @op:  an XPath compiled operation
13028 *
13029 * Evaluate the Precompiled XPath operation
13030 * Returns the number of nodes traversed
13031 */
13032static int
13033xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13034{
13035    int total = 0;
13036    int equal, ret;
13037    xmlXPathCompExprPtr comp;
13038    xmlXPathObjectPtr arg1, arg2;
13039    xmlNodePtr bak;
13040    xmlDocPtr bakd;
13041    int pp;
13042    int cs;
13043
13044    CHECK_ERROR0;
13045    comp = ctxt->comp;
13046    switch (op->op) {
13047        case XPATH_OP_END:
13048            return (0);
13049        case XPATH_OP_AND:
13050	    bakd = ctxt->context->doc;
13051	    bak = ctxt->context->node;
13052	    pp = ctxt->context->proximityPosition;
13053	    cs = ctxt->context->contextSize;
13054            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13055	    CHECK_ERROR0;
13056            xmlXPathBooleanFunction(ctxt, 1);
13057            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13058                return (total);
13059            arg2 = valuePop(ctxt);
13060	    ctxt->context->doc = bakd;
13061	    ctxt->context->node = bak;
13062	    ctxt->context->proximityPosition = pp;
13063	    ctxt->context->contextSize = cs;
13064            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13065	    if (ctxt->error) {
13066		xmlXPathFreeObject(arg2);
13067		return(0);
13068	    }
13069            xmlXPathBooleanFunction(ctxt, 1);
13070            arg1 = valuePop(ctxt);
13071            arg1->boolval &= arg2->boolval;
13072            valuePush(ctxt, arg1);
13073	    xmlXPathReleaseObject(ctxt->context, arg2);
13074            return (total);
13075        case XPATH_OP_OR:
13076	    bakd = ctxt->context->doc;
13077	    bak = ctxt->context->node;
13078	    pp = ctxt->context->proximityPosition;
13079	    cs = ctxt->context->contextSize;
13080            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13081	    CHECK_ERROR0;
13082            xmlXPathBooleanFunction(ctxt, 1);
13083            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13084                return (total);
13085            arg2 = valuePop(ctxt);
13086	    ctxt->context->doc = bakd;
13087	    ctxt->context->node = bak;
13088	    ctxt->context->proximityPosition = pp;
13089	    ctxt->context->contextSize = cs;
13090            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13091	    if (ctxt->error) {
13092		xmlXPathFreeObject(arg2);
13093		return(0);
13094	    }
13095            xmlXPathBooleanFunction(ctxt, 1);
13096            arg1 = valuePop(ctxt);
13097            arg1->boolval |= arg2->boolval;
13098            valuePush(ctxt, arg1);
13099	    xmlXPathReleaseObject(ctxt->context, arg2);
13100            return (total);
13101        case XPATH_OP_EQUAL:
13102	    bakd = ctxt->context->doc;
13103	    bak = ctxt->context->node;
13104	    pp = ctxt->context->proximityPosition;
13105	    cs = ctxt->context->contextSize;
13106            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13107	    CHECK_ERROR0;
13108	    ctxt->context->doc = bakd;
13109	    ctxt->context->node = bak;
13110	    ctxt->context->proximityPosition = pp;
13111	    ctxt->context->contextSize = cs;
13112            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13113	    CHECK_ERROR0;
13114	    if (op->value)
13115        	equal = xmlXPathEqualValues(ctxt);
13116	    else
13117		equal = xmlXPathNotEqualValues(ctxt);
13118	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13119            return (total);
13120        case XPATH_OP_CMP:
13121	    bakd = ctxt->context->doc;
13122	    bak = ctxt->context->node;
13123	    pp = ctxt->context->proximityPosition;
13124	    cs = ctxt->context->contextSize;
13125            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13126	    CHECK_ERROR0;
13127	    ctxt->context->doc = bakd;
13128	    ctxt->context->node = bak;
13129	    ctxt->context->proximityPosition = pp;
13130	    ctxt->context->contextSize = cs;
13131            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13132	    CHECK_ERROR0;
13133            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13134	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13135            return (total);
13136        case XPATH_OP_PLUS:
13137	    bakd = ctxt->context->doc;
13138	    bak = ctxt->context->node;
13139	    pp = ctxt->context->proximityPosition;
13140	    cs = ctxt->context->contextSize;
13141            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13142	    CHECK_ERROR0;
13143            if (op->ch2 != -1) {
13144		ctxt->context->doc = bakd;
13145		ctxt->context->node = bak;
13146		ctxt->context->proximityPosition = pp;
13147		ctxt->context->contextSize = cs;
13148                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13149	    }
13150	    CHECK_ERROR0;
13151            if (op->value == 0)
13152                xmlXPathSubValues(ctxt);
13153            else if (op->value == 1)
13154                xmlXPathAddValues(ctxt);
13155            else if (op->value == 2)
13156                xmlXPathValueFlipSign(ctxt);
13157            else if (op->value == 3) {
13158                CAST_TO_NUMBER;
13159                CHECK_TYPE0(XPATH_NUMBER);
13160            }
13161            return (total);
13162        case XPATH_OP_MULT:
13163	    bakd = ctxt->context->doc;
13164	    bak = ctxt->context->node;
13165	    pp = ctxt->context->proximityPosition;
13166	    cs = ctxt->context->contextSize;
13167            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13168	    CHECK_ERROR0;
13169	    ctxt->context->doc = bakd;
13170	    ctxt->context->node = bak;
13171	    ctxt->context->proximityPosition = pp;
13172	    ctxt->context->contextSize = cs;
13173            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13174	    CHECK_ERROR0;
13175            if (op->value == 0)
13176                xmlXPathMultValues(ctxt);
13177            else if (op->value == 1)
13178                xmlXPathDivValues(ctxt);
13179            else if (op->value == 2)
13180                xmlXPathModValues(ctxt);
13181            return (total);
13182        case XPATH_OP_UNION:
13183	    bakd = ctxt->context->doc;
13184	    bak = ctxt->context->node;
13185	    pp = ctxt->context->proximityPosition;
13186	    cs = ctxt->context->contextSize;
13187            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13188	    CHECK_ERROR0;
13189	    ctxt->context->doc = bakd;
13190	    ctxt->context->node = bak;
13191	    ctxt->context->proximityPosition = pp;
13192	    ctxt->context->contextSize = cs;
13193            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13194	    CHECK_ERROR0;
13195            CHECK_TYPE0(XPATH_NODESET);
13196            arg2 = valuePop(ctxt);
13197
13198            CHECK_TYPE0(XPATH_NODESET);
13199            arg1 = valuePop(ctxt);
13200
13201	    if ((arg1->nodesetval == NULL) ||
13202		((arg2->nodesetval != NULL) &&
13203		 (arg2->nodesetval->nodeNr != 0)))
13204	    {
13205		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13206							arg2->nodesetval);
13207	    }
13208
13209            valuePush(ctxt, arg1);
13210	    xmlXPathReleaseObject(ctxt->context, arg2);
13211            return (total);
13212        case XPATH_OP_ROOT:
13213            xmlXPathRoot(ctxt);
13214            return (total);
13215        case XPATH_OP_NODE:
13216            if (op->ch1 != -1)
13217                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13218	    CHECK_ERROR0;
13219            if (op->ch2 != -1)
13220                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13221	    CHECK_ERROR0;
13222	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13223		ctxt->context->node));
13224            return (total);
13225        case XPATH_OP_RESET:
13226            if (op->ch1 != -1)
13227                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13228	    CHECK_ERROR0;
13229            if (op->ch2 != -1)
13230                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13231	    CHECK_ERROR0;
13232            ctxt->context->node = NULL;
13233            return (total);
13234        case XPATH_OP_COLLECT:{
13235                if (op->ch1 == -1)
13236                    return (total);
13237
13238                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13239		CHECK_ERROR0;
13240
13241                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13242                return (total);
13243            }
13244        case XPATH_OP_VALUE:
13245            valuePush(ctxt,
13246                      xmlXPathCacheObjectCopy(ctxt->context,
13247			(xmlXPathObjectPtr) op->value4));
13248            return (total);
13249        case XPATH_OP_VARIABLE:{
13250		xmlXPathObjectPtr val;
13251
13252                if (op->ch1 != -1)
13253                    total +=
13254                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13255                if (op->value5 == NULL) {
13256		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13257		    if (val == NULL) {
13258			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13259			return(0);
13260		    }
13261                    valuePush(ctxt, val);
13262		} else {
13263                    const xmlChar *URI;
13264
13265                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13266                    if (URI == NULL) {
13267                        xmlGenericError(xmlGenericErrorContext,
13268                                        "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13269                                        op->value4, op->value5);
13270                        return (total);
13271                    }
13272		    val = xmlXPathVariableLookupNS(ctxt->context,
13273                                                       op->value4, URI);
13274		    if (val == NULL) {
13275			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13276			return(0);
13277		    }
13278                    valuePush(ctxt, val);
13279                }
13280                return (total);
13281            }
13282        case XPATH_OP_FUNCTION:{
13283                xmlXPathFunction func;
13284                const xmlChar *oldFunc, *oldFuncURI;
13285		int i;
13286
13287                if (op->ch1 != -1)
13288                    total +=
13289                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13290		if (ctxt->valueNr < op->value) {
13291		    xmlGenericError(xmlGenericErrorContext,
13292			    "xmlXPathCompOpEval: parameter error\n");
13293		    ctxt->error = XPATH_INVALID_OPERAND;
13294		    return (total);
13295		}
13296		for (i = 0; i < op->value; i++)
13297		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13298			xmlGenericError(xmlGenericErrorContext,
13299				"xmlXPathCompOpEval: parameter error\n");
13300			ctxt->error = XPATH_INVALID_OPERAND;
13301			return (total);
13302		    }
13303                if (op->cache != NULL)
13304                    XML_CAST_FPTR(func) = op->cache;
13305                else {
13306                    const xmlChar *URI = NULL;
13307
13308                    if (op->value5 == NULL)
13309                        func =
13310                            xmlXPathFunctionLookup(ctxt->context,
13311                                                   op->value4);
13312                    else {
13313                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13314                        if (URI == NULL) {
13315                            xmlGenericError(xmlGenericErrorContext,
13316                                            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13317                                            op->value4, op->value5);
13318                            return (total);
13319                        }
13320                        func = xmlXPathFunctionLookupNS(ctxt->context,
13321                                                        op->value4, URI);
13322                    }
13323                    if (func == NULL) {
13324                        xmlGenericError(xmlGenericErrorContext,
13325                                        "xmlXPathCompOpEval: function %s not found\n",
13326                                        op->value4);
13327                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13328                    }
13329                    op->cache = XML_CAST_FPTR(func);
13330                    op->cacheURI = (void *) URI;
13331                }
13332                oldFunc = ctxt->context->function;
13333                oldFuncURI = ctxt->context->functionURI;
13334                ctxt->context->function = op->value4;
13335                ctxt->context->functionURI = op->cacheURI;
13336                func(ctxt, op->value);
13337                ctxt->context->function = oldFunc;
13338                ctxt->context->functionURI = oldFuncURI;
13339                return (total);
13340            }
13341        case XPATH_OP_ARG:
13342	    bakd = ctxt->context->doc;
13343	    bak = ctxt->context->node;
13344	    pp = ctxt->context->proximityPosition;
13345	    cs = ctxt->context->contextSize;
13346            if (op->ch1 != -1)
13347                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13348	    ctxt->context->contextSize = cs;
13349	    ctxt->context->proximityPosition = pp;
13350	    ctxt->context->node = bak;
13351	    ctxt->context->doc = bakd;
13352	    CHECK_ERROR0;
13353            if (op->ch2 != -1) {
13354                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13355	        ctxt->context->doc = bakd;
13356	        ctxt->context->node = bak;
13357	        CHECK_ERROR0;
13358	    }
13359            return (total);
13360        case XPATH_OP_PREDICATE:
13361        case XPATH_OP_FILTER:{
13362                xmlXPathObjectPtr res;
13363                xmlXPathObjectPtr obj, tmp;
13364                xmlNodeSetPtr newset = NULL;
13365                xmlNodeSetPtr oldset;
13366                xmlNodePtr oldnode;
13367		xmlDocPtr oldDoc;
13368                int i;
13369
13370                /*
13371                 * Optimization for ()[1] selection i.e. the first elem
13372                 */
13373                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13374#ifdef XP_OPTIMIZED_FILTER_FIRST
13375		    /*
13376		    * FILTER TODO: Can we assume that the inner processing
13377		    *  will result in an ordered list if we have an
13378		    *  XPATH_OP_FILTER?
13379		    *  What about an additional field or flag on
13380		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13381		    *  to assume anything, so it would be more robust and
13382		    *  easier to optimize.
13383		    */
13384                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13385		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13386#else
13387		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13388#endif
13389                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13390                    xmlXPathObjectPtr val;
13391
13392                    val = comp->steps[op->ch2].value4;
13393                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13394                        (val->floatval == 1.0)) {
13395                        xmlNodePtr first = NULL;
13396
13397                        total +=
13398                            xmlXPathCompOpEvalFirst(ctxt,
13399                                                    &comp->steps[op->ch1],
13400                                                    &first);
13401			CHECK_ERROR0;
13402                        /*
13403                         * The nodeset should be in document order,
13404                         * Keep only the first value
13405                         */
13406                        if ((ctxt->value != NULL) &&
13407                            (ctxt->value->type == XPATH_NODESET) &&
13408                            (ctxt->value->nodesetval != NULL) &&
13409                            (ctxt->value->nodesetval->nodeNr > 1))
13410                            ctxt->value->nodesetval->nodeNr = 1;
13411                        return (total);
13412                    }
13413                }
13414                /*
13415                 * Optimization for ()[last()] selection i.e. the last elem
13416                 */
13417                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13418                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13419                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13420                    int f = comp->steps[op->ch2].ch1;
13421
13422                    if ((f != -1) &&
13423                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13424                        (comp->steps[f].value5 == NULL) &&
13425                        (comp->steps[f].value == 0) &&
13426                        (comp->steps[f].value4 != NULL) &&
13427                        (xmlStrEqual
13428                         (comp->steps[f].value4, BAD_CAST "last"))) {
13429                        xmlNodePtr last = NULL;
13430
13431                        total +=
13432                            xmlXPathCompOpEvalLast(ctxt,
13433                                                   &comp->steps[op->ch1],
13434                                                   &last);
13435			CHECK_ERROR0;
13436                        /*
13437                         * The nodeset should be in document order,
13438                         * Keep only the last value
13439                         */
13440                        if ((ctxt->value != NULL) &&
13441                            (ctxt->value->type == XPATH_NODESET) &&
13442                            (ctxt->value->nodesetval != NULL) &&
13443                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13444                            (ctxt->value->nodesetval->nodeNr > 1)) {
13445                            ctxt->value->nodesetval->nodeTab[0] =
13446                                ctxt->value->nodesetval->nodeTab[ctxt->
13447                                                                 value->
13448                                                                 nodesetval->
13449                                                                 nodeNr -
13450                                                                 1];
13451                            ctxt->value->nodesetval->nodeNr = 1;
13452                        }
13453                        return (total);
13454                    }
13455                }
13456		/*
13457		* Process inner predicates first.
13458		* Example "index[parent::book][1]":
13459		* ...
13460		*   PREDICATE   <-- we are here "[1]"
13461		*     PREDICATE <-- process "[parent::book]" first
13462		*       SORT
13463		*         COLLECT  'parent' 'name' 'node' book
13464		*           NODE
13465		*     ELEM Object is a number : 1
13466		*/
13467                if (op->ch1 != -1)
13468                    total +=
13469                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13470		CHECK_ERROR0;
13471                if (op->ch2 == -1)
13472                    return (total);
13473                if (ctxt->value == NULL)
13474                    return (total);
13475
13476                oldnode = ctxt->context->node;
13477
13478#ifdef LIBXML_XPTR_ENABLED
13479                /*
13480                 * Hum are we filtering the result of an XPointer expression
13481                 */
13482                if (ctxt->value->type == XPATH_LOCATIONSET) {
13483                    xmlLocationSetPtr newlocset = NULL;
13484                    xmlLocationSetPtr oldlocset;
13485
13486                    /*
13487                     * Extract the old locset, and then evaluate the result of the
13488                     * expression for all the element in the locset. use it to grow
13489                     * up a new locset.
13490                     */
13491                    CHECK_TYPE0(XPATH_LOCATIONSET);
13492                    obj = valuePop(ctxt);
13493                    oldlocset = obj->user;
13494                    ctxt->context->node = NULL;
13495
13496                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13497                        ctxt->context->contextSize = 0;
13498                        ctxt->context->proximityPosition = 0;
13499                        if (op->ch2 != -1)
13500                            total +=
13501                                xmlXPathCompOpEval(ctxt,
13502                                                   &comp->steps[op->ch2]);
13503                        res = valuePop(ctxt);
13504                        if (res != NULL) {
13505			    xmlXPathReleaseObject(ctxt->context, res);
13506			}
13507                        valuePush(ctxt, obj);
13508                        CHECK_ERROR0;
13509                        return (total);
13510                    }
13511                    newlocset = xmlXPtrLocationSetCreate(NULL);
13512
13513                    for (i = 0; i < oldlocset->locNr; i++) {
13514                        /*
13515                         * Run the evaluation with a node list made of a
13516                         * single item in the nodelocset.
13517                         */
13518                        ctxt->context->node = oldlocset->locTab[i]->user;
13519                        ctxt->context->contextSize = oldlocset->locNr;
13520                        ctxt->context->proximityPosition = i + 1;
13521			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13522			    ctxt->context->node);
13523                        valuePush(ctxt, tmp);
13524
13525                        if (op->ch2 != -1)
13526                            total +=
13527                                xmlXPathCompOpEval(ctxt,
13528                                                   &comp->steps[op->ch2]);
13529			if (ctxt->error != XPATH_EXPRESSION_OK) {
13530			    xmlXPathFreeObject(obj);
13531			    return(0);
13532			}
13533
13534                        /*
13535                         * The result of the evaluation need to be tested to
13536                         * decided whether the filter succeeded or not
13537                         */
13538                        res = valuePop(ctxt);
13539                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13540                            xmlXPtrLocationSetAdd(newlocset,
13541                                                  xmlXPathObjectCopy
13542                                                  (oldlocset->locTab[i]));
13543                        }
13544
13545                        /*
13546                         * Cleanup
13547                         */
13548                        if (res != NULL) {
13549			    xmlXPathReleaseObject(ctxt->context, res);
13550			}
13551                        if (ctxt->value == tmp) {
13552                            res = valuePop(ctxt);
13553			    xmlXPathReleaseObject(ctxt->context, res);
13554                        }
13555
13556                        ctxt->context->node = NULL;
13557                    }
13558
13559                    /*
13560                     * The result is used as the new evaluation locset.
13561                     */
13562		    xmlXPathReleaseObject(ctxt->context, obj);
13563                    ctxt->context->node = NULL;
13564                    ctxt->context->contextSize = -1;
13565                    ctxt->context->proximityPosition = -1;
13566                    valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13567                    ctxt->context->node = oldnode;
13568                    return (total);
13569                }
13570#endif /* LIBXML_XPTR_ENABLED */
13571
13572                /*
13573                 * Extract the old set, and then evaluate the result of the
13574                 * expression for all the element in the set. use it to grow
13575                 * up a new set.
13576                 */
13577                CHECK_TYPE0(XPATH_NODESET);
13578                obj = valuePop(ctxt);
13579                oldset = obj->nodesetval;
13580
13581                oldnode = ctxt->context->node;
13582		oldDoc = ctxt->context->doc;
13583                ctxt->context->node = NULL;
13584
13585                if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13586                    ctxt->context->contextSize = 0;
13587                    ctxt->context->proximityPosition = 0;
13588/*
13589                    if (op->ch2 != -1)
13590                        total +=
13591                            xmlXPathCompOpEval(ctxt,
13592                                               &comp->steps[op->ch2]);
13593		    CHECK_ERROR0;
13594                    res = valuePop(ctxt);
13595                    if (res != NULL)
13596                        xmlXPathFreeObject(res);
13597*/
13598                    valuePush(ctxt, obj);
13599                    ctxt->context->node = oldnode;
13600                    CHECK_ERROR0;
13601                } else {
13602		    tmp = NULL;
13603                    /*
13604                     * Initialize the new set.
13605		     * Also set the xpath document in case things like
13606		     * key() evaluation are attempted on the predicate
13607                     */
13608                    newset = xmlXPathNodeSetCreate(NULL);
13609		    /*
13610		    * SPEC XPath 1.0:
13611		    *  "For each node in the node-set to be filtered, the
13612		    *  PredicateExpr is evaluated with that node as the
13613		    *  context node, with the number of nodes in the
13614		    *  node-set as the context size, and with the proximity
13615		    *  position of the node in the node-set with respect to
13616		    *  the axis as the context position;"
13617		    * @oldset is the node-set" to be filtered.
13618		    *
13619		    * SPEC XPath 1.0:
13620		    *  "only predicates change the context position and
13621		    *  context size (see [2.4 Predicates])."
13622		    * Example:
13623		    *   node-set  context pos
13624		    *    nA         1
13625		    *    nB         2
13626		    *    nC         3
13627		    *   After applying predicate [position() > 1] :
13628		    *   node-set  context pos
13629		    *    nB         1
13630		    *    nC         2
13631		    *
13632		    * removed the first node in the node-set, then
13633		    * the context position of the
13634		    */
13635                    for (i = 0; i < oldset->nodeNr; i++) {
13636                        /*
13637                         * Run the evaluation with a node list made of
13638                         * a single item in the nodeset.
13639                         */
13640                        ctxt->context->node = oldset->nodeTab[i];
13641			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13642			    (oldset->nodeTab[i]->doc != NULL))
13643		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13644			if (tmp == NULL) {
13645			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13646				ctxt->context->node);
13647			} else {
13648			    xmlXPathNodeSetAddUnique(tmp->nodesetval,
13649				ctxt->context->node);
13650			}
13651                        valuePush(ctxt, tmp);
13652                        ctxt->context->contextSize = oldset->nodeNr;
13653                        ctxt->context->proximityPosition = i + 1;
13654			/*
13655			* Evaluate the predicate against the context node.
13656			* Can/should we optimize position() predicates
13657			* here (e.g. "[1]")?
13658			*/
13659                        if (op->ch2 != -1)
13660                            total +=
13661                                xmlXPathCompOpEval(ctxt,
13662                                                   &comp->steps[op->ch2]);
13663			if (ctxt->error != XPATH_EXPRESSION_OK) {
13664			    xmlXPathFreeNodeSet(newset);
13665			    xmlXPathFreeObject(obj);
13666			    return(0);
13667			}
13668
13669                        /*
13670                         * The result of the evaluation needs to be tested to
13671                         * decide whether the filter succeeded or not
13672                         */
13673			/*
13674			* OPTIMIZE TODO: Can we use
13675			* xmlXPathNodeSetAdd*Unique()* instead?
13676			*/
13677                        res = valuePop(ctxt);
13678                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13679                            xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13680                        }
13681
13682                        /*
13683                         * Cleanup
13684                         */
13685                        if (res != NULL) {
13686			    xmlXPathReleaseObject(ctxt->context, res);
13687			}
13688                        if (ctxt->value == tmp) {
13689                            valuePop(ctxt);
13690			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13691			    /*
13692			    * Don't free the temporary nodeset
13693			    * in order to avoid massive recreation inside this
13694			    * loop.
13695			    */
13696                        } else
13697			    tmp = NULL;
13698                        ctxt->context->node = NULL;
13699                    }
13700		    if (tmp != NULL)
13701			xmlXPathReleaseObject(ctxt->context, tmp);
13702                    /*
13703                     * The result is used as the new evaluation set.
13704                     */
13705		    xmlXPathReleaseObject(ctxt->context, obj);
13706                    ctxt->context->node = NULL;
13707                    ctxt->context->contextSize = -1;
13708                    ctxt->context->proximityPosition = -1;
13709		    /* may want to move this past the '}' later */
13710		    ctxt->context->doc = oldDoc;
13711		    valuePush(ctxt,
13712			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13713                }
13714                ctxt->context->node = oldnode;
13715                return (total);
13716            }
13717        case XPATH_OP_SORT:
13718            if (op->ch1 != -1)
13719                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13720	    CHECK_ERROR0;
13721            if ((ctxt->value != NULL) &&
13722                (ctxt->value->type == XPATH_NODESET) &&
13723                (ctxt->value->nodesetval != NULL) &&
13724		(ctxt->value->nodesetval->nodeNr > 1))
13725	    {
13726                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13727	    }
13728            return (total);
13729#ifdef LIBXML_XPTR_ENABLED
13730        case XPATH_OP_RANGETO:{
13731                xmlXPathObjectPtr range;
13732                xmlXPathObjectPtr res, obj;
13733                xmlXPathObjectPtr tmp;
13734                xmlLocationSetPtr newlocset = NULL;
13735		    xmlLocationSetPtr oldlocset;
13736                xmlNodeSetPtr oldset;
13737                int i, j;
13738
13739                if (op->ch1 != -1)
13740                    total +=
13741                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13742                if (op->ch2 == -1)
13743                    return (total);
13744
13745                if (ctxt->value->type == XPATH_LOCATIONSET) {
13746                    /*
13747                     * Extract the old locset, and then evaluate the result of the
13748                     * expression for all the element in the locset. use it to grow
13749                     * up a new locset.
13750                     */
13751                    CHECK_TYPE0(XPATH_LOCATIONSET);
13752                    obj = valuePop(ctxt);
13753                    oldlocset = obj->user;
13754
13755                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13756		        ctxt->context->node = NULL;
13757                        ctxt->context->contextSize = 0;
13758                        ctxt->context->proximityPosition = 0;
13759                        total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13760                        res = valuePop(ctxt);
13761                        if (res != NULL) {
13762			    xmlXPathReleaseObject(ctxt->context, res);
13763			}
13764                        valuePush(ctxt, obj);
13765                        CHECK_ERROR0;
13766                        return (total);
13767                    }
13768                    newlocset = xmlXPtrLocationSetCreate(NULL);
13769
13770                    for (i = 0; i < oldlocset->locNr; i++) {
13771                        /*
13772                         * Run the evaluation with a node list made of a
13773                         * single item in the nodelocset.
13774                         */
13775                        ctxt->context->node = oldlocset->locTab[i]->user;
13776                        ctxt->context->contextSize = oldlocset->locNr;
13777                        ctxt->context->proximityPosition = i + 1;
13778			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13779			    ctxt->context->node);
13780                        valuePush(ctxt, tmp);
13781
13782                        if (op->ch2 != -1)
13783                            total +=
13784                                xmlXPathCompOpEval(ctxt,
13785                                                   &comp->steps[op->ch2]);
13786			if (ctxt->error != XPATH_EXPRESSION_OK) {
13787			    xmlXPathFreeObject(obj);
13788			    return(0);
13789			}
13790
13791                        res = valuePop(ctxt);
13792			if (res->type == XPATH_LOCATIONSET) {
13793			    xmlLocationSetPtr rloc =
13794			        (xmlLocationSetPtr)res->user;
13795			    for (j=0; j<rloc->locNr; j++) {
13796			        range = xmlXPtrNewRange(
13797				  oldlocset->locTab[i]->user,
13798				  oldlocset->locTab[i]->index,
13799				  rloc->locTab[j]->user2,
13800				  rloc->locTab[j]->index2);
13801				if (range != NULL) {
13802				    xmlXPtrLocationSetAdd(newlocset, range);
13803				}
13804			    }
13805			} else {
13806			    range = xmlXPtrNewRangeNodeObject(
13807				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13808                            if (range != NULL) {
13809                                xmlXPtrLocationSetAdd(newlocset,range);
13810			    }
13811                        }
13812
13813                        /*
13814                         * Cleanup
13815                         */
13816                        if (res != NULL) {
13817			    xmlXPathReleaseObject(ctxt->context, res);
13818			}
13819                        if (ctxt->value == tmp) {
13820                            res = valuePop(ctxt);
13821			    xmlXPathReleaseObject(ctxt->context, res);
13822                        }
13823
13824                        ctxt->context->node = NULL;
13825                    }
13826		} else {	/* Not a location set */
13827                    CHECK_TYPE0(XPATH_NODESET);
13828                    obj = valuePop(ctxt);
13829                    oldset = obj->nodesetval;
13830                    ctxt->context->node = NULL;
13831
13832                    newlocset = xmlXPtrLocationSetCreate(NULL);
13833
13834                    if (oldset != NULL) {
13835                        for (i = 0; i < oldset->nodeNr; i++) {
13836                            /*
13837                             * Run the evaluation with a node list made of a single item
13838                             * in the nodeset.
13839                             */
13840                            ctxt->context->node = oldset->nodeTab[i];
13841			    /*
13842			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13843			    */
13844			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13845				ctxt->context->node);
13846                            valuePush(ctxt, tmp);
13847
13848                            if (op->ch2 != -1)
13849                                total +=
13850                                    xmlXPathCompOpEval(ctxt,
13851                                                   &comp->steps[op->ch2]);
13852			    if (ctxt->error != XPATH_EXPRESSION_OK) {
13853				xmlXPathFreeObject(obj);
13854				return(0);
13855			    }
13856
13857                            res = valuePop(ctxt);
13858                            range =
13859                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13860                                                      res);
13861                            if (range != NULL) {
13862                                xmlXPtrLocationSetAdd(newlocset, range);
13863                            }
13864
13865                            /*
13866                             * Cleanup
13867                             */
13868                            if (res != NULL) {
13869				xmlXPathReleaseObject(ctxt->context, res);
13870			    }
13871                            if (ctxt->value == tmp) {
13872                                res = valuePop(ctxt);
13873				xmlXPathReleaseObject(ctxt->context, res);
13874                            }
13875
13876                            ctxt->context->node = NULL;
13877                        }
13878                    }
13879                }
13880
13881                /*
13882                 * The result is used as the new evaluation set.
13883                 */
13884		xmlXPathReleaseObject(ctxt->context, obj);
13885                ctxt->context->node = NULL;
13886                ctxt->context->contextSize = -1;
13887                ctxt->context->proximityPosition = -1;
13888                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13889                return (total);
13890            }
13891#endif /* LIBXML_XPTR_ENABLED */
13892    }
13893    xmlGenericError(xmlGenericErrorContext,
13894                    "XPath: unknown precompiled operation %d\n", op->op);
13895    return (total);
13896}
13897
13898/**
13899 * xmlXPathCompOpEvalToBoolean:
13900 * @ctxt:  the XPath parser context
13901 *
13902 * Evaluates if the expression evaluates to true.
13903 *
13904 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13905 */
13906static int
13907xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13908			    xmlXPathStepOpPtr op,
13909			    int isPredicate)
13910{
13911    xmlXPathObjectPtr resObj = NULL;
13912
13913start:
13914    /* comp = ctxt->comp; */
13915    switch (op->op) {
13916        case XPATH_OP_END:
13917            return (0);
13918	case XPATH_OP_VALUE:
13919	    resObj = (xmlXPathObjectPtr) op->value4;
13920	    if (isPredicate)
13921		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13922	    return(xmlXPathCastToBoolean(resObj));
13923	case XPATH_OP_SORT:
13924	    /*
13925	    * We don't need sorting for boolean results. Skip this one.
13926	    */
13927            if (op->ch1 != -1) {
13928		op = &ctxt->comp->steps[op->ch1];
13929		goto start;
13930	    }
13931	    return(0);
13932	case XPATH_OP_COLLECT:
13933	    if (op->ch1 == -1)
13934		return(0);
13935
13936            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13937	    if (ctxt->error != XPATH_EXPRESSION_OK)
13938		return(-1);
13939
13940            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13941	    if (ctxt->error != XPATH_EXPRESSION_OK)
13942		return(-1);
13943
13944	    resObj = valuePop(ctxt);
13945	    if (resObj == NULL)
13946		return(-1);
13947	    break;
13948	default:
13949	    /*
13950	    * Fallback to call xmlXPathCompOpEval().
13951	    */
13952	    xmlXPathCompOpEval(ctxt, op);
13953	    if (ctxt->error != XPATH_EXPRESSION_OK)
13954		return(-1);
13955
13956	    resObj = valuePop(ctxt);
13957	    if (resObj == NULL)
13958		return(-1);
13959	    break;
13960    }
13961
13962    if (resObj) {
13963	int res;
13964
13965	if (resObj->type == XPATH_BOOLEAN) {
13966	    res = resObj->boolval;
13967	} else if (isPredicate) {
13968	    /*
13969	    * For predicates a result of type "number" is handled
13970	    * differently:
13971	    * SPEC XPath 1.0:
13972	    * "If the result is a number, the result will be converted
13973	    *  to true if the number is equal to the context position
13974	    *  and will be converted to false otherwise;"
13975	    */
13976	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13977	} else {
13978	    res = xmlXPathCastToBoolean(resObj);
13979	}
13980	xmlXPathReleaseObject(ctxt->context, resObj);
13981	return(res);
13982    }
13983
13984    return(0);
13985}
13986
13987#ifdef XPATH_STREAMING
13988/**
13989 * xmlXPathRunStreamEval:
13990 * @ctxt:  the XPath parser context with the compiled expression
13991 *
13992 * Evaluate the Precompiled Streamable XPath expression in the given context.
13993 */
13994static int
13995xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13996		      xmlXPathObjectPtr *resultSeq, int toBool)
13997{
13998    int max_depth, min_depth;
13999    int from_root;
14000    int ret, depth;
14001    int eval_all_nodes;
14002    xmlNodePtr cur = NULL, limit = NULL;
14003    xmlStreamCtxtPtr patstream = NULL;
14004
14005    int nb_nodes = 0;
14006
14007    if ((ctxt == NULL) || (comp == NULL))
14008        return(-1);
14009    max_depth = xmlPatternMaxDepth(comp);
14010    if (max_depth == -1)
14011        return(-1);
14012    if (max_depth == -2)
14013        max_depth = 10000;
14014    min_depth = xmlPatternMinDepth(comp);
14015    if (min_depth == -1)
14016        return(-1);
14017    from_root = xmlPatternFromRoot(comp);
14018    if (from_root < 0)
14019        return(-1);
14020#if 0
14021    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14022#endif
14023
14024    if (! toBool) {
14025	if (resultSeq == NULL)
14026	    return(-1);
14027	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14028	if (*resultSeq == NULL)
14029	    return(-1);
14030    }
14031
14032    /*
14033     * handle the special cases of "/" amd "." being matched
14034     */
14035    if (min_depth == 0) {
14036	if (from_root) {
14037	    /* Select "/" */
14038	    if (toBool)
14039		return(1);
14040	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14041		(xmlNodePtr) ctxt->doc);
14042	} else {
14043	    /* Select "self::node()" */
14044	    if (toBool)
14045		return(1);
14046	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14047	}
14048    }
14049    if (max_depth == 0) {
14050	return(0);
14051    }
14052
14053    if (from_root) {
14054        cur = (xmlNodePtr)ctxt->doc;
14055    } else if (ctxt->node != NULL) {
14056        switch (ctxt->node->type) {
14057            case XML_ELEMENT_NODE:
14058            case XML_DOCUMENT_NODE:
14059            case XML_DOCUMENT_FRAG_NODE:
14060            case XML_HTML_DOCUMENT_NODE:
14061#ifdef LIBXML_DOCB_ENABLED
14062            case XML_DOCB_DOCUMENT_NODE:
14063#endif
14064	        cur = ctxt->node;
14065		break;
14066            case XML_ATTRIBUTE_NODE:
14067            case XML_TEXT_NODE:
14068            case XML_CDATA_SECTION_NODE:
14069            case XML_ENTITY_REF_NODE:
14070            case XML_ENTITY_NODE:
14071            case XML_PI_NODE:
14072            case XML_COMMENT_NODE:
14073            case XML_NOTATION_NODE:
14074            case XML_DTD_NODE:
14075            case XML_DOCUMENT_TYPE_NODE:
14076            case XML_ELEMENT_DECL:
14077            case XML_ATTRIBUTE_DECL:
14078            case XML_ENTITY_DECL:
14079            case XML_NAMESPACE_DECL:
14080            case XML_XINCLUDE_START:
14081            case XML_XINCLUDE_END:
14082		break;
14083	}
14084	limit = cur;
14085    }
14086    if (cur == NULL) {
14087        return(0);
14088    }
14089
14090    patstream = xmlPatternGetStreamCtxt(comp);
14091    if (patstream == NULL) {
14092	/*
14093	* QUESTION TODO: Is this an error?
14094	*/
14095	return(0);
14096    }
14097
14098    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14099
14100    if (from_root) {
14101	ret = xmlStreamPush(patstream, NULL, NULL);
14102	if (ret < 0) {
14103	} else if (ret == 1) {
14104	    if (toBool)
14105		goto return_1;
14106	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14107	}
14108    }
14109    depth = 0;
14110    goto scan_children;
14111next_node:
14112    do {
14113        nb_nodes++;
14114
14115	switch (cur->type) {
14116	    case XML_ELEMENT_NODE:
14117	    case XML_TEXT_NODE:
14118	    case XML_CDATA_SECTION_NODE:
14119	    case XML_COMMENT_NODE:
14120	    case XML_PI_NODE:
14121		if (cur->type == XML_ELEMENT_NODE) {
14122		    ret = xmlStreamPush(patstream, cur->name,
14123				(cur->ns ? cur->ns->href : NULL));
14124		} else if (eval_all_nodes)
14125		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14126		else
14127		    break;
14128
14129		if (ret < 0) {
14130		    /* NOP. */
14131		} else if (ret == 1) {
14132		    if (toBool)
14133			goto return_1;
14134		    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14135		}
14136		if ((cur->children == NULL) || (depth >= max_depth)) {
14137		    ret = xmlStreamPop(patstream);
14138		    while (cur->next != NULL) {
14139			cur = cur->next;
14140			if ((cur->type != XML_ENTITY_DECL) &&
14141			    (cur->type != XML_DTD_NODE))
14142			    goto next_node;
14143		    }
14144		}
14145	    default:
14146		break;
14147	}
14148
14149scan_children:
14150	if ((cur->children != NULL) && (depth < max_depth)) {
14151	    /*
14152	     * Do not descend on entities declarations
14153	     */
14154	    if (cur->children->type != XML_ENTITY_DECL) {
14155		cur = cur->children;
14156		depth++;
14157		/*
14158		 * Skip DTDs
14159		 */
14160		if (cur->type != XML_DTD_NODE)
14161		    continue;
14162	    }
14163	}
14164
14165	if (cur == limit)
14166	    break;
14167
14168	while (cur->next != NULL) {
14169	    cur = cur->next;
14170	    if ((cur->type != XML_ENTITY_DECL) &&
14171		(cur->type != XML_DTD_NODE))
14172		goto next_node;
14173	}
14174
14175	do {
14176	    cur = cur->parent;
14177	    depth--;
14178	    if ((cur == NULL) || (cur == limit))
14179	        goto done;
14180	    if (cur->type == XML_ELEMENT_NODE) {
14181		ret = xmlStreamPop(patstream);
14182	    } else if ((eval_all_nodes) &&
14183		((cur->type == XML_TEXT_NODE) ||
14184		 (cur->type == XML_CDATA_SECTION_NODE) ||
14185		 (cur->type == XML_COMMENT_NODE) ||
14186		 (cur->type == XML_PI_NODE)))
14187	    {
14188		ret = xmlStreamPop(patstream);
14189	    }
14190	    if (cur->next != NULL) {
14191		cur = cur->next;
14192		break;
14193	    }
14194	} while (cur != NULL);
14195
14196    } while ((cur != NULL) && (depth >= 0));
14197
14198done:
14199
14200#if 0
14201    printf("stream eval: checked %d nodes selected %d\n",
14202           nb_nodes, retObj->nodesetval->nodeNr);
14203#endif
14204
14205    if (patstream)
14206	xmlFreeStreamCtxt(patstream);
14207    return(0);
14208
14209return_1:
14210    if (patstream)
14211	xmlFreeStreamCtxt(patstream);
14212    return(1);
14213}
14214#endif /* XPATH_STREAMING */
14215
14216/**
14217 * xmlXPathRunEval:
14218 * @ctxt:  the XPath parser context with the compiled expression
14219 * @toBool:  evaluate to a boolean result
14220 *
14221 * Evaluate the Precompiled XPath expression in the given context.
14222 */
14223static int
14224xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14225{
14226    xmlXPathCompExprPtr comp;
14227
14228    if ((ctxt == NULL) || (ctxt->comp == NULL))
14229	return(-1);
14230
14231    if (ctxt->valueTab == NULL) {
14232	/* Allocate the value stack */
14233	ctxt->valueTab = (xmlXPathObjectPtr *)
14234			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14235	if (ctxt->valueTab == NULL) {
14236	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14237	    xmlFree(ctxt);
14238	}
14239	ctxt->valueNr = 0;
14240	ctxt->valueMax = 10;
14241	ctxt->value = NULL;
14242    }
14243#ifdef XPATH_STREAMING
14244    if (ctxt->comp->stream) {
14245	int res;
14246
14247	if (toBool) {
14248	    /*
14249	    * Evaluation to boolean result.
14250	    */
14251	    res = xmlXPathRunStreamEval(ctxt->context,
14252		ctxt->comp->stream, NULL, 1);
14253	    if (res != -1)
14254		return(res);
14255	} else {
14256	    xmlXPathObjectPtr resObj = NULL;
14257
14258	    /*
14259	    * Evaluation to a sequence.
14260	    */
14261	    res = xmlXPathRunStreamEval(ctxt->context,
14262		ctxt->comp->stream, &resObj, 0);
14263
14264	    if ((res != -1) && (resObj != NULL)) {
14265		valuePush(ctxt, resObj);
14266		return(0);
14267	    }
14268	    if (resObj != NULL)
14269		xmlXPathReleaseObject(ctxt->context, resObj);
14270	}
14271	/*
14272	* QUESTION TODO: This falls back to normal XPath evaluation
14273	* if res == -1. Is this intended?
14274	*/
14275    }
14276#endif
14277    comp = ctxt->comp;
14278    if (comp->last < 0) {
14279	xmlGenericError(xmlGenericErrorContext,
14280	    "xmlXPathRunEval: last is less than zero\n");
14281	return(-1);
14282    }
14283    if (toBool)
14284	return(xmlXPathCompOpEvalToBoolean(ctxt,
14285	    &comp->steps[comp->last], 0));
14286    else
14287	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14288
14289    return(0);
14290}
14291
14292/************************************************************************
14293 *									*
14294 * 			Public interfaces				*
14295 *									*
14296 ************************************************************************/
14297
14298/**
14299 * xmlXPathEvalPredicate:
14300 * @ctxt:  the XPath context
14301 * @res:  the Predicate Expression evaluation result
14302 *
14303 * Evaluate a predicate result for the current node.
14304 * A PredicateExpr is evaluated by evaluating the Expr and converting
14305 * the result to a boolean. If the result is a number, the result will
14306 * be converted to true if the number is equal to the position of the
14307 * context node in the context node list (as returned by the position
14308 * function) and will be converted to false otherwise; if the result
14309 * is not a number, then the result will be converted as if by a call
14310 * to the boolean function.
14311 *
14312 * Returns 1 if predicate is true, 0 otherwise
14313 */
14314int
14315xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14316    if ((ctxt == NULL) || (res == NULL)) return(0);
14317    switch (res->type) {
14318        case XPATH_BOOLEAN:
14319	    return(res->boolval);
14320        case XPATH_NUMBER:
14321	    return(res->floatval == ctxt->proximityPosition);
14322        case XPATH_NODESET:
14323        case XPATH_XSLT_TREE:
14324	    if (res->nodesetval == NULL)
14325		return(0);
14326	    return(res->nodesetval->nodeNr != 0);
14327        case XPATH_STRING:
14328	    return((res->stringval != NULL) &&
14329	           (xmlStrlen(res->stringval) != 0));
14330        default:
14331	    STRANGE
14332    }
14333    return(0);
14334}
14335
14336/**
14337 * xmlXPathEvaluatePredicateResult:
14338 * @ctxt:  the XPath Parser context
14339 * @res:  the Predicate Expression evaluation result
14340 *
14341 * Evaluate a predicate result for the current node.
14342 * A PredicateExpr is evaluated by evaluating the Expr and converting
14343 * the result to a boolean. If the result is a number, the result will
14344 * be converted to true if the number is equal to the position of the
14345 * context node in the context node list (as returned by the position
14346 * function) and will be converted to false otherwise; if the result
14347 * is not a number, then the result will be converted as if by a call
14348 * to the boolean function.
14349 *
14350 * Returns 1 if predicate is true, 0 otherwise
14351 */
14352int
14353xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14354                                xmlXPathObjectPtr res) {
14355    if ((ctxt == NULL) || (res == NULL)) return(0);
14356    switch (res->type) {
14357        case XPATH_BOOLEAN:
14358	    return(res->boolval);
14359        case XPATH_NUMBER:
14360#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14361	    return((res->floatval == ctxt->context->proximityPosition) &&
14362	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14363#else
14364	    return(res->floatval == ctxt->context->proximityPosition);
14365#endif
14366        case XPATH_NODESET:
14367        case XPATH_XSLT_TREE:
14368	    if (res->nodesetval == NULL)
14369		return(0);
14370	    return(res->nodesetval->nodeNr != 0);
14371        case XPATH_STRING:
14372	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14373#ifdef LIBXML_XPTR_ENABLED
14374	case XPATH_LOCATIONSET:{
14375	    xmlLocationSetPtr ptr = res->user;
14376	    if (ptr == NULL)
14377	        return(0);
14378	    return (ptr->locNr != 0);
14379	    }
14380#endif
14381        default:
14382	    STRANGE
14383    }
14384    return(0);
14385}
14386
14387#ifdef XPATH_STREAMING
14388/**
14389 * xmlXPathTryStreamCompile:
14390 * @ctxt: an XPath context
14391 * @str:  the XPath expression
14392 *
14393 * Try to compile the XPath expression as a streamable subset.
14394 *
14395 * Returns the compiled expression or NULL if failed to compile.
14396 */
14397static xmlXPathCompExprPtr
14398xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14399    /*
14400     * Optimization: use streaming patterns when the XPath expression can
14401     * be compiled to a stream lookup
14402     */
14403    xmlPatternPtr stream;
14404    xmlXPathCompExprPtr comp;
14405    xmlDictPtr dict = NULL;
14406    const xmlChar **namespaces = NULL;
14407    xmlNsPtr ns;
14408    int i, j;
14409
14410    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14411        (!xmlStrchr(str, '@'))) {
14412	const xmlChar *tmp;
14413
14414	/*
14415	 * We don't try to handle expressions using the verbose axis
14416	 * specifiers ("::"), just the simplied form at this point.
14417	 * Additionally, if there is no list of namespaces available and
14418	 *  there's a ":" in the expression, indicating a prefixed QName,
14419	 *  then we won't try to compile either. xmlPatterncompile() needs
14420	 *  to have a list of namespaces at compilation time in order to
14421	 *  compile prefixed name tests.
14422	 */
14423	tmp = xmlStrchr(str, ':');
14424	if ((tmp != NULL) &&
14425	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14426	    return(NULL);
14427
14428	if (ctxt != NULL) {
14429	    dict = ctxt->dict;
14430	    if (ctxt->nsNr > 0) {
14431		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14432		if (namespaces == NULL) {
14433		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14434		    return(NULL);
14435		}
14436		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14437		    ns = ctxt->namespaces[j];
14438		    namespaces[i++] = ns->href;
14439		    namespaces[i++] = ns->prefix;
14440		}
14441		namespaces[i++] = NULL;
14442		namespaces[i++] = NULL;
14443	    }
14444	}
14445
14446	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14447			&namespaces[0]);
14448	if (namespaces != NULL) {
14449	    xmlFree((xmlChar **)namespaces);
14450 	}
14451	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14452	    comp = xmlXPathNewCompExpr();
14453	    if (comp == NULL) {
14454		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14455		return(NULL);
14456	    }
14457	    comp->stream = stream;
14458	    comp->dict = dict;
14459	    if (comp->dict)
14460		xmlDictReference(comp->dict);
14461	    return(comp);
14462	}
14463	xmlFreePattern(stream);
14464    }
14465    return(NULL);
14466}
14467#endif /* XPATH_STREAMING */
14468
14469static int
14470xmlXPathCanRewriteDosExpression(xmlChar *expr)
14471{
14472    if (expr == NULL)
14473	return(0);
14474    do {
14475        if ((*expr == '/') && (*(++expr) == '/'))
14476	    return(1);
14477    } while (*expr++);
14478    return(0);
14479}
14480static void
14481xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14482{
14483    /*
14484    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14485    * internal representation.
14486    */
14487    if (op->ch1 != -1) {
14488	if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14489	    ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14490	    ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14491	    ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14492	{
14493	    /*
14494	    * This is a "child::foo"
14495	    */
14496	    xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14497
14498	    if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14499		(prevop->ch1 != -1) &&
14500		((xmlXPathAxisVal) prevop->value ==
14501		    AXIS_DESCENDANT_OR_SELF) &&
14502		(prevop->ch2 == -1) &&
14503		((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14504		((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14505		(comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14506	    {
14507		/*
14508		* This is a "/descendant-or-self::node()" without predicates.
14509		* Eliminate it.
14510		*/
14511		op->ch1 = prevop->ch1;
14512		op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14513	    }
14514	}
14515	if (op->ch1 != -1)
14516	    xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14517    }
14518    if (op->ch2 != -1)
14519	xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14520}
14521
14522/**
14523 * xmlXPathCtxtCompile:
14524 * @ctxt: an XPath context
14525 * @str:  the XPath expression
14526 *
14527 * Compile an XPath expression
14528 *
14529 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14530 *         the caller has to free the object.
14531 */
14532xmlXPathCompExprPtr
14533xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14534    xmlXPathParserContextPtr pctxt;
14535    xmlXPathCompExprPtr comp;
14536
14537#ifdef XPATH_STREAMING
14538    comp = xmlXPathTryStreamCompile(ctxt, str);
14539    if (comp != NULL)
14540        return(comp);
14541#endif
14542
14543    xmlXPathInit();
14544
14545    pctxt = xmlXPathNewParserContext(str, ctxt);
14546    xmlXPathCompileExpr(pctxt, 1);
14547
14548    if( pctxt->error != XPATH_EXPRESSION_OK )
14549    {
14550        xmlXPathFreeParserContext(pctxt);
14551        return(NULL);
14552    }
14553
14554    if (*pctxt->cur != 0) {
14555	/*
14556	 * aleksey: in some cases this line prints *second* error message
14557	 * (see bug #78858) and probably this should be fixed.
14558	 * However, we are not sure that all error messages are printed
14559	 * out in other places. It's not critical so we leave it as-is for now
14560	 */
14561	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14562	comp = NULL;
14563    } else {
14564	comp = pctxt->comp;
14565	pctxt->comp = NULL;
14566    }
14567    xmlXPathFreeParserContext(pctxt);
14568
14569    if (comp != NULL) {
14570	comp->expr = xmlStrdup(str);
14571#ifdef DEBUG_EVAL_COUNTS
14572	comp->string = xmlStrdup(str);
14573	comp->nb = 0;
14574#endif
14575	if ((comp->expr != NULL) &&
14576	    (comp->nbStep > 2) &&
14577	    (comp->last >= 0) &&
14578	    (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14579	{
14580	    xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14581	}
14582    }
14583    return(comp);
14584}
14585
14586/**
14587 * xmlXPathCompile:
14588 * @str:  the XPath expression
14589 *
14590 * Compile an XPath expression
14591 *
14592 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14593 *         the caller has to free the object.
14594 */
14595xmlXPathCompExprPtr
14596xmlXPathCompile(const xmlChar *str) {
14597    return(xmlXPathCtxtCompile(NULL, str));
14598}
14599
14600/**
14601 * xmlXPathCompiledEvalInternal:
14602 * @comp:  the compiled XPath expression
14603 * @ctxt:  the XPath context
14604 * @resObj: the resulting XPath object or NULL
14605 * @toBool: 1 if only a boolean result is requested
14606 *
14607 * Evaluate the Precompiled XPath expression in the given context.
14608 * The caller has to free @resObj.
14609 *
14610 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14611 *         the caller has to free the object.
14612 */
14613static int
14614xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14615			     xmlXPathContextPtr ctxt,
14616			     xmlXPathObjectPtr *resObj,
14617			     int toBool)
14618{
14619    xmlXPathParserContextPtr pctxt;
14620#ifndef LIBXML_THREAD_ENABLED
14621    static int reentance = 0;
14622#endif
14623    int res;
14624
14625    CHECK_CTXT_NEG(ctxt)
14626
14627    if (comp == NULL)
14628	return(-1);
14629    xmlXPathInit();
14630
14631#ifndef LIBXML_THREAD_ENABLED
14632    reentance++;
14633    if (reentance > 1)
14634	xmlXPathDisableOptimizer = 1;
14635#endif
14636
14637#ifdef DEBUG_EVAL_COUNTS
14638    comp->nb++;
14639    if ((comp->string != NULL) && (comp->nb > 100)) {
14640	fprintf(stderr, "100 x %s\n", comp->string);
14641	comp->nb = 0;
14642    }
14643#endif
14644    pctxt = xmlXPathCompParserContext(comp, ctxt);
14645    res = xmlXPathRunEval(pctxt, toBool);
14646
14647    if (resObj) {
14648	if (pctxt->value == NULL) {
14649	    xmlGenericError(xmlGenericErrorContext,
14650		"xmlXPathCompiledEval: evaluation failed\n");
14651	    *resObj = NULL;
14652	} else {
14653	    *resObj = valuePop(pctxt);
14654	}
14655    }
14656
14657    /*
14658    * Pop all remaining objects from the stack.
14659    */
14660    if (pctxt->valueNr > 0) {
14661	xmlXPathObjectPtr tmp;
14662	int stack = 0;
14663
14664	do {
14665	    tmp = valuePop(pctxt);
14666	    if (tmp != NULL) {
14667		if (tmp != NULL)
14668		    stack++;
14669		xmlXPathReleaseObject(ctxt, tmp);
14670	    }
14671	} while (tmp != NULL);
14672	if ((stack != 0) &&
14673	    ((toBool) || ((resObj) && (*resObj))))
14674	{
14675	    xmlGenericError(xmlGenericErrorContext,
14676		"xmlXPathCompiledEval: %d objects left on the stack.\n",
14677		stack);
14678	}
14679    }
14680
14681    if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14682	xmlXPathFreeObject(*resObj);
14683	*resObj = NULL;
14684    }
14685    pctxt->comp = NULL;
14686    xmlXPathFreeParserContext(pctxt);
14687#ifndef LIBXML_THREAD_ENABLED
14688    reentance--;
14689#endif
14690
14691    return(res);
14692}
14693
14694/**
14695 * xmlXPathCompiledEval:
14696 * @comp:  the compiled XPath expression
14697 * @ctx:  the XPath context
14698 *
14699 * Evaluate the Precompiled XPath expression in the given context.
14700 *
14701 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14702 *         the caller has to free the object.
14703 */
14704xmlXPathObjectPtr
14705xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14706{
14707    xmlXPathObjectPtr res = NULL;
14708
14709    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14710    return(res);
14711}
14712
14713/**
14714 * xmlXPathCompiledEvalToBoolean:
14715 * @comp:  the compiled XPath expression
14716 * @ctxt:  the XPath context
14717 *
14718 * Applies the XPath boolean() function on the result of the given
14719 * compiled expression.
14720 *
14721 * Returns 1 if the expression evaluated to true, 0 if to false and
14722 *         -1 in API and internal errors.
14723 */
14724int
14725xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14726			      xmlXPathContextPtr ctxt)
14727{
14728    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14729}
14730
14731/**
14732 * xmlXPathEvalExpr:
14733 * @ctxt:  the XPath Parser context
14734 *
14735 * Parse and evaluate an XPath expression in the given context,
14736 * then push the result on the context stack
14737 */
14738void
14739xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14740#ifdef XPATH_STREAMING
14741    xmlXPathCompExprPtr comp;
14742#endif
14743
14744    if (ctxt == NULL) return;
14745
14746#ifdef XPATH_STREAMING
14747    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14748    if (comp != NULL) {
14749        if (ctxt->comp != NULL)
14750	    xmlXPathFreeCompExpr(ctxt->comp);
14751        ctxt->comp = comp;
14752	if (ctxt->cur != NULL)
14753	    while (*ctxt->cur != 0) ctxt->cur++;
14754    } else
14755#endif
14756    {
14757	xmlXPathCompileExpr(ctxt, 1);
14758	/*
14759	* In this scenario the expression string will sit in ctxt->base.
14760	*/
14761	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14762	    (ctxt->comp != NULL) &&
14763	    (ctxt->base != NULL) &&
14764	    (ctxt->comp->nbStep > 2) &&
14765	    (ctxt->comp->last >= 0) &&
14766	    (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14767	{
14768	    xmlXPathRewriteDOSExpression(ctxt->comp,
14769		&ctxt->comp->steps[ctxt->comp->last]);
14770	}
14771    }
14772    CHECK_ERROR;
14773    xmlXPathRunEval(ctxt, 0);
14774}
14775
14776/**
14777 * xmlXPathEval:
14778 * @str:  the XPath expression
14779 * @ctx:  the XPath context
14780 *
14781 * Evaluate the XPath Location Path in the given context.
14782 *
14783 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14784 *         the caller has to free the object.
14785 */
14786xmlXPathObjectPtr
14787xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14788    xmlXPathParserContextPtr ctxt;
14789    xmlXPathObjectPtr res, tmp, init = NULL;
14790    int stack = 0;
14791
14792    CHECK_CTXT(ctx)
14793
14794    xmlXPathInit();
14795
14796    ctxt = xmlXPathNewParserContext(str, ctx);
14797    xmlXPathEvalExpr(ctxt);
14798
14799    if (ctxt->value == NULL) {
14800	xmlGenericError(xmlGenericErrorContext,
14801		"xmlXPathEval: evaluation failed\n");
14802	res = NULL;
14803    } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14804#ifdef XPATH_STREAMING
14805            && (ctxt->comp->stream == NULL)
14806#endif
14807	      ) {
14808	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14809	res = NULL;
14810    } else {
14811	res = valuePop(ctxt);
14812    }
14813
14814    do {
14815        tmp = valuePop(ctxt);
14816	if (tmp != NULL) {
14817	    if (tmp != init)
14818		stack++;
14819	    xmlXPathReleaseObject(ctx, tmp);
14820        }
14821    } while (tmp != NULL);
14822    if ((stack != 0) && (res != NULL)) {
14823	xmlGenericError(xmlGenericErrorContext,
14824		"xmlXPathEval: %d object left on the stack\n",
14825	        stack);
14826    }
14827    if (ctxt->error != XPATH_EXPRESSION_OK) {
14828	xmlXPathFreeObject(res);
14829	res = NULL;
14830    }
14831
14832    xmlXPathFreeParserContext(ctxt);
14833    return(res);
14834}
14835
14836/**
14837 * xmlXPathEvalExpression:
14838 * @str:  the XPath expression
14839 * @ctxt:  the XPath context
14840 *
14841 * Evaluate the XPath expression in the given context.
14842 *
14843 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14844 *         the caller has to free the object.
14845 */
14846xmlXPathObjectPtr
14847xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14848    xmlXPathParserContextPtr pctxt;
14849    xmlXPathObjectPtr res, tmp;
14850    int stack = 0;
14851
14852    CHECK_CTXT(ctxt)
14853
14854    xmlXPathInit();
14855
14856    pctxt = xmlXPathNewParserContext(str, ctxt);
14857    xmlXPathEvalExpr(pctxt);
14858
14859    if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
14860	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14861	res = NULL;
14862    } else {
14863	res = valuePop(pctxt);
14864    }
14865    do {
14866        tmp = valuePop(pctxt);
14867	if (tmp != NULL) {
14868	    xmlXPathReleaseObject(ctxt, tmp);
14869	    stack++;
14870	}
14871    } while (tmp != NULL);
14872    if ((stack != 0) && (res != NULL)) {
14873	xmlGenericError(xmlGenericErrorContext,
14874		"xmlXPathEvalExpression: %d object left on the stack\n",
14875	        stack);
14876    }
14877    xmlXPathFreeParserContext(pctxt);
14878    return(res);
14879}
14880
14881/************************************************************************
14882 *									*
14883 *	Extra functions not pertaining to the XPath spec		*
14884 *									*
14885 ************************************************************************/
14886/**
14887 * xmlXPathEscapeUriFunction:
14888 * @ctxt:  the XPath Parser context
14889 * @nargs:  the number of arguments
14890 *
14891 * Implement the escape-uri() XPath function
14892 *    string escape-uri(string $str, bool $escape-reserved)
14893 *
14894 * This function applies the URI escaping rules defined in section 2 of [RFC
14895 * 2396] to the string supplied as $uri-part, which typically represents all
14896 * or part of a URI. The effect of the function is to replace any special
14897 * character in the string by an escape sequence of the form %xx%yy...,
14898 * where xxyy... is the hexadecimal representation of the octets used to
14899 * represent the character in UTF-8.
14900 *
14901 * The set of characters that are escaped depends on the setting of the
14902 * boolean argument $escape-reserved.
14903 *
14904 * If $escape-reserved is true, all characters are escaped other than lower
14905 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14906 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14907 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14908 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14909 * A-F).
14910 *
14911 * If $escape-reserved is false, the behavior differs in that characters
14912 * referred to in [RFC 2396] as reserved characters are not escaped. These
14913 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14914 *
14915 * [RFC 2396] does not define whether escaped URIs should use lower case or
14916 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14917 * compared using string comparison functions, this function must always use
14918 * the upper-case letters A-F.
14919 *
14920 * Generally, $escape-reserved should be set to true when escaping a string
14921 * that is to form a single part of a URI, and to false when escaping an
14922 * entire URI or URI reference.
14923 *
14924 * In the case of non-ascii characters, the string is encoded according to
14925 * utf-8 and then converted according to RFC 2396.
14926 *
14927 * Examples
14928 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14929 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14930 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14931 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14932 *
14933 */
14934static void
14935xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14936    xmlXPathObjectPtr str;
14937    int escape_reserved;
14938    xmlBufferPtr target;
14939    xmlChar *cptr;
14940    xmlChar escape[4];
14941
14942    CHECK_ARITY(2);
14943
14944    escape_reserved = xmlXPathPopBoolean(ctxt);
14945
14946    CAST_TO_STRING;
14947    str = valuePop(ctxt);
14948
14949    target = xmlBufferCreate();
14950
14951    escape[0] = '%';
14952    escape[3] = 0;
14953
14954    if (target) {
14955	for (cptr = str->stringval; *cptr; cptr++) {
14956	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
14957		(*cptr >= 'a' && *cptr <= 'z') ||
14958		(*cptr >= '0' && *cptr <= '9') ||
14959		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
14960		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
14961		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14962		(*cptr == '%' &&
14963		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14964		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14965		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
14966		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14967		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14968		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14969		(!escape_reserved &&
14970		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14971		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14972		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14973		  *cptr == ','))) {
14974		xmlBufferAdd(target, cptr, 1);
14975	    } else {
14976		if ((*cptr >> 4) < 10)
14977		    escape[1] = '0' + (*cptr >> 4);
14978		else
14979		    escape[1] = 'A' - 10 + (*cptr >> 4);
14980		if ((*cptr & 0xF) < 10)
14981		    escape[2] = '0' + (*cptr & 0xF);
14982		else
14983		    escape[2] = 'A' - 10 + (*cptr & 0xF);
14984
14985		xmlBufferAdd(target, &escape[0], 3);
14986	    }
14987	}
14988    }
14989    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14990	xmlBufferContent(target)));
14991    xmlBufferFree(target);
14992    xmlXPathReleaseObject(ctxt->context, str);
14993}
14994
14995/**
14996 * xmlXPathRegisterAllFunctions:
14997 * @ctxt:  the XPath context
14998 *
14999 * Registers all default XPath functions in this context
15000 */
15001void
15002xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15003{
15004    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15005                         xmlXPathBooleanFunction);
15006    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15007                         xmlXPathCeilingFunction);
15008    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15009                         xmlXPathCountFunction);
15010    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15011                         xmlXPathConcatFunction);
15012    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15013                         xmlXPathContainsFunction);
15014    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15015                         xmlXPathIdFunction);
15016    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15017                         xmlXPathFalseFunction);
15018    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15019                         xmlXPathFloorFunction);
15020    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15021                         xmlXPathLastFunction);
15022    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15023                         xmlXPathLangFunction);
15024    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15025                         xmlXPathLocalNameFunction);
15026    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15027                         xmlXPathNotFunction);
15028    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15029                         xmlXPathNameFunction);
15030    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15031                         xmlXPathNamespaceURIFunction);
15032    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15033                         xmlXPathNormalizeFunction);
15034    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15035                         xmlXPathNumberFunction);
15036    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15037                         xmlXPathPositionFunction);
15038    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15039                         xmlXPathRoundFunction);
15040    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15041                         xmlXPathStringFunction);
15042    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15043                         xmlXPathStringLengthFunction);
15044    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15045                         xmlXPathStartsWithFunction);
15046    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15047                         xmlXPathSubstringFunction);
15048    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15049                         xmlXPathSubstringBeforeFunction);
15050    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15051                         xmlXPathSubstringAfterFunction);
15052    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15053                         xmlXPathSumFunction);
15054    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15055                         xmlXPathTrueFunction);
15056    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15057                         xmlXPathTranslateFunction);
15058
15059    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15060	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15061                         xmlXPathEscapeUriFunction);
15062}
15063
15064#endif /* LIBXML_XPATH_ENABLED */
15065#define bottom_xpath
15066#include "elfgcchack.h"
15067