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