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