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