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