xpath.c revision f62ceffb7e538bf78894d2e2192848fdb40fe278
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@w3.org
14 */
15
16#ifdef WIN32
17#include "win32config.h"
18#else
19#include "config.h"
20#endif
21
22#include <libxml/xmlversion.h>
23#ifdef LIBXML_XPATH_ENABLED
24
25#include <stdio.h>
26#include <string.h>
27
28#ifdef HAVE_SYS_TYPES_H
29#include <sys/types.h>
30#endif
31#ifdef HAVE_MATH_H
32#include <math.h>
33#endif
34#ifdef HAVE_MATH_H
35#include <float.h>
36#endif
37#ifdef HAVE_IEEEFP_H
38#include <ieeefp.h>
39#endif
40#ifdef HAVE_NAN_H
41#include <nan.h>
42#endif
43#ifdef HAVE_CTYPE_H
44#include <ctype.h>
45#endif
46
47#include <libxml/xmlmemory.h>
48#include <libxml/tree.h>
49#include <libxml/valid.h>
50#include <libxml/xpath.h>
51#include <libxml/xpathInternals.h>
52#include <libxml/parserInternals.h>
53#include <libxml/hash.h>
54#ifdef LIBXML_XPTR_ENABLED
55#include <libxml/xpointer.h>
56#endif
57#ifdef LIBXML_DEBUG_ENABLED
58#include <libxml/debugXML.h>
59#endif
60#include <libxml/xmlerror.h>
61
62/* #define DEBUG */
63/* #define DEBUG_STEP */
64/* #define DEBUG_EXPR */
65
66void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
67double xmlXPathStringEvalNumber(const xmlChar *str);
68
69/*
70 * Setup stuff for floating point
71 * The lack of portability of this section of the libc is annoying !
72 */
73double xmlXPathNAN = 0;
74double xmlXPathPINF = 1;
75double xmlXPathNINF = -1;
76
77#ifndef isinf
78#ifndef HAVE_ISINF
79
80#if HAVE_FPCLASS
81
82int isinf(double d) {
83    fpclass_t	type = fpclass(d);
84    switch (type) {
85	case FP_NINF:
86	    return(-1);
87	case FP_PINF:
88	    return(1);
89    }
90    return(0);
91}
92
93#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
94
95#if HAVE_FP_CLASS_H
96#include <fp_class.h>
97#endif
98
99int isinf(double d) {
100#if HAVE_FP_CLASS
101    int	fpclass = fp_class(d);
102#else
103    int	fpclass = fp_class_d(d);
104#endif
105    if (fpclass == FP_POS_INF)
106	return(1);
107    if (fpclass == FP_NEG_INF)
108	return(-1);
109    return(0);
110}
111
112#elif defined(HAVE_CLASS)
113
114int isinf(double d) {
115    int	fpclass = class(d);
116    if (fpclass == FP_PLUS_INF)
117	return(1);
118    if (fpclass == FP_MINUS_INF)
119	return(-1);
120    return(0);
121}
122#elif defined(finite) || defined(HAVE_FINITE)
123int isinf(double x) { return !finite(x) && x==x; }
124#elif defined(HUGE_VAL)
125int isinf(double x)
126{
127    if (x == HUGE_VAL)
128        return(1);
129    if (x == -HUGE_VAL)
130        return(-1);
131    return(0);
132}
133#endif
134
135#endif /* ! HAVE_ISINF */
136#endif /* ! defined(isinf) */
137
138#ifndef isnan
139#ifndef HAVE_ISNAN
140
141#ifdef HAVE_ISNAND
142#define isnan(f) isnand(f)
143#endif /* HAVE_iSNAND */
144
145#endif /* ! HAVE_iSNAN */
146#endif /* ! defined(isnan) */
147
148/**
149 * xmlXPathInit:
150 *
151 * Initialize the XPath environment
152 */
153void
154xmlXPathInit(void) {
155    static int initialized = 0;
156
157    if (initialized) return;
158
159    xmlXPathNAN = 0;
160    xmlXPathNAN /= 0;
161
162    xmlXPathPINF = 1;
163    xmlXPathPINF /= 0;
164
165    xmlXPathNINF = -1;
166    xmlXPathNINF /= 0;
167
168    initialized = 1;
169}
170
171/************************************************************************
172 *									*
173 * 		Debugging related functions				*
174 *									*
175 ************************************************************************/
176
177#define TODO 								\
178    xmlGenericError(xmlGenericErrorContext,				\
179	    "Unimplemented block at %s:%d\n",				\
180            __FILE__, __LINE__);
181
182#define STRANGE 							\
183    xmlGenericError(xmlGenericErrorContext,				\
184	    "Internal error at %s:%d\n",				\
185            __FILE__, __LINE__);
186
187#ifdef LIBXML_DEBUG_ENABLED
188void xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
189    int i;
190    char shift[100];
191
192    for (i = 0;((i < depth) && (i < 25));i++)
193        shift[2 * i] = shift[2 * i + 1] = ' ';
194    shift[2 * i] = shift[2 * i + 1] = 0;
195    if (cur == NULL) {
196	fprintf(output, shift);
197	fprintf(output, "Node is NULL !\n");
198	return;
199
200    }
201
202    if ((cur->type == XML_DOCUMENT_NODE) ||
203	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
204	fprintf(output, shift);
205	fprintf(output, " /\n");
206    } else if (cur->type == XML_ATTRIBUTE_NODE)
207	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
208    else
209	xmlDebugDumpOneNode(output, cur, depth);
210}
211
212void xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
213    int i;
214    char shift[100];
215
216    for (i = 0;((i < depth) && (i < 25));i++)
217        shift[2 * i] = shift[2 * i + 1] = ' ';
218    shift[2 * i] = shift[2 * i + 1] = 0;
219
220    if (cur == NULL) {
221	fprintf(output, shift);
222	fprintf(output, "NodeSet is NULL !\n");
223	return;
224
225    }
226
227    fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
228    for (i = 0;i < cur->nodeNr;i++) {
229	fprintf(output, shift);
230        fprintf(output, "%d", i + 1);
231	xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
232    }
233}
234
235#if defined(LIBXML_XPTR_ENABLED)
236void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
237void xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
238    int i;
239    char shift[100];
240
241    for (i = 0;((i < depth) && (i < 25));i++)
242        shift[2 * i] = shift[2 * i + 1] = ' ';
243    shift[2 * i] = shift[2 * i + 1] = 0;
244
245    if (cur == NULL) {
246	fprintf(output, shift);
247	fprintf(output, "LocationSet is NULL !\n");
248	return;
249
250    }
251
252    for (i = 0;i < cur->locNr;i++) {
253	fprintf(output, shift);
254        fprintf(output, "%d : ", i + 1);
255	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
256    }
257}
258#endif
259
260void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
261    int i;
262    char shift[100];
263
264    for (i = 0;((i < depth) && (i < 25));i++)
265        shift[2 * i] = shift[2 * i + 1] = ' ';
266    shift[2 * i] = shift[2 * i + 1] = 0;
267
268    fprintf(output, shift);
269
270    if (cur == NULL) {
271        fprintf(output, "Object is empty (NULL)\n");
272	return;
273    }
274    switch(cur->type) {
275        case XPATH_UNDEFINED:
276	    fprintf(output, "Object is uninitialized\n");
277	    break;
278        case XPATH_NODESET:
279	    fprintf(output, "Object is a Node Set :\n");
280	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
281	    break;
282        case XPATH_BOOLEAN:
283	    fprintf(output, "Object is a Boolean : ");
284	    if (cur->boolval) fprintf(output, "true\n");
285	    else fprintf(output, "false\n");
286	    break;
287        case XPATH_NUMBER:
288	    fprintf(output, "Object is a number : %0g\n", cur->floatval);
289	    break;
290        case XPATH_STRING:
291	    fprintf(output, "Object is a string : ");
292	    xmlDebugDumpString(output, cur->stringval);
293	    fprintf(output, "\n");
294	    break;
295	case XPATH_POINT:
296	    fprintf(output, "Object is a point : index %d in node", cur->index);
297	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
298	    fprintf(output, "\n");
299	    break;
300	case XPATH_RANGE:
301	    if ((cur->user2 == NULL) ||
302		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
303		fprintf(output, "Object is a collapsed range :\n");
304		fprintf(output, shift);
305		if (cur->index >= 0)
306		    fprintf(output, "index %d in ", cur->index);
307		fprintf(output, "node\n");
308		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
309			              depth + 1);
310	    } else  {
311		fprintf(output, "Object is a range :\n");
312		fprintf(output, shift);
313		fprintf(output, "From ");
314		if (cur->index >= 0)
315		    fprintf(output, "index %d in ", cur->index);
316		fprintf(output, "node\n");
317		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
318			              depth + 1);
319		fprintf(output, shift);
320		fprintf(output, "To ");
321		if (cur->index2 >= 0)
322		    fprintf(output, "index %d in ", cur->index2);
323		fprintf(output, "node\n");
324		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
325			              depth + 1);
326		fprintf(output, "\n");
327	    }
328	    break;
329	case XPATH_LOCATIONSET:
330#if defined(LIBXML_XPTR_ENABLED)
331	    fprintf(output, "Object is a Location Set:\n");
332	    xmlXPathDebugDumpLocationSet(output,
333		    (xmlLocationSetPtr) cur->user, depth);
334#endif
335	    break;
336	case XPATH_USERS:
337	    fprintf(output, "Object is user defined\n");
338	    break;
339    }
340}
341#endif
342
343/************************************************************************
344 *									*
345 * 		Parser stacks related functions and macros		*
346 *									*
347 ************************************************************************/
348
349/*
350 * Generic function for accessing stacks in the Parser Context
351 */
352
353#define PUSH_AND_POP(type, name)					\
354extern int name##Push(xmlXPathParserContextPtr ctxt, type value) {	\
355    if (ctxt->name##Nr >= ctxt->name##Max) {				\
356	ctxt->name##Max *= 2;						\
357        ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab,		\
358	             ctxt->name##Max * sizeof(ctxt->name##Tab[0]));	\
359        if (ctxt->name##Tab == NULL) {					\
360	    xmlGenericError(xmlGenericErrorContext,			\
361		    "realloc failed !\n");				\
362	    return(0);							\
363	}								\
364    }									\
365    ctxt->name##Tab[ctxt->name##Nr] = value;				\
366    ctxt->name = value;							\
367    return(ctxt->name##Nr++);						\
368}									\
369extern type name##Pop(xmlXPathParserContextPtr ctxt) {			\
370    type ret;								\
371    if (ctxt->name##Nr <= 0) return(0);					\
372    ctxt->name##Nr--;							\
373    if (ctxt->name##Nr > 0)						\
374	ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1];		\
375    else								\
376        ctxt->name = NULL;						\
377    ret = ctxt->name##Tab[ctxt->name##Nr];				\
378    ctxt->name##Tab[ctxt->name##Nr] = 0;				\
379    return(ret);							\
380}									\
381
382PUSH_AND_POP(xmlXPathObjectPtr, value)
383
384/*
385 * Macros for accessing the content. Those should be used only by the parser,
386 * and not exported.
387 *
388 * Dirty macros, i.e. one need to make assumption on the context to use them
389 *
390 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
391 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
392 *           in ISO-Latin or UTF-8.
393 *           This should be used internally by the parser
394 *           only to compare to ASCII values otherwise it would break when
395 *           running with UTF-8 encoding.
396 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
397 *           to compare on ASCII based substring.
398 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
399 *           strings within the parser.
400 *   CURRENT Returns the current char value, with the full decoding of
401 *           UTF-8 if we are using this mode. It returns an int.
402 *   NEXT    Skip to the next character, this does the proper decoding
403 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
404 *           It returns the pointer to the current xmlChar.
405 */
406
407#define CUR (*ctxt->cur)
408#define SKIP(val) ctxt->cur += (val)
409#define NXT(val) ctxt->cur[(val)]
410#define CUR_PTR ctxt->cur
411
412#define SKIP_BLANKS 							\
413    while (IS_BLANK(*(ctxt->cur))) NEXT
414
415#define CURRENT (*ctxt->cur)
416#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
417
418/************************************************************************
419 *									*
420 *			Error handling routines				*
421 *									*
422 ************************************************************************/
423
424
425const char *xmlXPathErrorMessages[] = {
426    "Ok",
427    "Number encoding",
428    "Unfinished litteral",
429    "Start of litteral",
430    "Expected $ for variable reference",
431    "Undefined variable",
432    "Invalid predicate",
433    "Invalid expression",
434    "Missing closing curly brace",
435    "Unregistered function",
436    "Invalid operand",
437    "Invalid type",
438    "Invalid number of arguments",
439    "Invalid context size",
440    "Invalid context position",
441    "Memory allocation error",
442    "Syntax error",
443    "Resource error",
444    "Sub resource error"
445};
446
447/**
448 * xmlXPathError:
449 * @ctxt:  the XPath Parser context
450 * @file:  the file name
451 * @line:  the line number
452 * @no:  the error number
453 *
454 * Create a new xmlNodeSetPtr of type double and of value @val
455 *
456 * Returns the newly created object.
457 */
458void
459xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
460              int line, int no) {
461    int n;
462    const xmlChar *cur;
463    const xmlChar *base;
464
465    xmlGenericError(xmlGenericErrorContext,
466	    "Error %s:%d: %s\n", file, line,
467            xmlXPathErrorMessages[no]);
468
469    cur = ctxt->cur;
470    base = ctxt->base;
471    while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
472	cur--;
473    }
474    n = 0;
475    while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
476        cur--;
477    if ((*cur == '\n') || (*cur == '\r')) cur++;
478    base = cur;
479    n = 0;
480    while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
481        xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
482	n++;
483    }
484    xmlGenericError(xmlGenericErrorContext, "\n");
485    cur = ctxt->cur;
486    while ((*cur == '\n') || (*cur == '\r'))
487	cur--;
488    n = 0;
489    while ((cur != base) && (n++ < 80)) {
490        xmlGenericError(xmlGenericErrorContext, " ");
491        base++;
492    }
493    xmlGenericError(xmlGenericErrorContext,"^\n");
494}
495
496
497/************************************************************************
498 *									*
499 *			Routines to handle NodeSets			*
500 *									*
501 ************************************************************************/
502
503#define XML_NODESET_DEFAULT	10
504/**
505 * xmlXPathNodeSetCreate:
506 * @val:  an initial xmlNodePtr, or NULL
507 *
508 * Create a new xmlNodeSetPtr of type double and of value @val
509 *
510 * Returns the newly created object.
511 */
512xmlNodeSetPtr
513xmlXPathNodeSetCreate(xmlNodePtr val) {
514    xmlNodeSetPtr ret;
515
516    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
517    if (ret == NULL) {
518        xmlGenericError(xmlGenericErrorContext,
519		"xmlXPathNewNodeSet: out of memory\n");
520	return(NULL);
521    }
522    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
523    if (val != NULL) {
524        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
525					     sizeof(xmlNodePtr));
526	if (ret->nodeTab == NULL) {
527	    xmlGenericError(xmlGenericErrorContext,
528		    "xmlXPathNewNodeSet: out of memory\n");
529	    return(NULL);
530	}
531	memset(ret->nodeTab, 0 ,
532	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
533        ret->nodeMax = XML_NODESET_DEFAULT;
534	ret->nodeTab[ret->nodeNr++] = val;
535    }
536    return(ret);
537}
538
539/**
540 * xmlXPathNodeSetAdd:
541 * @cur:  the initial node set
542 * @val:  a new xmlNodePtr
543 *
544 * add a new xmlNodePtr ot an existing NodeSet
545 */
546void
547xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
548    int i;
549
550    if (val == NULL) return;
551
552    /*
553     * check against doublons
554     */
555    for (i = 0;i < cur->nodeNr;i++)
556        if (cur->nodeTab[i] == val) return;
557
558    /*
559     * grow the nodeTab if needed
560     */
561    if (cur->nodeMax == 0) {
562        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
563					     sizeof(xmlNodePtr));
564	if (cur->nodeTab == NULL) {
565	    xmlGenericError(xmlGenericErrorContext,
566		    "xmlXPathNodeSetAdd: out of memory\n");
567	    return;
568	}
569	memset(cur->nodeTab, 0 ,
570	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
571        cur->nodeMax = XML_NODESET_DEFAULT;
572    } else if (cur->nodeNr == cur->nodeMax) {
573        xmlNodePtr *temp;
574
575        cur->nodeMax *= 2;
576	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
577				      sizeof(xmlNodePtr));
578	if (temp == NULL) {
579	    xmlGenericError(xmlGenericErrorContext,
580		    "xmlXPathNodeSetAdd: out of memory\n");
581	    return;
582	}
583	cur->nodeTab = temp;
584    }
585    cur->nodeTab[cur->nodeNr++] = val;
586}
587
588/**
589 * xmlXPathNodeSetMerge:
590 * @val1:  the first NodeSet or NULL
591 * @val2:  the second NodeSet
592 *
593 * Merges two nodesets, all nodes from @val2 are added to @val1
594 * if @val1 is NULL, a new set is created and copied from @val2
595 *
596 * Returns val1 once extended or NULL in case of error.
597 */
598xmlNodeSetPtr
599xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
600    int i, j, initNr;
601
602    if (val2 == NULL) return(val1);
603    if (val1 == NULL) {
604	val1 = xmlXPathNodeSetCreate(NULL);
605    }
606
607    initNr = val1->nodeNr;
608
609    for (i = 0;i < val2->nodeNr;i++) {
610	/*
611	 * check against doublons
612	 */
613	for (j = 0; j < initNr; j++)
614	    if (val1->nodeTab[j] == val2->nodeTab[i]) continue;
615
616	/*
617	 * grow the nodeTab if needed
618	 */
619	if (val1->nodeMax == 0) {
620	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
621						    sizeof(xmlNodePtr));
622	    if (val1->nodeTab == NULL) {
623		xmlGenericError(xmlGenericErrorContext,
624				"xmlXPathNodeSetMerge: out of memory\n");
625		return(NULL);
626	    }
627	    memset(val1->nodeTab, 0 ,
628		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
629	    val1->nodeMax = XML_NODESET_DEFAULT;
630	} else if (val1->nodeNr == val1->nodeMax) {
631	    xmlNodePtr *temp;
632
633	    val1->nodeMax *= 2;
634	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
635					     sizeof(xmlNodePtr));
636	    if (temp == NULL) {
637		xmlGenericError(xmlGenericErrorContext,
638				"xmlXPathNodeSetMerge: out of memory\n");
639		return(NULL);
640	    }
641	    val1->nodeTab = temp;
642	}
643	val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
644    }
645
646    return(val1);
647}
648
649/**
650 * xmlXPathNodeSetDel:
651 * @cur:  the initial node set
652 * @val:  an xmlNodePtr
653 *
654 * Removes an xmlNodePtr from an existing NodeSet
655 */
656void
657xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
658    int i;
659
660    if (cur == NULL) return;
661    if (val == NULL) return;
662
663    /*
664     * check against doublons
665     */
666    for (i = 0;i < cur->nodeNr;i++)
667        if (cur->nodeTab[i] == val) break;
668
669    if (i >= cur->nodeNr) {
670#ifdef DEBUG
671        xmlGenericError(xmlGenericErrorContext,
672	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
673		val->name);
674#endif
675        return;
676    }
677    cur->nodeNr--;
678    for (;i < cur->nodeNr;i++)
679        cur->nodeTab[i] = cur->nodeTab[i + 1];
680    cur->nodeTab[cur->nodeNr] = NULL;
681}
682
683/**
684 * xmlXPathNodeSetRemove:
685 * @cur:  the initial node set
686 * @val:  the index to remove
687 *
688 * Removes an entry from an existing NodeSet list.
689 */
690void
691xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
692    if (cur == NULL) return;
693    if (val >= cur->nodeNr) return;
694    cur->nodeNr--;
695    for (;val < cur->nodeNr;val++)
696        cur->nodeTab[val] = cur->nodeTab[val + 1];
697    cur->nodeTab[cur->nodeNr] = NULL;
698}
699
700/**
701 * xmlXPathFreeNodeSet:
702 * @obj:  the xmlNodeSetPtr to free
703 *
704 * Free the NodeSet compound (not the actual nodes !).
705 */
706void
707xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
708    if (obj == NULL) return;
709    if (obj->nodeTab != NULL) {
710#ifdef DEBUG
711	memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
712#endif
713	xmlFree(obj->nodeTab);
714    }
715#ifdef DEBUG
716    memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
717#endif
718    xmlFree(obj);
719}
720
721#if defined(DEBUG) || defined(DEBUG_STEP)
722/**
723 * xmlGenericErrorContextNodeSet:
724 * @output:  a FILE * for the output
725 * @obj:  the xmlNodeSetPtr to free
726 *
727 * Quick display of a NodeSet
728 */
729void
730xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
731    int i;
732
733    if (output == NULL) output = xmlGenericErrorContext;
734    if (obj == NULL)  {
735        fprintf(output, "NodeSet == NULL !\n");
736	return;
737    }
738    if (obj->nodeNr == 0) {
739        fprintf(output, "NodeSet is empty\n");
740	return;
741    }
742    if (obj->nodeTab == NULL) {
743	fprintf(output, " nodeTab == NULL !\n");
744	return;
745    }
746    for (i = 0; i < obj->nodeNr; i++) {
747        if (obj->nodeTab[i] == NULL) {
748	    fprintf(output, " NULL !\n");
749	    return;
750        }
751	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
752	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
753	    fprintf(output, " /");
754	else if (obj->nodeTab[i]->name == NULL)
755	    fprintf(output, " noname!");
756	else fprintf(output, " %s", obj->nodeTab[i]->name);
757    }
758    fprintf(output, "\n");
759}
760#endif
761
762/**
763 * xmlXPathNewNodeSet:
764 * @val:  the NodePtr value
765 *
766 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
767 * it with the single Node @val
768 *
769 * Returns the newly created object.
770 */
771xmlXPathObjectPtr
772xmlXPathNewNodeSet(xmlNodePtr val) {
773    xmlXPathObjectPtr ret;
774
775    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
776    if (ret == NULL) {
777        xmlGenericError(xmlGenericErrorContext,
778		"xmlXPathNewNodeSet: out of memory\n");
779	return(NULL);
780    }
781    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
782    ret->type = XPATH_NODESET;
783    ret->nodesetval = xmlXPathNodeSetCreate(val);
784    return(ret);
785}
786
787/**
788 * xmlXPathNewNodeSetList:
789 * @val:  an existing NodeSet
790 *
791 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
792 * it with the Nodeset @val
793 *
794 * Returns the newly created object.
795 */
796xmlXPathObjectPtr
797xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
798    xmlXPathObjectPtr ret;
799    int i;
800
801    if (val == NULL)
802    	ret = NULL;
803    else if (val->nodeTab == NULL)
804	    ret = xmlXPathNewNodeSet(NULL);
805    else
806    	{
807	    ret = xmlXPathNewNodeSet(val->nodeTab[0]);
808	    for (i = 1; i < val->nodeNr; ++i)
809	    	xmlXPathNodeSetAdd(ret->nodesetval, val->nodeTab[i]);
810	    }
811
812    return(ret);
813}
814
815/**
816 * xmlXPathWrapNodeSet:
817 * @val:  the NodePtr value
818 *
819 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
820 *
821 * Returns the newly created object.
822 */
823xmlXPathObjectPtr
824xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
825    xmlXPathObjectPtr ret;
826
827    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
828    if (ret == NULL) {
829        xmlGenericError(xmlGenericErrorContext,
830		"xmlXPathWrapNodeSet: out of memory\n");
831	return(NULL);
832    }
833    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
834    ret->type = XPATH_NODESET;
835    ret->nodesetval = val;
836    return(ret);
837}
838
839/**
840 * xmlXPathFreeNodeSetList:
841 * @obj:  an existing NodeSetList object
842 *
843 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
844 * the list contrary to xmlXPathFreeObject().
845 */
846void
847xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
848    if (obj == NULL) return;
849#ifdef DEBUG
850    memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
851#endif
852    xmlFree(obj);
853}
854
855/************************************************************************
856 *									*
857 *		Routines to handle extra functions			*
858 *									*
859 ************************************************************************/
860
861/**
862 * xmlXPathRegisterFunc:
863 * @ctxt:  the XPath context
864 * @name:  the function name
865 * @f:  the function implementation or NULL
866 *
867 * Register a new function. If @f is NULL it unregisters the function
868 *
869 * Returns 0 in case of success, -1 in case of error
870 */
871int
872xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
873		     xmlXPathFunction f) {
874    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
875}
876
877/**
878 * xmlXPathRegisterFuncNS:
879 * @ctxt:  the XPath context
880 * @name:  the function name
881 * @ns_uri:  the function namespace URI
882 * @f:  the function implementation or NULL
883 *
884 * Register a new function. If @f is NULL it unregisters the function
885 *
886 * Returns 0 in case of success, -1 in case of error
887 */
888int
889xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
890		       const xmlChar *ns_uri, xmlXPathFunction f) {
891    if (ctxt == NULL)
892	return(-1);
893    if (name == NULL)
894	return(-1);
895
896    if (ctxt->funcHash == NULL)
897	ctxt->funcHash = xmlHashCreate(0);
898    if (ctxt->funcHash == NULL)
899	return(-1);
900    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
901}
902
903/**
904 * xmlXPathFunctionLookup:
905 * @ctxt:  the XPath context
906 * @name:  the function name
907 *
908 * Search in the Function array of the context for the given
909 * function.
910 *
911 * Returns the xmlXPathFunction or NULL if not found
912 */
913xmlXPathFunction
914xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
915    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
916}
917
918/**
919 * xmlXPathFunctionLookupNS:
920 * @ctxt:  the XPath context
921 * @name:  the function name
922 * @ns_uri:  the function namespace URI
923 *
924 * Search in the Function array of the context for the given
925 * function.
926 *
927 * Returns the xmlXPathFunction or NULL if not found
928 */
929xmlXPathFunction
930xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
931			 const xmlChar *ns_uri) {
932    if (ctxt == NULL)
933	return(NULL);
934    if (ctxt->funcHash == NULL)
935	return(NULL);
936    if (name == NULL)
937	return(NULL);
938
939    return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
940}
941
942/**
943 * xmlXPathRegisteredFuncsCleanup:
944 * @ctxt:  the XPath context
945 *
946 * Cleanup the XPath context data associated to registered functions
947 */
948void
949xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
950    if (ctxt == NULL)
951	return;
952
953    xmlHashFree(ctxt->funcHash, NULL);
954    ctxt->funcHash = NULL;
955}
956
957/************************************************************************
958 *									*
959 *			Routines to handle Variable			*
960 *									*
961 ************************************************************************/
962
963/**
964 * xmlXPathRegisterVariable:
965 * @ctxt:  the XPath context
966 * @name:  the variable name
967 * @value:  the variable value or NULL
968 *
969 * Register a new variable value. If @value is NULL it unregisters
970 * the variable
971 *
972 * Returns 0 in case of success, -1 in case of error
973 */
974int
975xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
976			 xmlXPathObjectPtr value) {
977    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
978}
979
980/**
981 * xmlXPathRegisterVariableNS:
982 * @ctxt:  the XPath context
983 * @name:  the variable name
984 * @ns_uri:  the variable namespace URI
985 * @value:  the variable value or NULL
986 *
987 * Register a new variable value. If @value is NULL it unregisters
988 * the variable
989 *
990 * Returns 0 in case of success, -1 in case of error
991 */
992int
993xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
994			   const xmlChar *ns_uri,
995			   xmlXPathObjectPtr value) {
996    if (ctxt == NULL)
997	return(-1);
998    if (name == NULL)
999	return(-1);
1000
1001    if (ctxt->varHash == NULL)
1002	ctxt->varHash = xmlHashCreate(0);
1003    if (ctxt->varHash == NULL)
1004	return(-1);
1005    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1006			       (void *) value,
1007			       (xmlHashDeallocator)xmlXPathFreeObject));
1008}
1009
1010/**
1011 * xmlXPathVariableLookup:
1012 * @ctxt:  the XPath context
1013 * @name:  the variable name
1014 *
1015 * Search in the Variable array of the context for the given
1016 * variable value.
1017 *
1018 * Returns the value or NULL if not found
1019 */
1020xmlXPathObjectPtr
1021xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1022    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1023}
1024
1025/**
1026 * xmlXPathVariableLookupNS:
1027 * @ctxt:  the XPath context
1028 * @name:  the variable name
1029 * @ns_uri:  the variable namespace URI
1030 *
1031 * Search in the Variable array of the context for the given
1032 * variable value.
1033 *
1034 * Returns the value or NULL if not found
1035 */
1036xmlXPathObjectPtr
1037xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1038			 const xmlChar *ns_uri) {
1039    if (ctxt == NULL)
1040	return(NULL);
1041    if (ctxt->varHash == NULL)
1042	return(NULL);
1043    if (name == NULL)
1044	return(NULL);
1045
1046    return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
1047}
1048
1049/**
1050 * xmlXPathRegisteredVariablesCleanup:
1051 * @ctxt:  the XPath context
1052 *
1053 * Cleanup the XPath context data associated to registered variables
1054 */
1055void
1056xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
1057    if (ctxt == NULL)
1058	return;
1059
1060    xmlHashFree(ctxt->varHash, NULL);
1061    ctxt->varHash = NULL;
1062}
1063
1064/************************************************************************
1065 *									*
1066 *			Routines to handle Values			*
1067 *									*
1068 ************************************************************************/
1069
1070/* Allocations are terrible, one need to optimize all this !!! */
1071
1072/**
1073 * xmlXPathNewFloat:
1074 * @val:  the double value
1075 *
1076 * Create a new xmlXPathObjectPtr of type double and of value @val
1077 *
1078 * Returns the newly created object.
1079 */
1080xmlXPathObjectPtr
1081xmlXPathNewFloat(double val) {
1082    xmlXPathObjectPtr ret;
1083
1084    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1085    if (ret == NULL) {
1086        xmlGenericError(xmlGenericErrorContext,
1087		"xmlXPathNewFloat: out of memory\n");
1088	return(NULL);
1089    }
1090    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1091    ret->type = XPATH_NUMBER;
1092    ret->floatval = val;
1093    return(ret);
1094}
1095
1096/**
1097 * xmlXPathNewBoolean:
1098 * @val:  the boolean value
1099 *
1100 * Create a new xmlXPathObjectPtr of type boolean and of value @val
1101 *
1102 * Returns the newly created object.
1103 */
1104xmlXPathObjectPtr
1105xmlXPathNewBoolean(int val) {
1106    xmlXPathObjectPtr ret;
1107
1108    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1109    if (ret == NULL) {
1110        xmlGenericError(xmlGenericErrorContext,
1111		"xmlXPathNewBoolean: out of memory\n");
1112	return(NULL);
1113    }
1114    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1115    ret->type = XPATH_BOOLEAN;
1116    ret->boolval = (val != 0);
1117    return(ret);
1118}
1119
1120/**
1121 * xmlXPathNewString:
1122 * @val:  the xmlChar * value
1123 *
1124 * Create a new xmlXPathObjectPtr of type string and of value @val
1125 *
1126 * Returns the newly created object.
1127 */
1128xmlXPathObjectPtr
1129xmlXPathNewString(const xmlChar *val) {
1130    xmlXPathObjectPtr ret;
1131
1132    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1133    if (ret == NULL) {
1134        xmlGenericError(xmlGenericErrorContext,
1135		"xmlXPathNewString: out of memory\n");
1136	return(NULL);
1137    }
1138    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1139    ret->type = XPATH_STRING;
1140    ret->stringval = xmlStrdup(val);
1141    return(ret);
1142}
1143
1144/**
1145 * xmlXPathNewCString:
1146 * @val:  the char * value
1147 *
1148 * Create a new xmlXPathObjectPtr of type string and of value @val
1149 *
1150 * Returns the newly created object.
1151 */
1152xmlXPathObjectPtr
1153xmlXPathNewCString(const char *val) {
1154    xmlXPathObjectPtr ret;
1155
1156    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1157    if (ret == NULL) {
1158        xmlGenericError(xmlGenericErrorContext,
1159		"xmlXPathNewCString: out of memory\n");
1160	return(NULL);
1161    }
1162    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1163    ret->type = XPATH_STRING;
1164    ret->stringval = xmlStrdup(BAD_CAST val);
1165    return(ret);
1166}
1167
1168/**
1169 * xmlXPathObjectCopy:
1170 * @val:  the original object
1171 *
1172 * allocate a new copy of a given object
1173 *
1174 * Returns the newly created object.
1175 */
1176xmlXPathObjectPtr
1177xmlXPathObjectCopy(xmlXPathObjectPtr val) {
1178    xmlXPathObjectPtr ret;
1179
1180    if (val == NULL)
1181	return(NULL);
1182
1183    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1184    if (ret == NULL) {
1185        xmlGenericError(xmlGenericErrorContext,
1186		"xmlXPathObjectCopy: out of memory\n");
1187	return(NULL);
1188    }
1189    memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
1190    switch (val->type) {
1191	case XPATH_BOOLEAN:
1192	case XPATH_NUMBER:
1193	case XPATH_STRING:
1194	case XPATH_POINT:
1195	case XPATH_RANGE:
1196	    break;
1197	case XPATH_NODESET:
1198	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1199	    break;
1200	case XPATH_LOCATIONSET:
1201#ifdef LIBXML_XPTR_ENABLED
1202	{
1203	    xmlLocationSetPtr loc = val->user;
1204	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
1205	    break;
1206	}
1207#endif
1208	case XPATH_UNDEFINED:
1209	case XPATH_USERS:
1210	    xmlGenericError(xmlGenericErrorContext,
1211		    "xmlXPathObjectCopy: unsupported type %d\n",
1212		    val->type);
1213    }
1214    return(ret);
1215}
1216
1217/**
1218 * xmlXPathFreeObject:
1219 * @obj:  the object to free
1220 *
1221 * Free up an xmlXPathObjectPtr object.
1222 */
1223void
1224xmlXPathFreeObject(xmlXPathObjectPtr obj) {
1225    if (obj == NULL) return;
1226    if (obj->type == XPATH_NODESET) {
1227	if (obj->nodesetval != NULL)
1228	    xmlXPathFreeNodeSet(obj->nodesetval);
1229#ifdef LIBXML_XPTR_ENABLED
1230    } else if (obj->type == XPATH_LOCATIONSET) {
1231	if (obj->user != NULL)
1232	    xmlXPtrFreeLocationSet(obj->user);
1233#endif
1234    } else if (obj->type == XPATH_STRING) {
1235	if (obj->stringval != NULL)
1236	    xmlFree(obj->stringval);
1237    }
1238
1239#ifdef DEBUG
1240    memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
1241#endif
1242    xmlFree(obj);
1243}
1244
1245/************************************************************************
1246 *									*
1247 *		Routines to handle XPath contexts			*
1248 *									*
1249 ************************************************************************/
1250
1251/**
1252 * xmlXPathNewContext:
1253 * @doc:  the XML document
1254 *
1255 * Create a new xmlXPathContext
1256 *
1257 * Returns the xmlXPathContext just allocated.
1258 */
1259xmlXPathContextPtr
1260xmlXPathNewContext(xmlDocPtr doc) {
1261    xmlXPathContextPtr ret;
1262
1263    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
1264    if (ret == NULL) {
1265        xmlGenericError(xmlGenericErrorContext,
1266		"xmlXPathNewContext: out of memory\n");
1267	return(NULL);
1268    }
1269    memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
1270    ret->doc = doc;
1271    ret->node = NULL;
1272
1273    ret->varHash = NULL;
1274
1275    ret->nb_types = 0;
1276    ret->max_types = 0;
1277    ret->types = NULL;
1278
1279    ret->funcHash = xmlHashCreate(0);
1280
1281    ret->nb_axis = 0;
1282    ret->max_axis = 0;
1283    ret->axis = NULL;
1284
1285    ret->namespaces = NULL;
1286    ret->user = NULL;
1287    ret->nsNr = 0;
1288
1289    ret->contextSize = -1;
1290    ret->proximityPosition = -1;
1291
1292    xmlXPathRegisterAllFunctions(ret);
1293
1294    return(ret);
1295}
1296
1297/**
1298 * xmlXPathFreeContext:
1299 * @ctxt:  the context to free
1300 *
1301 * Free up an xmlXPathContext
1302 */
1303void
1304xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
1305    if (ctxt->namespaces != NULL)
1306        xmlFree(ctxt->namespaces);
1307
1308    xmlXPathRegisteredFuncsCleanup(ctxt);
1309    xmlXPathRegisteredVariablesCleanup(ctxt);
1310#ifdef DEBUG
1311    memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
1312#endif
1313    xmlFree(ctxt);
1314}
1315
1316/************************************************************************
1317 *									*
1318 *		Routines to handle XPath parser contexts		*
1319 *									*
1320 ************************************************************************/
1321
1322#define CHECK_CTXT(ctxt)						\
1323    if (ctxt == NULL) { 						\
1324        xmlGenericError(xmlGenericErrorContext,				\
1325		"%s:%d Internal error: ctxt == NULL\n",			\
1326	        __FILE__, __LINE__);					\
1327    }									\
1328
1329
1330#define CHECK_CONTEXT(ctxt)						\
1331    if (ctxt == NULL) { 						\
1332        xmlGenericError(xmlGenericErrorContext,				\
1333		"%s:%d Internal error: no context\n",			\
1334	        __FILE__, __LINE__);					\
1335    }									\
1336    else if (ctxt->doc == NULL) { 					\
1337        xmlGenericError(xmlGenericErrorContext,				\
1338		"%s:%d Internal error: no document\n",			\
1339	        __FILE__, __LINE__);					\
1340    }									\
1341    else if (ctxt->doc->children == NULL) { 				\
1342        xmlGenericError(xmlGenericErrorContext,				\
1343	        "%s:%d Internal error: document without root\n",	\
1344	        __FILE__, __LINE__);					\
1345    }									\
1346
1347
1348/**
1349 * xmlXPathNewParserContext:
1350 * @str:  the XPath expression
1351 * @ctxt:  the XPath context
1352 *
1353 * Create a new xmlXPathParserContext
1354 *
1355 * Returns the xmlXPathParserContext just allocated.
1356 */
1357xmlXPathParserContextPtr
1358xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
1359    xmlXPathParserContextPtr ret;
1360
1361    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
1362    if (ret == NULL) {
1363        xmlGenericError(xmlGenericErrorContext,
1364		"xmlXPathNewParserContext: out of memory\n");
1365	return(NULL);
1366    }
1367    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
1368    ret->cur = ret->base = str;
1369    ret->context = ctxt;
1370
1371    /* Allocate the value stack */
1372    ret->valueTab = (xmlXPathObjectPtr *)
1373                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
1374    ret->valueNr = 0;
1375    ret->valueMax = 10;
1376    ret->value = NULL;
1377    return(ret);
1378}
1379
1380/**
1381 * xmlXPathFreeParserContext:
1382 * @ctxt:  the context to free
1383 *
1384 * Free up an xmlXPathParserContext
1385 */
1386void
1387xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
1388    if (ctxt->valueTab != NULL) {
1389#ifdef DEBUG
1390        memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
1391#endif
1392        xmlFree(ctxt->valueTab);
1393    }
1394#ifdef DEBUG
1395    memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
1396#endif
1397    xmlFree(ctxt);
1398}
1399
1400/************************************************************************
1401 *									*
1402 *		The implicit core function library			*
1403 *									*
1404 ************************************************************************/
1405
1406/*
1407 * Auto-pop and cast to a number
1408 */
1409void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
1410
1411
1412#define POP_FLOAT						\
1413    arg = valuePop(ctxt);					\
1414    if (arg == NULL) {						\
1415	XP_ERROR(XPATH_INVALID_OPERAND);				\
1416    }								\
1417    if (arg->type != XPATH_NUMBER) {				\
1418        valuePush(ctxt, arg);					\
1419        xmlXPathNumberFunction(ctxt, 1);			\
1420	arg = valuePop(ctxt);					\
1421    }
1422
1423/**
1424 * xmlXPathEqualNodeSetString
1425 * @arg:  the nodeset object argument
1426 * @str:  the string to compare to.
1427 *
1428 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1429 * If one object to be compared is a node-set and the other is a string,
1430 * then the comparison will be true if and only if there is a node in
1431 * the node-set such that the result of performing the comparison on the
1432 * string-value of the node and the other string is true.
1433 *
1434 * Returns 0 or 1 depending on the results of the test.
1435 */
1436int
1437xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
1438    int i;
1439    xmlNodeSetPtr ns;
1440    xmlChar *str2;
1441
1442    if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
1443        return(0);
1444    ns = arg->nodesetval;
1445    for (i = 0;i < ns->nodeNr;i++) {
1446         str2 = xmlNodeGetContent(ns->nodeTab[i]);
1447	 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
1448	     xmlFree(str2);
1449	     return(1);
1450	 }
1451	 xmlFree(str2);
1452    }
1453    return(0);
1454}
1455
1456/**
1457 * xmlXPathEqualNodeSetFloat
1458 * @arg:  the nodeset object argument
1459 * @f:  the float to compare to
1460 *
1461 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1462 * If one object to be compared is a node-set and the other is a number,
1463 * then the comparison will be true if and only if there is a node in
1464 * the node-set such that the result of performing the comparison on the
1465 * number to be compared and on the result of converting the string-value
1466 * of that node to a number using the number function is true.
1467 *
1468 * Returns 0 or 1 depending on the results of the test.
1469 */
1470int
1471xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
1472    char buf[100] = "";
1473
1474    if ((arg == NULL) || (arg->type != XPATH_NODESET))
1475        return(0);
1476
1477    if (isnan(f))
1478	sprintf(buf, "NaN");
1479    else if (isinf(f) > 0)
1480	sprintf(buf, "+Infinity");
1481    else if (isinf(f) < 0)
1482	sprintf(buf, "-Infinity");
1483    else
1484	sprintf(buf, "%0g", f);
1485
1486    return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
1487}
1488
1489
1490/**
1491 * xmlXPathEqualNodeSets
1492 * @arg1:  first nodeset object argument
1493 * @arg2:  second nodeset object argument
1494 *
1495 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1496 * If both objects to be compared are node-sets, then the comparison
1497 * will be true if and only if there is a node in the first node-set and
1498 * a node in the second node-set such that the result of performing the
1499 * comparison on the string-values of the two nodes is true.
1500 *
1501 * (needless to say, this is a costly operation)
1502 *
1503 * Returns 0 or 1 depending on the results of the test.
1504 */
1505int
1506xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1507    int i;
1508    xmlNodeSetPtr ns;
1509    xmlChar *str;
1510
1511    if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
1512        return(0);
1513    if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
1514        return(0);
1515
1516    ns = arg1->nodesetval;
1517    for (i = 0;i < ns->nodeNr;i++) {
1518         str = xmlNodeGetContent(ns->nodeTab[i]);
1519	 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
1520	     xmlFree(str);
1521	     return(1);
1522	 }
1523	 xmlFree(str);
1524    }
1525    return(0);
1526}
1527
1528/**
1529 * xmlXPathEqualValues:
1530 * @ctxt:  the XPath Parser context
1531 *
1532 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1533 *
1534 * Returns 0 or 1 depending on the results of the test.
1535 */
1536int
1537xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1538    xmlXPathObjectPtr arg1, arg2;
1539    int ret = 0;
1540
1541    arg1 = valuePop(ctxt);
1542    if (arg1 == NULL)
1543	XP_ERROR0(XPATH_INVALID_OPERAND);
1544
1545    arg2 = valuePop(ctxt);
1546    if (arg2 == NULL) {
1547	xmlXPathFreeObject(arg1);
1548	XP_ERROR0(XPATH_INVALID_OPERAND);
1549    }
1550
1551    if (arg1 == arg2) {
1552#ifdef DEBUG_EXPR
1553        xmlGenericError(xmlGenericErrorContext,
1554		"Equal: by pointer\n");
1555#endif
1556        return(1);
1557    }
1558
1559    switch (arg1->type) {
1560        case XPATH_UNDEFINED:
1561#ifdef DEBUG_EXPR
1562	    xmlGenericError(xmlGenericErrorContext,
1563		    "Equal: undefined\n");
1564#endif
1565	    break;
1566        case XPATH_NODESET:
1567	    switch (arg2->type) {
1568	        case XPATH_UNDEFINED:
1569#ifdef DEBUG_EXPR
1570		    xmlGenericError(xmlGenericErrorContext,
1571			    "Equal: undefined\n");
1572#endif
1573		    break;
1574		case XPATH_NODESET:
1575		    ret = xmlXPathEqualNodeSets(arg1, arg2);
1576		    break;
1577		case XPATH_BOOLEAN:
1578		    if ((arg1->nodesetval == NULL) ||
1579			(arg1->nodesetval->nodeNr == 0)) ret = 0;
1580		    else
1581			ret = 1;
1582		    ret = (ret == arg2->boolval);
1583		    break;
1584		case XPATH_NUMBER:
1585		    ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
1586		    break;
1587		case XPATH_STRING:
1588		    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
1589		    break;
1590		case XPATH_USERS:
1591		case XPATH_POINT:
1592		case XPATH_RANGE:
1593		case XPATH_LOCATIONSET:
1594		    TODO
1595		    break;
1596	    }
1597	    break;
1598        case XPATH_BOOLEAN:
1599	    switch (arg2->type) {
1600	        case XPATH_UNDEFINED:
1601#ifdef DEBUG_EXPR
1602		    xmlGenericError(xmlGenericErrorContext,
1603			    "Equal: undefined\n");
1604#endif
1605		    break;
1606		case XPATH_NODESET:
1607		    if ((arg2->nodesetval == NULL) ||
1608			(arg2->nodesetval->nodeNr == 0)) ret = 0;
1609		    else
1610			ret = 1;
1611		    break;
1612		case XPATH_BOOLEAN:
1613#ifdef DEBUG_EXPR
1614		    xmlGenericError(xmlGenericErrorContext,
1615			    "Equal: %d boolean %d \n",
1616			    arg1->boolval, arg2->boolval);
1617#endif
1618		    ret = (arg1->boolval == arg2->boolval);
1619		    break;
1620		case XPATH_NUMBER:
1621		    if (arg2->floatval) ret = 1;
1622		    else ret = 0;
1623		    ret = (arg1->boolval == ret);
1624		    break;
1625		case XPATH_STRING:
1626		    if ((arg2->stringval == NULL) ||
1627			(arg2->stringval[0] == 0)) ret = 0;
1628		    else
1629			ret = 1;
1630		    ret = (arg1->boolval == ret);
1631		    break;
1632		case XPATH_USERS:
1633		case XPATH_POINT:
1634		case XPATH_RANGE:
1635		case XPATH_LOCATIONSET:
1636		    TODO
1637		    break;
1638	    }
1639	    break;
1640        case XPATH_NUMBER:
1641	    switch (arg2->type) {
1642	        case XPATH_UNDEFINED:
1643#ifdef DEBUG_EXPR
1644		    xmlGenericError(xmlGenericErrorContext,
1645			    "Equal: undefined\n");
1646#endif
1647		    break;
1648		case XPATH_NODESET:
1649		    ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
1650		    break;
1651		case XPATH_BOOLEAN:
1652		    if (arg1->floatval) ret = 1;
1653		    else ret = 0;
1654		    ret = (arg2->boolval == ret);
1655		    break;
1656		case XPATH_STRING:
1657		    valuePush(ctxt, arg2);
1658		    xmlXPathNumberFunction(ctxt, 1);
1659		    arg2 = valuePop(ctxt);
1660		    /* no break on purpose */
1661		case XPATH_NUMBER:
1662		    ret = (arg1->floatval == arg2->floatval);
1663		    break;
1664		case XPATH_USERS:
1665		case XPATH_POINT:
1666		case XPATH_RANGE:
1667		case XPATH_LOCATIONSET:
1668		    TODO
1669		    break;
1670	    }
1671	    break;
1672        case XPATH_STRING:
1673	    switch (arg2->type) {
1674	        case XPATH_UNDEFINED:
1675#ifdef DEBUG_EXPR
1676		    xmlGenericError(xmlGenericErrorContext,
1677			    "Equal: undefined\n");
1678#endif
1679		    break;
1680		case XPATH_NODESET:
1681		    ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
1682		    break;
1683		case XPATH_BOOLEAN:
1684		    if ((arg1->stringval == NULL) ||
1685			(arg1->stringval[0] == 0)) ret = 0;
1686		    else
1687			ret = 1;
1688		    ret = (arg2->boolval == ret);
1689		    break;
1690		case XPATH_STRING:
1691		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
1692		    break;
1693		case XPATH_NUMBER:
1694		    valuePush(ctxt, arg1);
1695		    xmlXPathNumberFunction(ctxt, 1);
1696		    arg1 = valuePop(ctxt);
1697		    ret = (arg1->floatval == arg2->floatval);
1698		    break;
1699		case XPATH_USERS:
1700		case XPATH_POINT:
1701		case XPATH_RANGE:
1702		case XPATH_LOCATIONSET:
1703		    TODO
1704		    break;
1705	    }
1706	    break;
1707        case XPATH_USERS:
1708	case XPATH_POINT:
1709	case XPATH_RANGE:
1710	case XPATH_LOCATIONSET:
1711	    TODO
1712	    break;
1713    }
1714    xmlXPathFreeObject(arg1);
1715    xmlXPathFreeObject(arg2);
1716    return(ret);
1717}
1718
1719/**
1720 * xmlXPathCompareValues:
1721 * @ctxt:  the XPath Parser context
1722 * @inf:  less than (1) or greater than (2)
1723 * @strict:  is the comparison strict
1724 *
1725 * Implement the compare operation on XPath objects:
1726 *     @arg1 < @arg2    (1, 1, ...
1727 *     @arg1 <= @arg2   (1, 0, ...
1728 *     @arg1 > @arg2    (0, 1, ...
1729 *     @arg1 >= @arg2   (0, 0, ...
1730 *
1731 * When neither object to be compared is a node-set and the operator is
1732 * <=, <, >=, >, then the objects are compared by converted both objects
1733 * to numbers and comparing the numbers according to IEEE 754. The <
1734 * comparison will be true if and only if the first number is less than the
1735 * second number. The <= comparison will be true if and only if the first
1736 * number is less than or equal to the second number. The > comparison
1737 * will be true if and only if the first number is greater than the second
1738 * number. The >= comparison will be true if and only if the first number
1739 * is greater than or equal to the second number.
1740 */
1741int
1742xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1743    int ret = 0;
1744    xmlXPathObjectPtr arg1, arg2;
1745
1746    arg2 = valuePop(ctxt);
1747    if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1748        if (arg2 != NULL)
1749	    xmlXPathFreeObject(arg2);
1750	XP_ERROR0(XPATH_INVALID_OPERAND);
1751    }
1752
1753    arg1 = valuePop(ctxt);
1754    if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1755        if (arg1 != NULL)
1756	    xmlXPathFreeObject(arg1);
1757	xmlXPathFreeObject(arg2);
1758	XP_ERROR0(XPATH_INVALID_OPERAND);
1759    }
1760
1761    if (arg1->type != XPATH_NUMBER) {
1762	valuePush(ctxt, arg1);
1763	xmlXPathNumberFunction(ctxt, 1);
1764	arg1 = valuePop(ctxt);
1765    }
1766    if (arg1->type != XPATH_NUMBER) {
1767	xmlXPathFreeObject(arg1);
1768	xmlXPathFreeObject(arg2);
1769	XP_ERROR0(XPATH_INVALID_OPERAND);
1770    }
1771    if (arg2->type != XPATH_NUMBER) {
1772	valuePush(ctxt, arg2);
1773	xmlXPathNumberFunction(ctxt, 1);
1774	arg2 = valuePop(ctxt);
1775    }
1776    if (arg2->type != XPATH_NUMBER) {
1777	xmlXPathFreeObject(arg1);
1778	xmlXPathFreeObject(arg2);
1779	XP_ERROR0(XPATH_INVALID_OPERAND);
1780    }
1781    /*
1782     * Add tests for infinity and nan
1783     * => feedback on 3.4 for Inf and NaN
1784     */
1785    if (inf && strict)
1786        ret = (arg1->floatval < arg2->floatval);
1787    else if (inf && !strict)
1788        ret = (arg1->floatval <= arg2->floatval);
1789    else if (!inf && strict)
1790        ret = (arg1->floatval > arg2->floatval);
1791    else if (!inf && !strict)
1792        ret = (arg1->floatval >= arg2->floatval);
1793    xmlXPathFreeObject(arg1);
1794    xmlXPathFreeObject(arg2);
1795    return(ret);
1796}
1797
1798/**
1799 * xmlXPathValueFlipSign:
1800 * @ctxt:  the XPath Parser context
1801 *
1802 * Implement the unary - operation on an XPath object
1803 * The numeric operators convert their operands to numbers as if
1804 * by calling the number function.
1805 */
1806void
1807xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1808    xmlXPathObjectPtr arg;
1809
1810    POP_FLOAT
1811    arg->floatval = -arg->floatval;
1812    valuePush(ctxt, arg);
1813}
1814
1815/**
1816 * xmlXPathAddValues:
1817 * @ctxt:  the XPath Parser context
1818 *
1819 * Implement the add operation on XPath objects:
1820 * The numeric operators convert their operands to numbers as if
1821 * by calling the number function.
1822 */
1823void
1824xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1825    xmlXPathObjectPtr arg;
1826    double val;
1827
1828    POP_FLOAT
1829    val = arg->floatval;
1830    xmlXPathFreeObject(arg);
1831
1832    POP_FLOAT
1833    arg->floatval += val;
1834    valuePush(ctxt, arg);
1835}
1836
1837/**
1838 * xmlXPathSubValues:
1839 * @ctxt:  the XPath Parser context
1840 *
1841 * Implement the substraction operation on XPath objects:
1842 * The numeric operators convert their operands to numbers as if
1843 * by calling the number function.
1844 */
1845void
1846xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1847    xmlXPathObjectPtr arg;
1848    double val;
1849
1850    POP_FLOAT
1851    val = arg->floatval;
1852    xmlXPathFreeObject(arg);
1853
1854    POP_FLOAT
1855    arg->floatval -= val;
1856    valuePush(ctxt, arg);
1857}
1858
1859/**
1860 * xmlXPathMultValues:
1861 * @ctxt:  the XPath Parser context
1862 *
1863 * Implement the multiply operation on XPath objects:
1864 * The numeric operators convert their operands to numbers as if
1865 * by calling the number function.
1866 */
1867void
1868xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1869    xmlXPathObjectPtr arg;
1870    double val;
1871
1872    POP_FLOAT
1873    val = arg->floatval;
1874    xmlXPathFreeObject(arg);
1875
1876    POP_FLOAT
1877    arg->floatval *= val;
1878    valuePush(ctxt, arg);
1879}
1880
1881/**
1882 * xmlXPathDivValues:
1883 * @ctxt:  the XPath Parser context
1884 *
1885 * Implement the div operation on XPath objects:
1886 * The numeric operators convert their operands to numbers as if
1887 * by calling the number function.
1888 */
1889void
1890xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1891    xmlXPathObjectPtr arg;
1892    double val;
1893
1894    POP_FLOAT
1895    val = arg->floatval;
1896    xmlXPathFreeObject(arg);
1897
1898    POP_FLOAT
1899    arg->floatval /= val;
1900    valuePush(ctxt, arg);
1901}
1902
1903/**
1904 * xmlXPathModValues:
1905 * @ctxt:  the XPath Parser context
1906 *
1907 * Implement the div operation on XPath objects: @arg1 / @arg2
1908 * The numeric operators convert their operands to numbers as if
1909 * by calling the number function.
1910 */
1911void
1912xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1913    xmlXPathObjectPtr arg;
1914    double val;
1915
1916    POP_FLOAT
1917    val = arg->floatval;
1918    xmlXPathFreeObject(arg);
1919
1920    POP_FLOAT
1921    arg->floatval /= val;
1922    valuePush(ctxt, arg);
1923}
1924
1925/************************************************************************
1926 *									*
1927 *		The traversal functions					*
1928 *									*
1929 ************************************************************************/
1930
1931typedef enum {
1932    AXIS_ANCESTOR = 1,
1933    AXIS_ANCESTOR_OR_SELF,
1934    AXIS_ATTRIBUTE,
1935    AXIS_CHILD,
1936    AXIS_DESCENDANT,
1937    AXIS_DESCENDANT_OR_SELF,
1938    AXIS_FOLLOWING,
1939    AXIS_FOLLOWING_SIBLING,
1940    AXIS_NAMESPACE,
1941    AXIS_PARENT,
1942    AXIS_PRECEDING,
1943    AXIS_PRECEDING_SIBLING,
1944    AXIS_SELF
1945} xmlXPathAxisVal;
1946
1947/*
1948 * A traversal function enumerates nodes along an axis.
1949 * Initially it must be called with NULL, and it indicates
1950 * termination on the axis by returning NULL.
1951 */
1952typedef xmlNodePtr (*xmlXPathTraversalFunction)
1953                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1954
1955/**
1956 * xmlXPathNextSelf:
1957 * @ctxt:  the XPath Parser context
1958 * @cur:  the current node in the traversal
1959 *
1960 * Traversal function for the "self" direction
1961 * The self axis contains just the context node itself
1962 *
1963 * Returns the next element following that axis
1964 */
1965xmlNodePtr
1966xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1967    if (cur == NULL)
1968        return(ctxt->context->node);
1969    return(NULL);
1970}
1971
1972/**
1973 * xmlXPathNextChild:
1974 * @ctxt:  the XPath Parser context
1975 * @cur:  the current node in the traversal
1976 *
1977 * Traversal function for the "child" direction
1978 * The child axis contains the children of the context node in document order.
1979 *
1980 * Returns the next element following that axis
1981 */
1982xmlNodePtr
1983xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1984    if (cur == NULL) {
1985	if (ctxt->context->node == NULL) return(NULL);
1986	switch (ctxt->context->node->type) {
1987            case XML_ELEMENT_NODE:
1988            case XML_TEXT_NODE:
1989            case XML_CDATA_SECTION_NODE:
1990            case XML_ENTITY_REF_NODE:
1991            case XML_ENTITY_NODE:
1992            case XML_PI_NODE:
1993            case XML_COMMENT_NODE:
1994            case XML_NOTATION_NODE:
1995            case XML_DTD_NODE:
1996		return(ctxt->context->node->children);
1997            case XML_DOCUMENT_NODE:
1998            case XML_DOCUMENT_TYPE_NODE:
1999            case XML_DOCUMENT_FRAG_NODE:
2000            case XML_HTML_DOCUMENT_NODE:
2001#ifdef LIBXML_SGML_ENABLED
2002	    case XML_SGML_DOCUMENT_NODE:
2003#endif
2004		return(((xmlDocPtr) ctxt->context->node)->children);
2005	    case XML_ELEMENT_DECL:
2006	    case XML_ATTRIBUTE_DECL:
2007	    case XML_ENTITY_DECL:
2008            case XML_ATTRIBUTE_NODE:
2009	    case XML_NAMESPACE_DECL:
2010	    case XML_XINCLUDE_START:
2011	    case XML_XINCLUDE_END:
2012		return(NULL);
2013	}
2014	return(NULL);
2015    }
2016    if ((cur->type == XML_DOCUMENT_NODE) ||
2017        (cur->type == XML_HTML_DOCUMENT_NODE))
2018	return(NULL);
2019    return(cur->next);
2020}
2021
2022/**
2023 * xmlXPathNextDescendant:
2024 * @ctxt:  the XPath Parser context
2025 * @cur:  the current node in the traversal
2026 *
2027 * Traversal function for the "descendant" direction
2028 * the descendant axis contains the descendants of the context node in document
2029 * order; a descendant is a child or a child of a child and so on.
2030 *
2031 * Returns the next element following that axis
2032 */
2033xmlNodePtr
2034xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2035    if (cur == NULL) {
2036	if (ctxt->context->node == NULL)
2037	    return(NULL);
2038	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2039	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
2040	    return(NULL);
2041
2042        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
2043	    return(ctxt->context->doc->children);
2044        return(ctxt->context->node->children);
2045    }
2046
2047    if (cur->children != NULL)
2048    	{
2049    	if (cur->children->type != XML_ENTITY_DECL)
2050		   	return(cur->children);
2051    	}
2052    if (cur->next != NULL) return(cur->next);
2053
2054    do {
2055        cur = cur->parent;
2056	if (cur == NULL) return(NULL);
2057	if (cur == ctxt->context->node) return(NULL);
2058	if (cur->next != NULL) {
2059	    cur = cur->next;
2060	    return(cur);
2061	}
2062    } while (cur != NULL);
2063    return(cur);
2064}
2065
2066/**
2067 * xmlXPathNextDescendantOrSelf:
2068 * @ctxt:  the XPath Parser context
2069 * @cur:  the current node in the traversal
2070 *
2071 * Traversal function for the "descendant-or-self" direction
2072 * the descendant-or-self axis contains the context node and the descendants
2073 * of the context node in document order; thus the context node is the first
2074 * node on the axis, and the first child of the context node is the second node
2075 * on the axis
2076 *
2077 * Returns the next element following that axis
2078 */
2079xmlNodePtr
2080xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2081    if (cur == NULL) {
2082	if (ctxt->context->node == NULL)
2083	    return(NULL);
2084	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2085	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
2086	    return(NULL);
2087        return(ctxt->context->node);
2088    }
2089
2090    return(xmlXPathNextDescendant(ctxt, cur));
2091}
2092
2093/**
2094 * xmlXPathNextParent:
2095 * @ctxt:  the XPath Parser context
2096 * @cur:  the current node in the traversal
2097 *
2098 * Traversal function for the "parent" direction
2099 * The parent axis contains the parent of the context node, if there is one.
2100 *
2101 * Returns the next element following that axis
2102 */
2103xmlNodePtr
2104xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2105    /*
2106     * the parent of an attribute or namespace node is the element
2107     * to which the attribute or namespace node is attached
2108     * Namespace handling !!!
2109     */
2110    if (cur == NULL) {
2111	if (ctxt->context->node == NULL) return(NULL);
2112	switch (ctxt->context->node->type) {
2113            case XML_ELEMENT_NODE:
2114            case XML_TEXT_NODE:
2115            case XML_CDATA_SECTION_NODE:
2116            case XML_ENTITY_REF_NODE:
2117            case XML_ENTITY_NODE:
2118            case XML_PI_NODE:
2119            case XML_COMMENT_NODE:
2120            case XML_NOTATION_NODE:
2121            case XML_DTD_NODE:
2122	    case XML_ELEMENT_DECL:
2123	    case XML_ATTRIBUTE_DECL:
2124	    case XML_XINCLUDE_START:
2125	    case XML_XINCLUDE_END:
2126	    case XML_ENTITY_DECL:
2127		if (ctxt->context->node->parent == NULL)
2128		    return((xmlNodePtr) ctxt->context->doc);
2129		return(ctxt->context->node->parent);
2130            case XML_ATTRIBUTE_NODE: {
2131		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2132
2133		return(att->parent);
2134	    }
2135            case XML_DOCUMENT_NODE:
2136            case XML_DOCUMENT_TYPE_NODE:
2137            case XML_DOCUMENT_FRAG_NODE:
2138            case XML_HTML_DOCUMENT_NODE:
2139#ifdef LIBXML_SGML_ENABLED
2140	    case XML_SGML_DOCUMENT_NODE:
2141#endif
2142                return(NULL);
2143	    case XML_NAMESPACE_DECL:
2144		/*
2145		 * TODO !!! may require extending struct _xmlNs with
2146		 * parent field
2147		 * C.f. Infoset case...
2148		 */
2149                return(NULL);
2150	}
2151    }
2152    return(NULL);
2153}
2154
2155/**
2156 * xmlXPathNextAncestor:
2157 * @ctxt:  the XPath Parser context
2158 * @cur:  the current node in the traversal
2159 *
2160 * Traversal function for the "ancestor" direction
2161 * the ancestor axis contains the ancestors of the context node; the ancestors
2162 * of the context node consist of the parent of context node and the parent's
2163 * parent and so on; the nodes are ordered in reverse document order; thus the
2164 * parent is the first node on the axis, and the parent's parent is the second
2165 * node on the axis
2166 *
2167 * Returns the next element following that axis
2168 */
2169xmlNodePtr
2170xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2171    /*
2172     * the parent of an attribute or namespace node is the element
2173     * to which the attribute or namespace node is attached
2174     * !!!!!!!!!!!!!
2175     */
2176    if (cur == NULL) {
2177	if (ctxt->context->node == NULL) return(NULL);
2178	switch (ctxt->context->node->type) {
2179            case XML_ELEMENT_NODE:
2180            case XML_TEXT_NODE:
2181            case XML_CDATA_SECTION_NODE:
2182            case XML_ENTITY_REF_NODE:
2183            case XML_ENTITY_NODE:
2184            case XML_PI_NODE:
2185            case XML_COMMENT_NODE:
2186	    case XML_DTD_NODE:
2187	    case XML_ELEMENT_DECL:
2188	    case XML_ATTRIBUTE_DECL:
2189	    case XML_ENTITY_DECL:
2190            case XML_NOTATION_NODE:
2191	    case XML_XINCLUDE_START:
2192	    case XML_XINCLUDE_END:
2193		if (ctxt->context->node->parent == NULL)
2194		    return((xmlNodePtr) ctxt->context->doc);
2195		return(ctxt->context->node->parent);
2196            case XML_ATTRIBUTE_NODE: {
2197		xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
2198
2199		return(cur->parent);
2200	    }
2201            case XML_DOCUMENT_NODE:
2202            case XML_DOCUMENT_TYPE_NODE:
2203            case XML_DOCUMENT_FRAG_NODE:
2204            case XML_HTML_DOCUMENT_NODE:
2205#ifdef LIBXML_SGML_ENABLED
2206	    case XML_SGML_DOCUMENT_NODE:
2207#endif
2208                return(NULL);
2209	    case XML_NAMESPACE_DECL:
2210		/*
2211		 * TODO !!! may require extending struct _xmlNs with
2212		 * parent field
2213		 * C.f. Infoset case...
2214		 */
2215                return(NULL);
2216	}
2217	return(NULL);
2218    }
2219    if (cur == ctxt->context->doc->children)
2220	return((xmlNodePtr) ctxt->context->doc);
2221    if (cur == (xmlNodePtr) ctxt->context->doc)
2222	return(NULL);
2223    switch (cur->type) {
2224	case XML_ELEMENT_NODE:
2225	case XML_TEXT_NODE:
2226	case XML_CDATA_SECTION_NODE:
2227	case XML_ENTITY_REF_NODE:
2228	case XML_ENTITY_NODE:
2229	case XML_PI_NODE:
2230	case XML_COMMENT_NODE:
2231	case XML_NOTATION_NODE:
2232	case XML_DTD_NODE:
2233        case XML_ELEMENT_DECL:
2234        case XML_ATTRIBUTE_DECL:
2235        case XML_ENTITY_DECL:
2236	case XML_XINCLUDE_START:
2237	case XML_XINCLUDE_END:
2238	    return(cur->parent);
2239	case XML_ATTRIBUTE_NODE: {
2240	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2241
2242	    return(att->parent);
2243	}
2244	case XML_DOCUMENT_NODE:
2245	case XML_DOCUMENT_TYPE_NODE:
2246	case XML_DOCUMENT_FRAG_NODE:
2247	case XML_HTML_DOCUMENT_NODE:
2248#ifdef LIBXML_SGML_ENABLED
2249	case XML_SGML_DOCUMENT_NODE:
2250#endif
2251	    return(NULL);
2252	case XML_NAMESPACE_DECL:
2253	    /*
2254	     * TODO !!! may require extending struct _xmlNs with
2255	     * parent field
2256	     * C.f. Infoset case...
2257	     */
2258	    return(NULL);
2259    }
2260    return(NULL);
2261}
2262
2263/**
2264 * xmlXPathNextAncestorOrSelf:
2265 * @ctxt:  the XPath Parser context
2266 * @cur:  the current node in the traversal
2267 *
2268 * Traversal function for the "ancestor-or-self" direction
2269 * he ancestor-or-self axis contains the context node and ancestors of
2270 * the context node in reverse document order; thus the context node is
2271 * the first node on the axis, and the context node's parent the second;
2272 * parent here is defined the same as with the parent axis.
2273 *
2274 * Returns the next element following that axis
2275 */
2276xmlNodePtr
2277xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2278    if (cur == NULL)
2279        return(ctxt->context->node);
2280    return(xmlXPathNextAncestor(ctxt, cur));
2281}
2282
2283/**
2284 * xmlXPathNextFollowingSibling:
2285 * @ctxt:  the XPath Parser context
2286 * @cur:  the current node in the traversal
2287 *
2288 * Traversal function for the "following-sibling" direction
2289 * The following-sibling axis contains the following siblings of the context
2290 * node in document order.
2291 *
2292 * Returns the next element following that axis
2293 */
2294xmlNodePtr
2295xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2296    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2297	(ctxt->context->node->type == XML_NAMESPACE_DECL))
2298	return(NULL);
2299    if (cur == (xmlNodePtr) ctxt->context->doc)
2300        return(NULL);
2301    if (cur == NULL)
2302        return(ctxt->context->node->next);
2303    return(cur->next);
2304}
2305
2306/**
2307 * xmlXPathNextPrecedingSibling:
2308 * @ctxt:  the XPath Parser context
2309 * @cur:  the current node in the traversal
2310 *
2311 * Traversal function for the "preceding-sibling" direction
2312 * The preceding-sibling axis contains the preceding siblings of the context
2313 * node in reverse document order; the first preceding sibling is first on the
2314 * axis; the sibling preceding that node is the second on the axis and so on.
2315 *
2316 * Returns the next element following that axis
2317 */
2318xmlNodePtr
2319xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2320    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2321	(ctxt->context->node->type == XML_NAMESPACE_DECL))
2322	return(NULL);
2323    if (cur == (xmlNodePtr) ctxt->context->doc)
2324        return(NULL);
2325    if (cur == NULL)
2326        return(ctxt->context->node->prev);
2327    return(cur->prev);
2328}
2329
2330/**
2331 * xmlXPathNextFollowing:
2332 * @ctxt:  the XPath Parser context
2333 * @cur:  the current node in the traversal
2334 *
2335 * Traversal function for the "following" direction
2336 * The following axis contains all nodes in the same document as the context
2337 * node that are after the context node in document order, excluding any
2338 * descendants and excluding attribute nodes and namespace nodes; the nodes
2339 * are ordered in document order
2340 *
2341 * Returns the next element following that axis
2342 */
2343xmlNodePtr
2344xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2345    if (cur != NULL && cur->children != NULL)
2346        return cur->children ;
2347    if (cur == NULL) cur = ctxt->context->node;
2348    if (cur == NULL) return(NULL) ; /* ERROR */
2349    if (cur->next != NULL) return(cur->next) ;
2350    do {
2351        cur = cur->parent;
2352        if (cur == NULL) return(NULL);
2353        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
2354        if (cur->next != NULL) return(cur->next);
2355    } while (cur != NULL);
2356    return(cur);
2357}
2358
2359/*
2360 * xmlXPathIsAncestor:
2361 * @ancestor:  the ancestor node
2362 * @node:  the current node
2363 *
2364 * Check that @ancestor is a @node's ancestor
2365 *
2366 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
2367 */
2368static int
2369xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
2370    if ((ancestor == NULL) || (node == NULL)) return(0);
2371    /* nodes need to be in the same document */
2372    if (ancestor->doc != node->doc) return(0);
2373    /* avoid searching if ancestor or node is the root node */
2374    if (ancestor == (xmlNodePtr) node->doc) return(1);
2375    if (node == (xmlNodePtr) ancestor->doc) return(0);
2376    while (node->parent != NULL) {
2377        if (node->parent == ancestor)
2378            return(1);
2379	node = node->parent;
2380    }
2381    return(0);
2382}
2383
2384/**
2385 * xmlXPathNextPreceding:
2386 * @ctxt:  the XPath Parser context
2387 * @cur:  the current node in the traversal
2388 *
2389 * Traversal function for the "preceding" direction
2390 * the preceding axis contains all nodes in the same document as the context
2391 * node that are before the context node in document order, excluding any
2392 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
2393 * ordered in reverse document order
2394 *
2395 * Returns the next element following that axis
2396 */
2397xmlNodePtr
2398xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2399    if (cur == NULL)
2400        cur = ctxt->context->node ;
2401    do {
2402        if (cur->prev != NULL) {
2403            for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
2404                ;
2405            return(cur) ;
2406        }
2407
2408        cur = cur->parent;
2409        if (cur == NULL) return(NULL);
2410        if (cur == ctxt->context->doc->children) return(NULL);
2411    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
2412    return(cur);
2413}
2414
2415/**
2416 * xmlXPathNextNamespace:
2417 * @ctxt:  the XPath Parser context
2418 * @cur:  the current attribute in the traversal
2419 *
2420 * Traversal function for the "namespace" direction
2421 * the namespace axis contains the namespace nodes of the context node;
2422 * the order of nodes on this axis is implementation-defined; the axis will
2423 * be empty unless the context node is an element
2424 *
2425 * Returns the next element following that axis
2426 */
2427xmlNodePtr
2428xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2429    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
2430    if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
2431        if (ctxt->context->namespaces != NULL)
2432	    xmlFree(ctxt->context->namespaces);
2433	ctxt->context->namespaces =
2434	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
2435	if (ctxt->context->namespaces == NULL) return(NULL);
2436	ctxt->context->nsNr = 0;
2437    }
2438    return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
2439}
2440
2441/**
2442 * xmlXPathNextAttribute:
2443 * @ctxt:  the XPath Parser context
2444 * @cur:  the current attribute in the traversal
2445 *
2446 * Traversal function for the "attribute" direction
2447 * TODO: support DTD inherited default attributes
2448 *
2449 * Returns the next element following that axis
2450 */
2451xmlNodePtr
2452xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2453    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
2454    if (cur == NULL) {
2455        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
2456	    return(NULL);
2457        return((xmlNodePtr)ctxt->context->node->properties);
2458    }
2459    return((xmlNodePtr)cur->next);
2460}
2461
2462/************************************************************************
2463 *									*
2464 *		NodeTest Functions					*
2465 *									*
2466 ************************************************************************/
2467
2468typedef enum {
2469    NODE_TEST_NONE = 0,
2470    NODE_TEST_TYPE = 1,
2471    NODE_TEST_PI = 2,
2472    NODE_TEST_ALL = 3,
2473    NODE_TEST_NS = 4,
2474    NODE_TEST_NAME = 5
2475} xmlXPathTestVal;
2476
2477typedef enum {
2478    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
2479    NODE_TYPE_TEXT = XML_TEXT_NODE,
2480    NODE_TYPE_PI = XML_PI_NODE,
2481    NODE_TYPE_NODE = XML_ELEMENT_NODE
2482} xmlXPathTypeVal;
2483
2484#define IS_FUNCTION			200
2485
2486/**
2487 * xmlXPathNodeCollectAndTest:
2488 * @ctxt:  the XPath Parser context
2489 * @axis:  the XPath axis
2490 * @test:  the XPath test
2491 * @type:  the XPath type
2492 * @prefix:  the namesapce prefix if any
2493 * @name:  the name used in the search if any
2494 *
2495 * This is the function implementing a step: based on the current list
2496 * of nodes, it builds up a new list, looking at all nodes under that
2497 * axis and selecting them.
2498 *
2499 * Returns the new NodeSet resulting from the search.
2500 */
2501void
2502xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, xmlXPathAxisVal axis,
2503                           xmlXPathTestVal test, xmlXPathTypeVal type,
2504			   const xmlChar *prefix, const xmlChar *name) {
2505#ifdef DEBUG_STEP
2506    int n = 0, t = 0;
2507#endif
2508    int i;
2509    xmlNodeSetPtr ret;
2510    xmlXPathTraversalFunction next = NULL;
2511    xmlNodePtr cur = NULL;
2512    xmlXPathObjectPtr obj;
2513    xmlNodeSetPtr nodelist;
2514
2515    CHECK_TYPE(XPATH_NODESET);
2516    obj = valuePop(ctxt);
2517
2518#ifdef DEBUG_STEP
2519    xmlGenericError(xmlGenericErrorContext,
2520	    "new step : ");
2521#endif
2522    switch (axis) {
2523        case AXIS_ANCESTOR:
2524#ifdef DEBUG_STEP
2525	    xmlGenericError(xmlGenericErrorContext,
2526		    "axis 'ancestors' ");
2527#endif
2528	    next = xmlXPathNextAncestor; break;
2529        case AXIS_ANCESTOR_OR_SELF:
2530#ifdef DEBUG_STEP
2531	    xmlGenericError(xmlGenericErrorContext,
2532		    "axis 'ancestors-or-self' ");
2533#endif
2534	    next = xmlXPathNextAncestorOrSelf; break;
2535        case AXIS_ATTRIBUTE:
2536#ifdef DEBUG_STEP
2537	    xmlGenericError(xmlGenericErrorContext,
2538		    "axis 'attributes' ");
2539#endif
2540	    next = xmlXPathNextAttribute; break;
2541	    break;
2542        case AXIS_CHILD:
2543#ifdef DEBUG_STEP
2544	    xmlGenericError(xmlGenericErrorContext,
2545		    "axis 'child' ");
2546#endif
2547	    next = xmlXPathNextChild; break;
2548        case AXIS_DESCENDANT:
2549#ifdef DEBUG_STEP
2550	    xmlGenericError(xmlGenericErrorContext,
2551		    "axis 'descendant' ");
2552#endif
2553	    next = xmlXPathNextDescendant; break;
2554        case AXIS_DESCENDANT_OR_SELF:
2555#ifdef DEBUG_STEP
2556	    xmlGenericError(xmlGenericErrorContext,
2557		    "axis 'descendant-or-self' ");
2558#endif
2559	    next = xmlXPathNextDescendantOrSelf; break;
2560        case AXIS_FOLLOWING:
2561#ifdef DEBUG_STEP
2562	    xmlGenericError(xmlGenericErrorContext,
2563		    "axis 'following' ");
2564#endif
2565	    next = xmlXPathNextFollowing; break;
2566        case AXIS_FOLLOWING_SIBLING:
2567#ifdef DEBUG_STEP
2568	    xmlGenericError(xmlGenericErrorContext,
2569		    "axis 'following-siblings' ");
2570#endif
2571	    next = xmlXPathNextFollowingSibling; break;
2572        case AXIS_NAMESPACE:
2573#ifdef DEBUG_STEP
2574	    xmlGenericError(xmlGenericErrorContext,
2575		    "axis 'namespace' ");
2576#endif
2577	    next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
2578	    break;
2579        case AXIS_PARENT:
2580#ifdef DEBUG_STEP
2581	    xmlGenericError(xmlGenericErrorContext,
2582		    "axis 'parent' ");
2583#endif
2584	    next = xmlXPathNextParent; break;
2585        case AXIS_PRECEDING:
2586#ifdef DEBUG_STEP
2587	    xmlGenericError(xmlGenericErrorContext,
2588		    "axis 'preceding' ");
2589#endif
2590	    next = xmlXPathNextPreceding; break;
2591        case AXIS_PRECEDING_SIBLING:
2592#ifdef DEBUG_STEP
2593	    xmlGenericError(xmlGenericErrorContext,
2594		    "axis 'preceding-sibling' ");
2595#endif
2596	    next = xmlXPathNextPrecedingSibling; break;
2597        case AXIS_SELF:
2598#ifdef DEBUG_STEP
2599	    xmlGenericError(xmlGenericErrorContext,
2600		    "axis 'self' ");
2601#endif
2602	    next = xmlXPathNextSelf; break;
2603    }
2604    if (next == NULL)
2605	return;
2606
2607    nodelist = obj->nodesetval;
2608    ret = xmlXPathNodeSetCreate(NULL);
2609#ifdef DEBUG_STEP
2610    xmlGenericError(xmlGenericErrorContext,
2611	    " context contains %d nodes\n",
2612            nodelist->nodeNr);
2613    switch (test) {
2614	case NODE_TEST_NONE:
2615	    xmlGenericError(xmlGenericErrorContext,
2616		    "           searching for none !!!\n");
2617	    break;
2618	case NODE_TEST_TYPE:
2619	    xmlGenericError(xmlGenericErrorContext,
2620		    "           searching for type %d\n", type);
2621	    break;
2622	case NODE_TEST_PI:
2623	    xmlGenericError(xmlGenericErrorContext,
2624		    "           searching for PI !!!\n");
2625	    break;
2626	case NODE_TEST_ALL:
2627	    xmlGenericError(xmlGenericErrorContext,
2628		    "           searching for *\n");
2629	    break;
2630	case NODE_TEST_NS:
2631	    xmlGenericError(xmlGenericErrorContext,
2632		    "           searching for namespace %s\n",
2633	            prefix);
2634	    break;
2635	case NODE_TEST_NAME:
2636	    xmlGenericError(xmlGenericErrorContext,
2637		    "           searching for name %s\n", name);
2638	    if (prefix != NULL)
2639		xmlGenericError(xmlGenericErrorContext,
2640			"           with namespace %s\n",
2641		        prefix);
2642	    break;
2643    }
2644    xmlGenericError(xmlGenericErrorContext, "Testing : ");
2645#endif
2646    /*
2647     * 2.3 Node Tests
2648     *  - For the attribute axis, the principal node type is attribute.
2649     *  - For the namespace axis, the principal node type is namespace.
2650     *  - For other axes, the principal node type is element.
2651     *
2652     * A node test * is true for any node of the
2653     * principal node type. For example, child::* willi
2654     * select all element children of the context node
2655     */
2656    for (i = 0;i < nodelist->nodeNr; i++) {
2657        ctxt->context->node = nodelist->nodeTab[i];
2658
2659	cur = NULL;
2660	do {
2661	    cur = next(ctxt, cur);
2662	    if (cur == NULL) break;
2663#ifdef DEBUG_STEP
2664            t++;
2665            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
2666#endif
2667	    switch (test) {
2668                case NODE_TEST_NONE:
2669		    STRANGE
2670		    return;
2671                case NODE_TEST_TYPE:
2672		    if ((cur->type == type) ||
2673		        ((type == XML_ELEMENT_NODE) &&
2674			 ((cur->type == XML_DOCUMENT_NODE) ||
2675			  (cur->type == XML_HTML_DOCUMENT_NODE)))) {
2676#ifdef DEBUG_STEP
2677                        n++;
2678#endif
2679		        xmlXPathNodeSetAdd(ret, cur);
2680		    }
2681		    break;
2682                case NODE_TEST_PI:
2683		    if (cur->type == XML_PI_NODE) {
2684		        if ((name != NULL) &&
2685			    (!xmlStrEqual(name, cur->name)))
2686			    break;
2687#ifdef DEBUG_STEP
2688			n++;
2689#endif
2690			xmlXPathNodeSetAdd(ret, cur);
2691		    }
2692		    break;
2693                case NODE_TEST_ALL:
2694		    if (axis == AXIS_ATTRIBUTE) {
2695			if (cur->type == XML_ATTRIBUTE_NODE) {
2696#ifdef DEBUG_STEP
2697			    n++;
2698#endif
2699			    xmlXPathNodeSetAdd(ret, cur);
2700			}
2701		    } else if (axis == AXIS_NAMESPACE) {
2702			if (cur->type == XML_NAMESPACE_DECL) {
2703#ifdef DEBUG_STEP
2704			    n++;
2705#endif
2706			    xmlXPathNodeSetAdd(ret, cur);
2707			}
2708		    } else {
2709			if ((cur->type == XML_ELEMENT_NODE) ||
2710			    (cur->type == XML_DOCUMENT_NODE) ||
2711			    (cur->type == XML_HTML_DOCUMENT_NODE)) {
2712#ifdef DEBUG_STEP
2713			    n++;
2714#endif
2715			    xmlXPathNodeSetAdd(ret, cur);
2716			}
2717		    }
2718		    break;
2719                case NODE_TEST_NS: {
2720		    TODO;
2721		    break;
2722		}
2723                case NODE_TEST_NAME:
2724		    switch (cur->type) {
2725		        case XML_ELEMENT_NODE:
2726			    if (xmlStrEqual(name, cur->name) &&
2727				(((prefix == NULL) ||
2728				  ((cur->ns != NULL) &&
2729				   (xmlStrEqual(prefix, cur->ns->href)))))) {
2730#ifdef DEBUG_STEP
2731				n++;
2732#endif
2733				xmlXPathNodeSetAdd(ret, cur);
2734			    }
2735			    break;
2736		        case XML_ATTRIBUTE_NODE: {
2737			    xmlAttrPtr attr = (xmlAttrPtr) cur;
2738			    if (xmlStrEqual(name, attr->name)) {
2739#ifdef DEBUG_STEP
2740				n++;
2741#endif
2742				xmlXPathNodeSetAdd(ret, cur);
2743			    }
2744			    break;
2745			}
2746			case XML_NAMESPACE_DECL: {
2747			    TODO;
2748			    break;
2749			}
2750			default:
2751			    break;
2752		    }
2753	            break;
2754	    }
2755	} while (cur != NULL);
2756    }
2757#ifdef DEBUG_STEP
2758    xmlGenericError(xmlGenericErrorContext,
2759            "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2760#endif
2761    xmlXPathFreeObject(obj);
2762    valuePush(ctxt, xmlXPathWrapNodeSet(ret));
2763}
2764
2765
2766/************************************************************************
2767 *									*
2768 *		Implicit tree core function library			*
2769 *									*
2770 ************************************************************************/
2771
2772/**
2773 * xmlXPathRoot:
2774 * @ctxt:  the XPath Parser context
2775 *
2776 * Initialize the context to the root of the document
2777 */
2778void
2779xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
2780    ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
2781    valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2782}
2783
2784/************************************************************************
2785 *									*
2786 *		The explicit core function library			*
2787 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
2788 *									*
2789 ************************************************************************/
2790
2791
2792/**
2793 * xmlXPathLastFunction:
2794 * @ctxt:  the XPath Parser context
2795 *
2796 * Implement the last() XPath function
2797 *    number last()
2798 * The last function returns the number of nodes in the context node list.
2799 */
2800void
2801xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2802    CHECK_ARITY(0);
2803    if (ctxt->context->contextSize > 0) {
2804	valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
2805#ifdef DEBUG_EXPR
2806	xmlGenericError(xmlGenericErrorContext,
2807		"last() : %d\n", ctxt->context->contextSize);
2808#endif
2809    } else {
2810	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
2811    }
2812}
2813
2814/**
2815 * xmlXPathPositionFunction:
2816 * @ctxt:  the XPath Parser context
2817 *
2818 * Implement the position() XPath function
2819 *    number position()
2820 * The position function returns the position of the context node in the
2821 * context node list. The first position is 1, and so the last positionr
2822 * will be equal to last().
2823 */
2824void
2825xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2826    CHECK_ARITY(0);
2827    if (ctxt->context->proximityPosition >= 0) {
2828	valuePush(ctxt,
2829	      xmlXPathNewFloat((double) ctxt->context->proximityPosition));
2830#ifdef DEBUG_EXPR
2831	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
2832		ctxt->context->proximityPosition);
2833#endif
2834    } else {
2835	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
2836    }
2837}
2838
2839/**
2840 * xmlXPathCountFunction:
2841 * @ctxt:  the XPath Parser context
2842 *
2843 * Implement the count() XPath function
2844 *    number count(node-set)
2845 */
2846void
2847xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2848    xmlXPathObjectPtr cur;
2849
2850    CHECK_ARITY(1);
2851    CHECK_TYPE(XPATH_NODESET);
2852    cur = valuePop(ctxt);
2853
2854    valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
2855    xmlXPathFreeObject(cur);
2856}
2857
2858/**
2859 * xmlXPathIdFunction:
2860 * @ctxt:  the XPath Parser context
2861 *
2862 * Implement the id() XPath function
2863 *    node-set id(object)
2864 * The id function selects elements by their unique ID
2865 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2866 * then the result is the union of the result of applying id to the
2867 * string value of each of the nodes in the argument node-set. When the
2868 * argument to id is of any other type, the argument is converted to a
2869 * string as if by a call to the string function; the string is split
2870 * into a whitespace-separated list of tokens (whitespace is any sequence
2871 * of characters matching the production S); the result is a node-set
2872 * containing the elements in the same document as the context node that
2873 * have a unique ID equal to any of the tokens in the list.
2874 */
2875void
2876xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2877    const xmlChar *tokens;
2878    const xmlChar *cur;
2879    xmlChar *ID;
2880    xmlAttrPtr attr;
2881    xmlNodePtr elem = NULL;
2882    xmlXPathObjectPtr ret, obj;
2883
2884    CHECK_ARITY(1);
2885    obj = valuePop(ctxt);
2886    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
2887    if (obj->type == XPATH_NODESET) {
2888	xmlXPathObjectPtr newobj;
2889	int i;
2890
2891	ret = xmlXPathNewNodeSet(NULL);
2892
2893	for (i = 0; i < obj->nodesetval->nodeNr; i++) {
2894	    valuePush(ctxt,
2895		      xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
2896	    xmlXPathStringFunction(ctxt, 1);
2897	    xmlXPathIdFunction(ctxt, 1);
2898	    newobj = valuePop(ctxt);
2899	    ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
2900						   newobj->nodesetval);
2901	    xmlXPathFreeObject(newobj);
2902	}
2903
2904	xmlXPathFreeObject(obj);
2905	valuePush(ctxt, ret);
2906	return;
2907    }
2908    if (obj->type != XPATH_STRING) {
2909        valuePush(ctxt, obj);
2910	xmlXPathStringFunction(ctxt, 1);
2911	obj = valuePop(ctxt);
2912	if (obj->type != XPATH_STRING) {
2913	    xmlXPathFreeObject(obj);
2914	    return;
2915	}
2916    }
2917    tokens = obj->stringval;
2918
2919    ret = xmlXPathNewNodeSet(NULL);
2920    valuePush(ctxt, ret);
2921    if (tokens == NULL) {
2922	xmlXPathFreeObject(obj);
2923        return;
2924    }
2925
2926    cur = tokens;
2927
2928    while (IS_BLANK(*cur)) cur++;
2929    while (*cur != 0) {
2930	while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2931	       (*cur == '.') || (*cur == '-') ||
2932	       (*cur == '_') || (*cur == ':') ||
2933	       (IS_COMBINING(*cur)) ||
2934	       (IS_EXTENDER(*cur)))
2935	       cur++;
2936
2937	if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2938
2939        ID = xmlStrndup(tokens, cur - tokens);
2940	attr = xmlGetID(ctxt->context->doc, ID);
2941	if (attr != NULL) {
2942	    elem = attr->parent;
2943            xmlXPathNodeSetAdd(ret->nodesetval, elem);
2944        }
2945	if (ID != NULL)
2946	    xmlFree(ID);
2947
2948	while (IS_BLANK(*cur)) cur++;
2949	tokens = cur;
2950    }
2951    xmlXPathFreeObject(obj);
2952    return;
2953}
2954
2955/**
2956 * xmlXPathLocalNameFunction:
2957 * @ctxt:  the XPath Parser context
2958 *
2959 * Implement the local-name() XPath function
2960 *    string local-name(node-set?)
2961 * The local-name function returns a string containing the local part
2962 * of the name of the node in the argument node-set that is first in
2963 * document order. If the node-set is empty or the first node has no
2964 * name, an empty string is returned. If the argument is omitted it
2965 * defaults to the context node.
2966 */
2967void
2968xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2969    xmlXPathObjectPtr cur;
2970
2971    if (nargs == 0) {
2972	valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2973	nargs = 1;
2974    }
2975
2976    CHECK_ARITY(1);
2977    CHECK_TYPE(XPATH_NODESET);
2978    cur = valuePop(ctxt);
2979
2980    if (cur->nodesetval->nodeNr == 0) {
2981	valuePush(ctxt, xmlXPathNewCString(""));
2982    } else {
2983	int i = 0; /* Should be first in document order !!!!! */
2984	switch (cur->nodesetval->nodeTab[i]->type) {
2985	case XML_ELEMENT_NODE:
2986	case XML_ATTRIBUTE_NODE:
2987	case XML_PI_NODE:
2988	    valuePush(ctxt,
2989		      xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2990	    break;
2991	case XML_NAMESPACE_DECL:
2992	    valuePush(ctxt, xmlXPathNewString(
2993			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
2994	    break;
2995	default:
2996	    valuePush(ctxt, xmlXPathNewCString(""));
2997	}
2998    }
2999    xmlXPathFreeObject(cur);
3000}
3001
3002/**
3003 * xmlXPathNamespaceURIFunction:
3004 * @ctxt:  the XPath Parser context
3005 *
3006 * Implement the namespace-uri() XPath function
3007 *    string namespace-uri(node-set?)
3008 * The namespace-uri function returns a string containing the
3009 * namespace URI of the expanded name of the node in the argument
3010 * node-set that is first in document order. If the node-set is empty,
3011 * the first node has no name, or the expanded name has no namespace
3012 * URI, an empty string is returned. If the argument is omitted it
3013 * defaults to the context node.
3014 */
3015void
3016xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3017    xmlXPathObjectPtr cur;
3018
3019    if (nargs == 0) {
3020        valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3021	nargs = 1;
3022    }
3023    CHECK_ARITY(1);
3024    CHECK_TYPE(XPATH_NODESET);
3025    cur = valuePop(ctxt);
3026
3027    if (cur->nodesetval->nodeNr == 0) {
3028	valuePush(ctxt, xmlXPathNewCString(""));
3029    } else {
3030	int i = 0; /* Should be first in document order !!!!! */
3031	switch (cur->nodesetval->nodeTab[i]->type) {
3032	case XML_ELEMENT_NODE:
3033	case XML_ATTRIBUTE_NODE:
3034	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
3035		valuePush(ctxt, xmlXPathNewCString(""));
3036	    else
3037		valuePush(ctxt, xmlXPathNewString(
3038			  cur->nodesetval->nodeTab[i]->ns->href));
3039	    break;
3040	default:
3041	    valuePush(ctxt, xmlXPathNewCString(""));
3042	}
3043    }
3044    xmlXPathFreeObject(cur);
3045}
3046
3047/**
3048 * xmlXPathNameFunction:
3049 * @ctxt:  the XPath Parser context
3050 *
3051 * Implement the name() XPath function
3052 *    string name(node-set?)
3053 * The name function returns a string containing a QName representing
3054 * the name of the node in the argument node-set that is first in documenti
3055 * order. The QName must represent the name with respect to the namespace
3056 * declarations in effect on the node whose name is being represented.
3057 * Typically, this will be the form in which the name occurred in the XML
3058 * source. This need not be the case if there are namespace declarations
3059 * in effect on the node that associate multiple prefixes with the same
3060 * namespace. However, an implementation may include information about
3061 * the original prefix in its representation of nodes; in this case, an
3062 * implementation can ensure that the returned string is always the same
3063 * as the QName used in the XML source. If the argument it omitted it
3064 * defaults to the context node.
3065 * Libxml keep the original prefix so the "real qualified name" used is
3066 * returned.
3067 */
3068void
3069xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3070    xmlXPathObjectPtr cur;
3071
3072    if (nargs == 0) {
3073	valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3074	nargs = 1;
3075    }
3076
3077    CHECK_ARITY(1);
3078    CHECK_TYPE(XPATH_NODESET);
3079    cur = valuePop(ctxt);
3080
3081    if (cur->nodesetval->nodeNr == 0) {
3082	valuePush(ctxt, xmlXPathNewCString(""));
3083    } else {
3084	int i = 0; /* Should be first in document order !!!!! */
3085
3086	switch (cur->nodesetval->nodeTab[i]->type) {
3087	case XML_ELEMENT_NODE:
3088	case XML_ATTRIBUTE_NODE:
3089	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
3090		valuePush(ctxt, xmlXPathNewString(
3091			    cur->nodesetval->nodeTab[i]->name));
3092
3093	    else {
3094		char name[2000];
3095#ifdef HAVE_SNPRINTF
3096		snprintf(name, sizeof(name), "%s:%s",
3097			 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
3098			 (char *) cur->nodesetval->nodeTab[i]->name);
3099#else
3100		sprintf(name, "%s:%s",
3101			(char *) cur->nodesetval->nodeTab[i]->ns->prefix,
3102			(char *) cur->nodesetval->nodeTab[i]->name);
3103#endif
3104		name[sizeof(name) - 1] = 0;
3105		valuePush(ctxt, xmlXPathNewCString(name));
3106	    }
3107	    break;
3108	default:
3109	    valuePush(ctxt,
3110		      xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
3111	    xmlXPathLocalNameFunction(ctxt, 1);
3112	}
3113    }
3114    xmlXPathFreeObject(cur);
3115}
3116
3117/**
3118 * xmlXPathStringFunction:
3119 * @ctxt:  the XPath Parser context
3120 *
3121 * Implement the string() XPath function
3122 *    string string(object?)
3123 * he string function converts an object to a string as follows:
3124 *    - A node-set is converted to a string by returning the value of
3125 *      the node in the node-set that is first in document order.
3126 *      If the node-set is empty, an empty string is returned.
3127 *    - A number is converted to a string as follows
3128 *      + NaN is converted to the string NaN
3129 *      + positive zero is converted to the string 0
3130 *      + negative zero is converted to the string 0
3131 *      + positive infinity is converted to the string Infinity
3132 *      + negative infinity is converted to the string -Infinity
3133 *      + if the number is an integer, the number is represented in
3134 *        decimal form as a Number with no decimal point and no leading
3135 *        zeros, preceded by a minus sign (-) if the number is negative
3136 *      + otherwise, the number is represented in decimal form as a
3137 *        Number including a decimal point with at least one digit
3138 *        before the decimal point and at least one digit after the
3139 *        decimal point, preceded by a minus sign (-) if the number
3140 *        is negative; there must be no leading zeros before the decimal
3141 *        point apart possibly from the one required digit immediatelyi
3142 *        before the decimal point; beyond the one required digit
3143 *        after the decimal point there must be as many, but only as
3144 *        many, more digits as are needed to uniquely distinguish the
3145 *        number from all other IEEE 754 numeric values.
3146 *    - The boolean false value is converted to the string false.
3147 *      The boolean true value is converted to the string true.
3148 *
3149 * If the argument is omitted, it defaults to a node-set with the
3150 * context node as its only member.
3151 */
3152void
3153xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3154    xmlXPathObjectPtr cur;
3155
3156    if (nargs == 0) {
3157	valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3158	nargs = 1;
3159    }
3160
3161    CHECK_ARITY(1);
3162    cur = valuePop(ctxt);
3163    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
3164    switch (cur->type) {
3165	case XPATH_UNDEFINED:
3166#ifdef DEBUG_EXPR
3167	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3168#endif
3169	    valuePush(ctxt, xmlXPathNewCString(""));
3170	    break;
3171        case XPATH_NODESET:
3172	    if (cur->nodesetval->nodeNr == 0) {
3173		valuePush(ctxt, xmlXPathNewCString(""));
3174	    } else {
3175		xmlChar *res;
3176	        int i = 0; /* Should be first in document order !!!!! */
3177		res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
3178		valuePush(ctxt, xmlXPathNewString(res));
3179		xmlFree(res);
3180	    }
3181	    xmlXPathFreeObject(cur);
3182	    return;
3183	case XPATH_STRING:
3184	    valuePush(ctxt, cur);
3185	    return;
3186        case XPATH_BOOLEAN:
3187	    if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
3188	    else valuePush(ctxt, xmlXPathNewCString("false"));
3189	    xmlXPathFreeObject(cur);
3190	    return;
3191	case XPATH_NUMBER: {
3192	    char buf[100];
3193
3194	    if (isnan(cur->floatval))
3195	        sprintf(buf, "NaN");
3196	    else if (isinf(cur->floatval) > 0)
3197	        sprintf(buf, "+Infinity");
3198	    else if (isinf(cur->floatval) < 0)
3199	        sprintf(buf, "-Infinity");
3200	    else
3201		sprintf(buf, "%0g", cur->floatval);
3202	    valuePush(ctxt, xmlXPathNewCString(buf));
3203	    xmlXPathFreeObject(cur);
3204	    return;
3205	}
3206	case XPATH_USERS:
3207	case XPATH_POINT:
3208	case XPATH_RANGE:
3209	case XPATH_LOCATIONSET:
3210	    TODO
3211	    valuePush(ctxt, xmlXPathNewCString(""));
3212	    break;
3213    }
3214    STRANGE
3215}
3216
3217/**
3218 * xmlXPathStringLengthFunction:
3219 * @ctxt:  the XPath Parser context
3220 *
3221 * Implement the string-length() XPath function
3222 *    number string-length(string?)
3223 * The string-length returns the number of characters in the string
3224 * (see [3.6 Strings]). If the argument is omitted, it defaults to
3225 * the context node converted to a string, in other words the value
3226 * of the context node.
3227 */
3228void
3229xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3230    xmlXPathObjectPtr cur;
3231
3232    if (nargs == 0) {
3233	if (ctxt->context->node == NULL) {
3234	    valuePush(ctxt, xmlXPathNewFloat(0));
3235	} else {
3236	    xmlChar *content;
3237
3238	    content = xmlNodeGetContent(ctxt->context->node);
3239	    valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
3240	    xmlFree(content);
3241	}
3242	return;
3243    }
3244    CHECK_ARITY(1);
3245    CAST_TO_STRING;
3246    CHECK_TYPE(XPATH_STRING);
3247    cur = valuePop(ctxt);
3248    valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
3249    xmlXPathFreeObject(cur);
3250}
3251
3252/**
3253 * xmlXPathConcatFunction:
3254 * @ctxt:  the XPath Parser context
3255 *
3256 * Implement the concat() XPath function
3257 *    string concat(string, string, string*)
3258 * The concat function returns the concatenation of its arguments.
3259 */
3260void
3261xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3262    xmlXPathObjectPtr cur, newobj;
3263    xmlChar *tmp;
3264
3265    if (nargs < 2) {
3266	CHECK_ARITY(2);
3267    }
3268
3269    CAST_TO_STRING;
3270    cur = valuePop(ctxt);
3271    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
3272        xmlXPathFreeObject(cur);
3273	return;
3274    }
3275    nargs--;
3276
3277    while (nargs > 0) {
3278	CAST_TO_STRING;
3279	newobj = valuePop(ctxt);
3280	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
3281	    xmlXPathFreeObject(newobj);
3282	    xmlXPathFreeObject(cur);
3283	    XP_ERROR(XPATH_INVALID_TYPE);
3284	}
3285	tmp = xmlStrcat(newobj->stringval, cur->stringval);
3286	newobj->stringval = cur->stringval;
3287	cur->stringval = tmp;
3288
3289	xmlXPathFreeObject(newobj);
3290	nargs--;
3291    }
3292    valuePush(ctxt, cur);
3293}
3294
3295/**
3296 * xmlXPathContainsFunction:
3297 * @ctxt:  the XPath Parser context
3298 *
3299 * Implement the contains() XPath function
3300 *    boolean contains(string, string)
3301 * The contains function returns true if the first argument string
3302 * contains the second argument string, and otherwise returns false.
3303 */
3304void
3305xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3306    xmlXPathObjectPtr hay, needle;
3307
3308    CHECK_ARITY(2);
3309    CAST_TO_STRING;
3310    CHECK_TYPE(XPATH_STRING);
3311    needle = valuePop(ctxt);
3312    CAST_TO_STRING;
3313    hay = valuePop(ctxt);
3314    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
3315        xmlXPathFreeObject(hay);
3316        xmlXPathFreeObject(needle);
3317	XP_ERROR(XPATH_INVALID_TYPE);
3318    }
3319    if (xmlStrstr(hay->stringval, needle->stringval))
3320        valuePush(ctxt, xmlXPathNewBoolean(1));
3321    else
3322        valuePush(ctxt, xmlXPathNewBoolean(0));
3323    xmlXPathFreeObject(hay);
3324    xmlXPathFreeObject(needle);
3325}
3326
3327/**
3328 * xmlXPathStartsWithFunction:
3329 * @ctxt:  the XPath Parser context
3330 *
3331 * Implement the starts-with() XPath function
3332 *    boolean starts-with(string, string)
3333 * The starts-with function returns true if the first argument string
3334 * starts with the second argument string, and otherwise returns false.
3335 */
3336void
3337xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3338    xmlXPathObjectPtr hay, needle;
3339    int n;
3340
3341    CHECK_ARITY(2);
3342    CAST_TO_STRING;
3343    CHECK_TYPE(XPATH_STRING);
3344    needle = valuePop(ctxt);
3345    CAST_TO_STRING;
3346    hay = valuePop(ctxt);
3347    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
3348        xmlXPathFreeObject(hay);
3349        xmlXPathFreeObject(needle);
3350	XP_ERROR(XPATH_INVALID_TYPE);
3351    }
3352    n = xmlStrlen(needle->stringval);
3353    if (xmlStrncmp(hay->stringval, needle->stringval, n))
3354        valuePush(ctxt, xmlXPathNewBoolean(0));
3355    else
3356        valuePush(ctxt, xmlXPathNewBoolean(1));
3357    xmlXPathFreeObject(hay);
3358    xmlXPathFreeObject(needle);
3359}
3360
3361/**
3362 * xmlXPathSubstringFunction:
3363 * @ctxt:  the XPath Parser context
3364 *
3365 * Implement the substring() XPath function
3366 *    string substring(string, number, number?)
3367 * The substring function returns the substring of the first argument
3368 * starting at the position specified in the second argument with
3369 * length specified in the third argument. For example,
3370 * substring("12345",2,3) returns "234". If the third argument is not
3371 * specified, it returns the substring starting at the position specified
3372 * in the second argument and continuing to the end of the string. For
3373 * example, substring("12345",2) returns "2345".  More precisely, each
3374 * character in the string (see [3.6 Strings]) is considered to have a
3375 * numeric position: the position of the first character is 1, the position
3376 * of the second character is 2 and so on. The returned substring contains
3377 * those characters for which the position of the character is greater than
3378 * or equal to the second argument and, if the third argument is specified,
3379 * less than the sum of the second and third arguments; the comparisons
3380 * and addition used for the above follow the standard IEEE 754 rules. Thus:
3381 *  - substring("12345", 1.5, 2.6) returns "234"
3382 *  - substring("12345", 0, 3) returns "12"
3383 *  - substring("12345", 0 div 0, 3) returns ""
3384 *  - substring("12345", 1, 0 div 0) returns ""
3385 *  - substring("12345", -42, 1 div 0) returns "12345"
3386 *  - substring("12345", -1 div 0, 1 div 0) returns ""
3387 */
3388void
3389xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3390    xmlXPathObjectPtr str, start, len;
3391    double le, in;
3392    int i, l;
3393    xmlChar *ret;
3394
3395    /*
3396     * Conformance needs to be checked !!!!!
3397     */
3398    if (nargs < 2) {
3399	CHECK_ARITY(2);
3400    }
3401    if (nargs > 3) {
3402	CHECK_ARITY(3);
3403    }
3404    if (nargs == 3) {
3405	CAST_TO_NUMBER;
3406	CHECK_TYPE(XPATH_NUMBER);
3407	len = valuePop(ctxt);
3408	le = len->floatval;
3409        xmlXPathFreeObject(len);
3410    } else {
3411	le = 2000000000;
3412    }
3413    CAST_TO_NUMBER;
3414    CHECK_TYPE(XPATH_NUMBER);
3415    start = valuePop(ctxt);
3416    in = start->floatval;
3417    xmlXPathFreeObject(start);
3418    CAST_TO_STRING;
3419    CHECK_TYPE(XPATH_STRING);
3420    str = valuePop(ctxt);
3421    le += in;
3422
3423    /* integer index of the first char */
3424    i = (int) in;
3425    if (((double)i) != in) i++;
3426
3427    /* integer index of the last char */
3428    l = (int) le;
3429    if (((double)l) != le) l++;
3430
3431    /* back to a zero based len */
3432    i--;
3433    l--;
3434
3435    /* check against the string len */
3436    if (l > 1024) {
3437        l = xmlStrlen(str->stringval);
3438    }
3439    if (i < 0) {
3440        i = 0;
3441    }
3442
3443    /* number of chars to copy */
3444    l -= i;
3445
3446    ret = xmlStrsub(str->stringval, i, l);
3447    if (ret == NULL)
3448	valuePush(ctxt, xmlXPathNewCString(""));
3449    else {
3450	valuePush(ctxt, xmlXPathNewString(ret));
3451	xmlFree(ret);
3452    }
3453    xmlXPathFreeObject(str);
3454}
3455
3456/**
3457 * xmlXPathSubstringBeforeFunction:
3458 * @ctxt:  the XPath Parser context
3459 *
3460 * Implement the substring-before() XPath function
3461 *    string substring-before(string, string)
3462 * The substring-before function returns the substring of the first
3463 * argument string that precedes the first occurrence of the second
3464 * argument string in the first argument string, or the empty string
3465 * if the first argument string does not contain the second argument
3466 * string. For example, substring-before("1999/04/01","/") returns 1999.
3467 */
3468void
3469xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3470  xmlXPathObjectPtr str;
3471  xmlXPathObjectPtr find;
3472  xmlBufferPtr target;
3473  const xmlChar *point;
3474  int offset;
3475
3476  CHECK_ARITY(2);
3477  CAST_TO_STRING;
3478  find = valuePop(ctxt);
3479  CAST_TO_STRING;
3480  str = valuePop(ctxt);
3481
3482  target = xmlBufferCreate();
3483  if (target) {
3484    point = xmlStrstr(str->stringval, find->stringval);
3485    if (point) {
3486      offset = (int)(point - str->stringval);
3487      xmlBufferAdd(target, str->stringval, offset);
3488    }
3489    valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3490    xmlBufferFree(target);
3491  }
3492
3493  xmlXPathFreeObject(str);
3494  xmlXPathFreeObject(find);
3495}
3496
3497/**
3498 * xmlXPathSubstringAfterFunction:
3499 * @ctxt:  the XPath Parser context
3500 *
3501 * Implement the substring-after() XPath function
3502 *    string substring-after(string, string)
3503 * The substring-after function returns the substring of the first
3504 * argument string that follows the first occurrence of the second
3505 * argument string in the first argument string, or the empty stringi
3506 * if the first argument string does not contain the second argument
3507 * string. For example, substring-after("1999/04/01","/") returns 04/01,
3508 * and substring-after("1999/04/01","19") returns 99/04/01.
3509 */
3510void
3511xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3512  xmlXPathObjectPtr str;
3513  xmlXPathObjectPtr find;
3514  xmlBufferPtr target;
3515  const xmlChar *point;
3516  int offset;
3517
3518  CHECK_ARITY(2);
3519  CAST_TO_STRING;
3520  find = valuePop(ctxt);
3521  CAST_TO_STRING;
3522  str = valuePop(ctxt);
3523
3524  target = xmlBufferCreate();
3525  if (target) {
3526    point = xmlStrstr(str->stringval, find->stringval);
3527    if (point) {
3528      offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
3529      xmlBufferAdd(target, &str->stringval[offset],
3530		   xmlStrlen(str->stringval) - offset);
3531    }
3532    valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3533    xmlBufferFree(target);
3534  }
3535
3536  xmlXPathFreeObject(str);
3537  xmlXPathFreeObject(find);
3538}
3539
3540/**
3541 * xmlXPathNormalizeFunction:
3542 * @ctxt:  the XPath Parser context
3543 *
3544 * Implement the normalize-space() XPath function
3545 *    string normalize-space(string?)
3546 * The normalize-space function returns the argument string with white
3547 * space normalized by stripping leading and trailing whitespace
3548 * and replacing sequences of whitespace characters by a single
3549 * space. Whitespace characters are the same allowed by the S production
3550 * in XML. If the argument is omitted, it defaults to the context
3551 * node converted to a string, in other words the value of the context node.
3552 */
3553void
3554xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3555  xmlXPathObjectPtr obj = NULL;
3556  xmlChar *source = NULL;
3557  xmlBufferPtr target;
3558  xmlChar blank;
3559
3560  if (nargs == 0) {
3561    /* Use current context node */
3562    valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3563    xmlXPathStringFunction(ctxt, 1);
3564    nargs = 1;
3565  }
3566
3567  CHECK_ARITY(1);
3568  CAST_TO_STRING;
3569  CHECK_TYPE(XPATH_STRING);
3570  obj = valuePop(ctxt);
3571  source = obj->stringval;
3572
3573  target = xmlBufferCreate();
3574  if (target && source) {
3575
3576    /* Skip leading whitespaces */
3577    while (IS_BLANK(*source))
3578      source++;
3579
3580    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
3581    blank = 0;
3582    while (*source) {
3583      if (IS_BLANK(*source)) {
3584	blank = *source;
3585      } else {
3586	if (blank) {
3587	  xmlBufferAdd(target, &blank, 1);
3588	  blank = 0;
3589	}
3590	xmlBufferAdd(target, source, 1);
3591      }
3592      source++;
3593    }
3594
3595    valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3596    xmlBufferFree(target);
3597  }
3598  xmlXPathFreeObject(obj);
3599}
3600
3601/**
3602 * xmlXPathTranslateFunction:
3603 * @ctxt:  the XPath Parser context
3604 *
3605 * Implement the translate() XPath function
3606 *    string translate(string, string, string)
3607 * The translate function returns the first argument string with
3608 * occurrences of characters in the second argument string replaced
3609 * by the character at the corresponding position in the third argument
3610 * string. For example, translate("bar","abc","ABC") returns the string
3611 * BAr. If there is a character in the second argument string with no
3612 * character at a corresponding position in the third argument string
3613 * (because the second argument string is longer than the third argument
3614 * string), then occurrences of that character in the first argument
3615 * string are removed. For example, translate("--aaa--","abc-","ABC")
3616 * returns "AAA". If a character occurs more than once in second
3617 * argument string, then the first occurrence determines the replacement
3618 * character. If the third argument string is longer than the second
3619 * argument string, then excess characters are ignored.
3620 */
3621void
3622xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3623  xmlXPathObjectPtr str;
3624  xmlXPathObjectPtr from;
3625  xmlXPathObjectPtr to;
3626  xmlBufferPtr target;
3627  int i, offset, max;
3628  xmlChar ch;
3629  const xmlChar *point;
3630
3631  CHECK_ARITY(3);
3632
3633  CAST_TO_STRING;
3634  to = valuePop(ctxt);
3635  CAST_TO_STRING;
3636  from = valuePop(ctxt);
3637  CAST_TO_STRING;
3638  str = valuePop(ctxt);
3639
3640  target = xmlBufferCreate();
3641  if (target) {
3642    max = xmlStrlen(to->stringval);
3643    for (i = 0; (ch = str->stringval[i]); i++) {
3644      point = xmlStrchr(from->stringval, ch);
3645      if (point) {
3646	/* Warning: This may not work with UTF-8 */
3647	offset = (int)(point - from->stringval);
3648	if (offset < max)
3649	  xmlBufferAdd(target, &to->stringval[offset], 1);
3650      } else
3651	xmlBufferAdd(target, &ch, 1);
3652    }
3653  }
3654  valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3655  xmlBufferFree(target);
3656  xmlXPathFreeObject(str);
3657  xmlXPathFreeObject(from);
3658  xmlXPathFreeObject(to);
3659}
3660
3661/**
3662 * xmlXPathBooleanFunction:
3663 * @ctxt:  the XPath Parser context
3664 *
3665 * Implement the boolean() XPath function
3666 *    boolean boolean(object)
3667 * he boolean function converts its argument to a boolean as follows:
3668 *    - a number is true if and only if it is neither positive or
3669 *      negative zero nor NaN
3670 *    - a node-set is true if and only if it is non-empty
3671 *    - a string is true if and only if its length is non-zero
3672 */
3673void
3674xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3675    xmlXPathObjectPtr cur;
3676    int res = 0;
3677
3678    CHECK_ARITY(1);
3679    cur = valuePop(ctxt);
3680    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
3681    switch (cur->type) {
3682        case XPATH_NODESET:
3683	    if ((cur->nodesetval == NULL) ||
3684	        (cur->nodesetval->nodeNr == 0)) res = 0;
3685	    else
3686	        res = 1;
3687	    break;
3688	case XPATH_STRING:
3689	    if ((cur->stringval == NULL) ||
3690	        (cur->stringval[0] == 0)) res = 0;
3691	    else
3692	        res = 1;
3693	    break;
3694        case XPATH_BOOLEAN:
3695	    valuePush(ctxt, cur);
3696	    return;
3697	case XPATH_NUMBER:
3698	    if (cur->floatval) res = 1;
3699	    break;
3700	default:
3701	    STRANGE
3702    }
3703    xmlXPathFreeObject(cur);
3704    valuePush(ctxt, xmlXPathNewBoolean(res));
3705}
3706
3707/**
3708 * xmlXPathNotFunction:
3709 * @ctxt:  the XPath Parser context
3710 *
3711 * Implement the not() XPath function
3712 *    boolean not(boolean)
3713 * The not function returns true if its argument is false,
3714 * and false otherwise.
3715 */
3716void
3717xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3718    CHECK_ARITY(1);
3719    CAST_TO_BOOLEAN;
3720    CHECK_TYPE(XPATH_BOOLEAN);
3721    ctxt->value->boolval = ! ctxt->value->boolval;
3722}
3723
3724/**
3725 * xmlXPathTrueFunction:
3726 * @ctxt:  the XPath Parser context
3727 *
3728 * Implement the true() XPath function
3729 *    boolean true()
3730 */
3731void
3732xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3733    CHECK_ARITY(0);
3734    valuePush(ctxt, xmlXPathNewBoolean(1));
3735}
3736
3737/**
3738 * xmlXPathFalseFunction:
3739 * @ctxt:  the XPath Parser context
3740 *
3741 * Implement the false() XPath function
3742 *    boolean false()
3743 */
3744void
3745xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3746    CHECK_ARITY(0);
3747    valuePush(ctxt, xmlXPathNewBoolean(0));
3748}
3749
3750/**
3751 * xmlXPathLangFunction:
3752 * @ctxt:  the XPath Parser context
3753 *
3754 * Implement the lang() XPath function
3755 *    boolean lang(string)
3756 * The lang function returns true or false depending on whether the
3757 * language of the context node as specified by xml:lang attributes
3758 * is the same as or is a sublanguage of the language specified by
3759 * the argument string. The language of the context node is determined
3760 * by the value of the xml:lang attribute on the context node, or, if
3761 * the context node has no xml:lang attribute, by the value of the
3762 * xml:lang attribute on the nearest ancestor of the context node that
3763 * has an xml:lang attribute. If there is no such attribute, then lang
3764 * returns false. If there is such an attribute, then lang returns
3765 * true if the attribute value is equal to the argument ignoring case,
3766 * or if there is some suffix starting with - such that the attribute
3767 * value is equal to the argument ignoring that suffix of the attribute
3768 * value and ignoring case.
3769 */
3770void
3771xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3772    xmlXPathObjectPtr val;
3773    const xmlChar *theLang;
3774    const xmlChar *lang;
3775    int ret = 0;
3776    int i;
3777
3778    CHECK_ARITY(1);
3779    CAST_TO_STRING;
3780    CHECK_TYPE(XPATH_STRING);
3781    val = valuePop(ctxt);
3782    lang = val->stringval;
3783    theLang = xmlNodeGetLang(ctxt->context->node);
3784    if ((theLang != NULL) && (lang != NULL)) {
3785        for (i = 0;lang[i] != 0;i++)
3786	    if (toupper(lang[i]) != toupper(theLang[i]))
3787	        goto not_equal;
3788        ret = 1;
3789    }
3790not_equal:
3791    xmlXPathFreeObject(val);
3792    valuePush(ctxt, xmlXPathNewBoolean(ret));
3793}
3794
3795/**
3796 * xmlXPathNumberFunction:
3797 * @ctxt:  the XPath Parser context
3798 *
3799 * Implement the number() XPath function
3800 *    number number(object?)
3801 */
3802void
3803xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3804    xmlXPathObjectPtr cur;
3805    double res;
3806
3807    if (nargs == 0) {
3808	if (ctxt->context->node == NULL) {
3809	    valuePush(ctxt, xmlXPathNewFloat(0.0));
3810	} else {
3811	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
3812
3813	    res = xmlXPathStringEvalNumber(content);
3814	    valuePush(ctxt, xmlXPathNewFloat(res));
3815	    xmlFree(content);
3816	}
3817	return;
3818    }
3819
3820    CHECK_ARITY(1);
3821    cur = valuePop(ctxt);
3822    switch (cur->type) {
3823	case XPATH_UNDEFINED:
3824#ifdef DEBUG_EXPR
3825	    xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3826#endif
3827	    valuePush(ctxt, xmlXPathNewFloat(0.0));
3828	    break;
3829        case XPATH_NODESET:
3830	    valuePush(ctxt, cur);
3831	    xmlXPathStringFunction(ctxt, 1);
3832	    cur = valuePop(ctxt);
3833	case XPATH_STRING:
3834	    res = xmlXPathStringEvalNumber(cur->stringval);
3835	    valuePush(ctxt, xmlXPathNewFloat(res));
3836	    xmlXPathFreeObject(cur);
3837	    return;
3838        case XPATH_BOOLEAN:
3839	    if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
3840	    else valuePush(ctxt, xmlXPathNewFloat(0.0));
3841	    xmlXPathFreeObject(cur);
3842	    return;
3843	case XPATH_NUMBER:
3844	    valuePush(ctxt, cur);
3845	    return;
3846	case XPATH_USERS:
3847	case XPATH_POINT:
3848	case XPATH_RANGE:
3849	case XPATH_LOCATIONSET:
3850	    TODO
3851	    valuePush(ctxt, xmlXPathNewFloat(0.0));
3852	    break;
3853    }
3854    STRANGE
3855}
3856
3857/**
3858 * xmlXPathSumFunction:
3859 * @ctxt:  the XPath Parser context
3860 *
3861 * Implement the sum() XPath function
3862 *    number sum(node-set)
3863 * The sum function returns the sum of the values of the nodes in
3864 * the argument node-set.
3865 */
3866void
3867xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3868    xmlXPathObjectPtr cur;
3869    int i;
3870
3871    CHECK_ARITY(1);
3872    CHECK_TYPE(XPATH_NODESET);
3873    cur = valuePop(ctxt);
3874
3875    if (cur->nodesetval->nodeNr == 0) {
3876	valuePush(ctxt, xmlXPathNewFloat(0.0));
3877    } else {
3878	valuePush(ctxt,
3879		  xmlXPathNewNodeSet(cur->nodesetval->nodeTab[0]));
3880	xmlXPathNumberFunction(ctxt, 1);
3881	for (i = 1; i < cur->nodesetval->nodeNr; i++) {
3882	    valuePush(ctxt,
3883		      xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
3884	    xmlXPathAddValues(ctxt);
3885	}
3886    }
3887    xmlXPathFreeObject(cur);
3888}
3889
3890/**
3891 * xmlXPathFloorFunction:
3892 * @ctxt:  the XPath Parser context
3893 *
3894 * Implement the floor() XPath function
3895 *    number floor(number)
3896 * The floor function returns the largest (closest to positive infinity)
3897 * number that is not greater than the argument and that is an integer.
3898 */
3899void
3900xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3901    CHECK_ARITY(1);
3902    CAST_TO_NUMBER;
3903    CHECK_TYPE(XPATH_NUMBER);
3904#if 0
3905    ctxt->value->floatval = floor(ctxt->value->floatval);
3906#else
3907    /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
3908    ctxt->value->floatval = (double)((int) ctxt->value->floatval);
3909#endif
3910}
3911
3912/**
3913 * xmlXPathCeilingFunction:
3914 * @ctxt:  the XPath Parser context
3915 *
3916 * Implement the ceiling() XPath function
3917 *    number ceiling(number)
3918 * The ceiling function returns the smallest (closest to negative infinity)
3919 * number that is not less than the argument and that is an integer.
3920 */
3921void
3922xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3923    double f;
3924
3925    CHECK_ARITY(1);
3926    CAST_TO_NUMBER;
3927    CHECK_TYPE(XPATH_NUMBER);
3928
3929#if 0
3930    ctxt->value->floatval = ceil(ctxt->value->floatval);
3931#else
3932    f = (double)((int) ctxt->value->floatval);
3933    if (f != ctxt->value->floatval)
3934	ctxt->value->floatval = f + 1;
3935#endif
3936}
3937
3938/**
3939 * xmlXPathRoundFunction:
3940 * @ctxt:  the XPath Parser context
3941 *
3942 * Implement the round() XPath function
3943 *    number round(number)
3944 * The round function returns the number that is closest to the
3945 * argument and that is an integer. If there are two such numbers,
3946 * then the one that is even is returned.
3947 */
3948void
3949xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3950    double f;
3951
3952    CHECK_ARITY(1);
3953    CAST_TO_NUMBER;
3954    CHECK_TYPE(XPATH_NUMBER);
3955
3956    if ((ctxt->value->floatval == xmlXPathNAN) ||
3957	(ctxt->value->floatval == xmlXPathPINF) ||
3958	(ctxt->value->floatval == xmlXPathNINF) ||
3959	(ctxt->value->floatval == 0.0))
3960	return;
3961
3962#if 0
3963    f = floor(ctxt->value->floatval);
3964#else
3965    f = (double)((int) ctxt->value->floatval);
3966#endif
3967    if (ctxt->value->floatval < f + 0.5)
3968        ctxt->value->floatval = f;
3969    else
3970        ctxt->value->floatval = f + 1;
3971}
3972
3973/************************************************************************
3974 *									*
3975 *			The Parser					*
3976 *									*
3977 ************************************************************************/
3978
3979/*
3980 * a couple of forward declarations since we use a recursive call based
3981 * implementation.
3982 */
3983void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
3984void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
3985void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
3986void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
3987
3988/**
3989 * xmlXPathParseNCName:
3990 * @ctxt:  the XPath Parser context
3991 *
3992 * parse an XML namespace non qualified name.
3993 *
3994 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
3995 *
3996 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
3997 *                       CombiningChar | Extender
3998 *
3999 * Returns the namespace name or NULL
4000 */
4001
4002xmlChar *
4003xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
4004    const xmlChar *q;
4005    xmlChar *ret = NULL;
4006
4007    if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
4008    q = NEXT;
4009
4010    while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
4011           (CUR == '.') || (CUR == '-') ||
4012	   (CUR == '_') ||
4013	   (IS_COMBINING(CUR)) ||
4014	   (IS_EXTENDER(CUR)))
4015	NEXT;
4016
4017    ret = xmlStrndup(q, CUR_PTR - q);
4018
4019    return(ret);
4020}
4021
4022/**
4023 * xmlXPathParseQName:
4024 * @ctxt:  the XPath Parser context
4025 * @prefix:  a xmlChar **
4026 *
4027 * parse an XML qualified name
4028 *
4029 * [NS 5] QName ::= (Prefix ':')? LocalPart
4030 *
4031 * [NS 6] Prefix ::= NCName
4032 *
4033 * [NS 7] LocalPart ::= NCName
4034 *
4035 * Returns the function returns the local part, and prefix is updated
4036 *   to get the Prefix if any.
4037 */
4038
4039xmlChar *
4040xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
4041    xmlChar *ret = NULL;
4042
4043    *prefix = NULL;
4044    ret = xmlXPathParseNCName(ctxt);
4045    if (CUR == ':') {
4046        *prefix = ret;
4047	NEXT;
4048	ret = xmlXPathParseNCName(ctxt);
4049    }
4050    return(ret);
4051}
4052
4053/**
4054 * xmlXPathParseName:
4055 * @ctxt:  the XPointer Parser context
4056 *
4057 * parse an XML name
4058 *
4059 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
4060 *                  CombiningChar | Extender
4061 *
4062 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
4063 *
4064 * Returns the namespace name or NULL
4065 */
4066
4067xmlChar *
4068xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
4069    const xmlChar *q;
4070    xmlChar *ret = NULL;
4071
4072    if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
4073    q = NEXT;
4074
4075    /* TODO Make this UTF8 compliant !!! */
4076    while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
4077           (CUR == '.') || (CUR == '-') ||
4078	   (CUR == '_') || (CUR == ':') ||
4079	   (IS_COMBINING(CUR)) ||
4080	   (IS_EXTENDER(CUR)))
4081	NEXT;
4082
4083    ret = xmlStrndup(q, CUR_PTR - q);
4084
4085    return(ret);
4086}
4087
4088/**
4089 * xmlXPathStringEvalNumber:
4090 * @str:  A string to scan
4091 *
4092 *  [30]   Number ::=   Digits ('.' Digits?)?
4093 *                    | '.' Digits
4094 *  [31]   Digits ::=   [0-9]+
4095 *
4096 * Parse and evaluate a Number in the string
4097 * In complement of the Number expression, this function also handles
4098 * negative values : '-' Number.
4099 *
4100 * Returns the double value.
4101 */
4102double
4103xmlXPathStringEvalNumber(const xmlChar *str) {
4104    const xmlChar *cur = str;
4105    double ret = 0.0;
4106    double mult = 1;
4107    int ok = 0;
4108    int isneg = 0;
4109
4110    while (*cur == ' ') cur++;
4111    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
4112        return(xmlXPathNAN);
4113    }
4114    if (*cur == '-') {
4115	isneg = 1;
4116	cur++;
4117    }
4118    while ((*cur >= '0') && (*cur <= '9')) {
4119        ret = ret * 10 + (*cur - '0');
4120	ok = 1;
4121	cur++;
4122    }
4123    if (*cur == '.') {
4124        cur++;
4125	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
4126	    return(xmlXPathNAN);
4127	}
4128	while ((*cur >= '0') && (*cur <= '9')) {
4129	    mult /= 10;
4130	    ret = ret  + (*cur - '0') * mult;
4131	    cur++;
4132	}
4133    }
4134    while (*cur == ' ') cur++;
4135    if (*cur != 0) return(xmlXPathNAN);
4136    if (isneg) ret = -ret;
4137    return(ret);
4138}
4139
4140/**
4141 * xmlXPathEvalNumber:
4142 * @ctxt:  the XPath Parser context
4143 *
4144 *  [30]   Number ::=   Digits ('.' Digits?)?
4145 *                    | '.' Digits
4146 *  [31]   Digits ::=   [0-9]+
4147 *
4148 * Parse and evaluate a Number, then push it on the stack
4149 *
4150 */
4151void
4152xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
4153    double ret = 0.0;
4154    double mult = 1;
4155    int ok = 0;
4156
4157    CHECK_ERROR;
4158    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
4159        XP_ERROR(XPATH_NUMBER_ERROR);
4160    }
4161    while ((CUR >= '0') && (CUR <= '9')) {
4162        ret = ret * 10 + (CUR - '0');
4163	ok = 1;
4164	NEXT;
4165    }
4166    if (CUR == '.') {
4167        NEXT;
4168	if (((CUR < '0') || (CUR > '9')) && (!ok)) {
4169	     XP_ERROR(XPATH_NUMBER_ERROR);
4170	}
4171	while ((CUR >= '0') && (CUR <= '9')) {
4172	    mult /= 10;
4173	    ret = ret  + (CUR - '0') * mult;
4174	    NEXT;
4175	}
4176    }
4177    valuePush(ctxt, xmlXPathNewFloat(ret));
4178}
4179
4180/**
4181 * xmlXPathEvalLiteral:
4182 * @ctxt:  the XPath Parser context
4183 *
4184 * Parse a Literal and push it on the stack.
4185 *
4186 *  [29]   Literal ::=   '"' [^"]* '"'
4187 *                    | "'" [^']* "'"
4188 *
4189 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
4190 */
4191void
4192xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
4193    const xmlChar *q;
4194    xmlChar *ret = NULL;
4195
4196    if (CUR == '"') {
4197        NEXT;
4198	q = CUR_PTR;
4199	while ((IS_CHAR(CUR)) && (CUR != '"'))
4200	    NEXT;
4201	if (!IS_CHAR(CUR)) {
4202	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
4203	} else {
4204	    ret = xmlStrndup(q, CUR_PTR - q);
4205	    NEXT;
4206        }
4207    } else if (CUR == '\'') {
4208        NEXT;
4209	q = CUR_PTR;
4210	while ((IS_CHAR(CUR)) && (CUR != '\''))
4211	    NEXT;
4212	if (!IS_CHAR(CUR)) {
4213	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
4214	} else {
4215	    ret = xmlStrndup(q, CUR_PTR - q);
4216	    NEXT;
4217        }
4218    } else {
4219	XP_ERROR(XPATH_START_LITERAL_ERROR);
4220    }
4221    if (ret == NULL) return;
4222    valuePush(ctxt, xmlXPathNewString(ret));
4223    xmlFree(ret);
4224}
4225
4226/**
4227 * xmlXPathEvalVariableReference:
4228 * @ctxt:  the XPath Parser context
4229 *
4230 * Parse a VariableReference, evaluate it and push it on the stack.
4231 *
4232 * The variable bindings consist of a mapping from variable names
4233 * to variable values. The value of a variable is an object, which
4234 * of any of the types that are possible for the value of an expression,
4235 * and may also be of additional types not specified here.
4236 *
4237 * Early evaluation is possible since:
4238 * The variable bindings [...] used to evaluate a subexpression are
4239 * always the same as those used to evaluate the containing expression.
4240 *
4241 *  [36]   VariableReference ::=   '$' QName
4242 */
4243void
4244xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
4245    xmlChar *name;
4246    xmlChar *prefix;
4247    xmlXPathObjectPtr value;
4248
4249    SKIP_BLANKS;
4250    if (CUR != '$') {
4251	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
4252    }
4253    name = xmlXPathParseQName(ctxt, &prefix);
4254    if (name == NULL) {
4255	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
4256    }
4257    if (prefix == NULL) {
4258	value = xmlXPathVariableLookup(ctxt->context, name);
4259    } else {
4260	TODO;
4261	value = NULL;
4262    }
4263    xmlFree(name);
4264    if (prefix != NULL) xmlFree(prefix);
4265    if (value == NULL) {
4266	XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
4267    }
4268    valuePush(ctxt, value);
4269    SKIP_BLANKS;
4270}
4271
4272/**
4273 * xmlXPathIsNodeType:
4274 * @ctxt:  the XPath Parser context
4275 * @name:  a name string
4276 *
4277 * Is the name given a NodeType one.
4278 *
4279 *  [38]   NodeType ::=   'comment'
4280 *                    | 'text'
4281 *                    | 'processing-instruction'
4282 *                    | 'node'
4283 *
4284 * Returns 1 if true 0 otherwise
4285 */
4286int
4287xmlXPathIsNodeType(const xmlChar *name) {
4288    if (name == NULL)
4289	return(0);
4290
4291    if (xmlStrEqual(name, BAD_CAST "comment"))
4292	return(1);
4293    if (xmlStrEqual(name, BAD_CAST "text"))
4294	return(1);
4295    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
4296	return(1);
4297    if (xmlStrEqual(name, BAD_CAST "node"))
4298	return(1);
4299    return(0);
4300}
4301
4302/**
4303 * xmlXPathEvalFunctionCall:
4304 * @ctxt:  the XPath Parser context
4305 *
4306 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
4307 *  [17]   Argument ::=   Expr
4308 *
4309 * Parse and evaluate a function call, the evaluation of all arguments are
4310 * pushed on the stack
4311 */
4312void
4313xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
4314    xmlChar *name;
4315    xmlChar *prefix;
4316    xmlXPathFunction func;
4317    int nbargs = 0;
4318
4319    name = xmlXPathParseQName(ctxt, &prefix);
4320    if (name == NULL) {
4321	XP_ERROR(XPATH_EXPR_ERROR);
4322    }
4323    SKIP_BLANKS;
4324    if (prefix == NULL) {
4325	func = xmlXPathFunctionLookup(ctxt->context, name);
4326    } else {
4327	TODO;
4328	func = NULL;
4329    }
4330    if (func == NULL) {
4331        xmlFree(name);
4332	if (prefix != NULL) xmlFree(prefix);
4333	XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
4334    }
4335#ifdef DEBUG_EXPR
4336    if (prefix == NULL)
4337	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
4338			name);
4339    else
4340	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
4341			prefix, name);
4342#endif
4343
4344    xmlFree(name);
4345    if (prefix != NULL) xmlFree(prefix);
4346
4347    if (CUR != '(') {
4348	XP_ERROR(XPATH_EXPR_ERROR);
4349    }
4350    NEXT;
4351    SKIP_BLANKS;
4352
4353    while (CUR != ')') {
4354        xmlXPathEvalExpr(ctxt);
4355	nbargs++;
4356	if (CUR == ')') break;
4357	if (CUR != ',') {
4358	    XP_ERROR(XPATH_EXPR_ERROR);
4359	}
4360	NEXT;
4361	SKIP_BLANKS;
4362    }
4363    NEXT;
4364    SKIP_BLANKS;
4365    func(ctxt, nbargs);
4366}
4367
4368/**
4369 * xmlXPathEvalPrimaryExpr:
4370 * @ctxt:  the XPath Parser context
4371 *
4372 *  [15]   PrimaryExpr ::=   VariableReference
4373 *                | '(' Expr ')'
4374 *                | Literal
4375 *                | Number
4376 *                | FunctionCall
4377 *
4378 * Parse and evaluate a primary expression, then push the result on the stack
4379 */
4380void
4381xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
4382    SKIP_BLANKS;
4383    if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
4384    else if (CUR == '(') {
4385	NEXT;
4386	SKIP_BLANKS;
4387	xmlXPathEvalExpr(ctxt);
4388	if (CUR != ')') {
4389	    XP_ERROR(XPATH_EXPR_ERROR);
4390	}
4391	NEXT;
4392	SKIP_BLANKS;
4393    } else if (IS_DIGIT(CUR)) {
4394	xmlXPathEvalNumber(ctxt);
4395    } else if ((CUR == '\'') || (CUR == '"')) {
4396	xmlXPathEvalLiteral(ctxt);
4397    } else {
4398	xmlXPathEvalFunctionCall(ctxt);
4399    }
4400    SKIP_BLANKS;
4401}
4402
4403/**
4404 * xmlXPathEvalFilterExpr:
4405 * @ctxt:  the XPath Parser context
4406 *
4407 *  [20]   FilterExpr ::=   PrimaryExpr
4408 *               | FilterExpr Predicate
4409 *
4410 * Parse and evaluate a filter expression, then push the result on the stack
4411 * Square brackets are used to filter expressions in the same way that
4412 * they are used in location paths. It is an error if the expression to
4413 * be filtered does not evaluate to a node-set. The context node list
4414 * used for evaluating the expression in square brackets is the node-set
4415 * to be filtered listed in document order.
4416 */
4417
4418void
4419xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
4420    xmlXPathEvalPrimaryExpr(ctxt);
4421    CHECK_ERROR;
4422    SKIP_BLANKS;
4423
4424    while (CUR == '[') {
4425	if ((ctxt->value == NULL) ||
4426	    ((ctxt->value->type != XPATH_NODESET) &&
4427	     (ctxt->value->type != XPATH_LOCATIONSET)))
4428	    XP_ERROR(XPATH_INVALID_TYPE)
4429
4430	if (ctxt->value->type == XPATH_NODESET)
4431	    xmlXPathEvalPredicate(ctxt);
4432        else
4433	    xmlXPtrEvalRangePredicate(ctxt);
4434	SKIP_BLANKS;
4435    }
4436
4437
4438}
4439
4440/**
4441 * xmlXPathScanName:
4442 * @ctxt:  the XPath Parser context
4443 *
4444 * Trickery: parse an XML name but without consuming the input flow
4445 * Needed to avoid insanity in the parser state.
4446 *
4447 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
4448 *                  CombiningChar | Extender
4449 *
4450 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
4451 *
4452 * [6] Names ::= Name (S Name)*
4453 *
4454 * Returns the Name parsed or NULL
4455 */
4456
4457xmlChar *
4458xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
4459    xmlChar buf[XML_MAX_NAMELEN];
4460    int len = 0;
4461
4462    SKIP_BLANKS;
4463    if (!IS_LETTER(CUR) && (CUR != '_') &&
4464        (CUR != ':')) {
4465	return(NULL);
4466    }
4467
4468    while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
4469           (NXT(len) == '.') || (NXT(len) == '-') ||
4470	   (NXT(len) == '_') || (NXT(len) == ':') ||
4471	   (IS_COMBINING(NXT(len))) ||
4472	   (IS_EXTENDER(NXT(len)))) {
4473	buf[len] = NXT(len);
4474	len++;
4475	if (len >= XML_MAX_NAMELEN) {
4476	    xmlGenericError(xmlGenericErrorContext,
4477	       "xmlScanName: reached XML_MAX_NAMELEN limit\n");
4478	    while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
4479		   (NXT(len) == '.') || (NXT(len) == '-') ||
4480		   (NXT(len) == '_') || (NXT(len) == ':') ||
4481		   (IS_COMBINING(NXT(len))) ||
4482		   (IS_EXTENDER(NXT(len))))
4483		 len++;
4484	    break;
4485	}
4486    }
4487    return(xmlStrndup(buf, len));
4488}
4489
4490/**
4491 * xmlXPathEvalPathExpr:
4492 * @ctxt:  the XPath Parser context
4493 *
4494 *  [19]   PathExpr ::=   LocationPath
4495 *               | FilterExpr
4496 *               | FilterExpr '/' RelativeLocationPath
4497 *               | FilterExpr '//' RelativeLocationPath
4498 *
4499 * Parse and evaluate a path expression, then push the result on the stack
4500 * The / operator and // operators combine an arbitrary expression
4501 * and a relative location path. It is an error if the expression
4502 * does not evaluate to a node-set.
4503 * The / operator does composition in the same way as when / is
4504 * used in a location path. As in location paths, // is short for
4505 * /descendant-or-self::node()/.
4506 */
4507
4508void
4509xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
4510    int lc = 1;           /* Should we branch to LocationPath ?         */
4511    xmlChar *name = NULL; /* we may have to preparse a name to find out */
4512
4513    SKIP_BLANKS;
4514    if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
4515        (CUR == '\'') || (CUR == '"')) {
4516	lc = 0;
4517    } else if (CUR == '/') {
4518	/* relative or absolute location path */
4519	lc = 1;
4520    } else if (CUR == '@') {
4521	/* relative abbreviated attribute location path */
4522	lc = 1;
4523    } else if (CUR == '.') {
4524	/* relative abbreviated attribute location path */
4525	lc = 1;
4526    } else {
4527	/*
4528	 * Problem is finding if we have a name here whether it's:
4529	 *   - a nodetype
4530	 *   - a function call in which case it's followed by '('
4531	 *   - an axis in which case it's followed by ':'
4532	 *   - a element name
4533	 * We do an a priori analysis here rather than having to
4534	 * maintain parsed token content through the recursive function
4535	 * calls. This looks uglier but makes the code quite easier to
4536	 * read/write/debug.
4537	 */
4538	SKIP_BLANKS;
4539	name = xmlXPathScanName(ctxt);
4540	if (name != NULL) {
4541	    int len =xmlStrlen(name);
4542	    int blank = 0;
4543
4544	    while (NXT(len) != 0) {
4545		if (NXT(len) == '/') {
4546		    /* element name */
4547#ifdef DEBUG_STEP
4548		    xmlGenericError(xmlGenericErrorContext,
4549			    "PathExpr: AbbrRelLocation\n");
4550#endif
4551		    lc = 1;
4552		    break;
4553		} else if (IS_BLANK(NXT(len))) {
4554		    /* skip to next */
4555		    blank = 1;
4556		} else if (NXT(len) == ':') {
4557#ifdef DEBUG_STEP
4558		    xmlGenericError(xmlGenericErrorContext,
4559			    "PathExpr: AbbrRelLocation\n");
4560#endif
4561		    lc = 1;
4562		    break;
4563		} else if ((NXT(len) == '(')) {
4564		    /* Note Type or Function */
4565		    if (xmlXPathIsNodeType(name)) {
4566#ifdef DEBUG_STEP
4567		        xmlGenericError(xmlGenericErrorContext,
4568				"PathExpr: Type search\n");
4569#endif
4570			lc = 1;
4571		    } else {
4572#ifdef DEBUG_STEP
4573		        xmlGenericError(xmlGenericErrorContext,
4574				"PathExpr: function call\n");
4575#endif
4576			lc = 0;
4577		    }
4578                    break;
4579		} else if ((NXT(len) == '[')) {
4580		    /* element name */
4581#ifdef DEBUG_STEP
4582		    xmlGenericError(xmlGenericErrorContext,
4583			    "PathExpr: AbbrRelLocation\n");
4584#endif
4585		    lc = 1;
4586		    break;
4587		} else {
4588		    XP_ERROR(XPATH_EXPR_ERROR);
4589		}
4590		len++;
4591	    }
4592	    if (NXT(len) == 0) {
4593#ifdef DEBUG_STEP
4594		xmlGenericError(xmlGenericErrorContext,
4595			"PathExpr: AbbrRelLocation\n");
4596#endif
4597		/* element name */
4598		lc = 1;
4599	    }
4600	    xmlFree(name);
4601	} else {
4602	    /* make sure all cases are covered explicitely */
4603	    XP_ERROR(XPATH_EXPR_ERROR);
4604	}
4605    }
4606
4607    if (lc) {
4608	if (CUR == '/')
4609	    xmlXPathRoot(ctxt);
4610	xmlXPathEvalLocationPath(ctxt);
4611    } else {
4612	xmlXPathEvalFilterExpr(ctxt);
4613	CHECK_ERROR;
4614	if ((CUR == '/') && (NXT(1) == '/')) {
4615	    SKIP(2);
4616	    SKIP_BLANKS;
4617	    xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
4618			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
4619	    ctxt->context->node = NULL;
4620	    xmlXPathEvalRelativeLocationPath(ctxt);
4621	} else if (CUR == '/') {
4622	    xmlXPathEvalRelativeLocationPath(ctxt);
4623	}
4624    }
4625    SKIP_BLANKS;
4626}
4627
4628/**
4629 * xmlXPathEvalUnionExpr:
4630 * @ctxt:  the XPath Parser context
4631 *
4632 *  [18]   UnionExpr ::=   PathExpr
4633 *               | UnionExpr '|' PathExpr
4634 *
4635 * Parse and evaluate an union expression, then push the result on the stack
4636 */
4637
4638void
4639xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
4640    xmlXPathEvalPathExpr(ctxt);
4641    CHECK_ERROR;
4642    SKIP_BLANKS;
4643    if (CUR == '|') {
4644	xmlXPathObjectPtr obj1,obj2;
4645
4646	CHECK_TYPE(XPATH_NODESET);
4647	obj1 = valuePop(ctxt);
4648	valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4649
4650	NEXT;
4651	SKIP_BLANKS;
4652	xmlXPathEvalPathExpr(ctxt);
4653
4654	CHECK_TYPE(XPATH_NODESET);
4655	obj2 = valuePop(ctxt);
4656	obj1->nodesetval = xmlXPathNodeSetMerge(obj1->nodesetval,
4657		                                obj2->nodesetval);
4658	valuePush(ctxt, obj1);
4659	xmlXPathFreeObject(obj2);
4660	SKIP_BLANKS;
4661    }
4662}
4663
4664/**
4665 * xmlXPathEvalUnaryExpr:
4666 * @ctxt:  the XPath Parser context
4667 *
4668 *  [27]   UnaryExpr ::=   UnionExpr
4669 *                   | '-' UnaryExpr
4670 *
4671 * Parse and evaluate an unary expression, then push the result on the stack
4672 */
4673
4674void
4675xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
4676    int minus = 0;
4677
4678    SKIP_BLANKS;
4679    if (CUR == '-') {
4680        minus = 1;
4681	NEXT;
4682	SKIP_BLANKS;
4683    }
4684    xmlXPathEvalUnionExpr(ctxt);
4685    CHECK_ERROR;
4686    if (minus) {
4687        xmlXPathValueFlipSign(ctxt);
4688    }
4689}
4690
4691/**
4692 * xmlXPathEvalMultiplicativeExpr:
4693 * @ctxt:  the XPath Parser context
4694 *
4695 *  [26]   MultiplicativeExpr ::=   UnaryExpr
4696 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
4697 *                   | MultiplicativeExpr 'div' UnaryExpr
4698 *                   | MultiplicativeExpr 'mod' UnaryExpr
4699 *  [34]   MultiplyOperator ::=   '*'
4700 *
4701 * Parse and evaluate an Additive expression, then push the result on the stack
4702 */
4703
4704void
4705xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
4706    xmlXPathEvalUnaryExpr(ctxt);
4707    CHECK_ERROR;
4708    SKIP_BLANKS;
4709    while ((CUR == '*') ||
4710           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
4711           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
4712	int op = -1;
4713
4714        if (CUR == '*') {
4715	    op = 0;
4716	    NEXT;
4717	} else if (CUR == 'd') {
4718	    op = 1;
4719	    SKIP(3);
4720	} else if (CUR == 'm') {
4721	    op = 2;
4722	    SKIP(3);
4723	}
4724	SKIP_BLANKS;
4725        xmlXPathEvalUnaryExpr(ctxt);
4726	CHECK_ERROR;
4727	switch (op) {
4728	    case 0:
4729	        xmlXPathMultValues(ctxt);
4730		break;
4731	    case 1:
4732	        xmlXPathDivValues(ctxt);
4733		break;
4734	    case 2:
4735	        xmlXPathModValues(ctxt);
4736		break;
4737	}
4738	SKIP_BLANKS;
4739    }
4740}
4741
4742/**
4743 * xmlXPathEvalAdditiveExpr:
4744 * @ctxt:  the XPath Parser context
4745 *
4746 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
4747 *                   | AdditiveExpr '+' MultiplicativeExpr
4748 *                   | AdditiveExpr '-' MultiplicativeExpr
4749 *
4750 * Parse and evaluate an Additive expression, then push the result on the stack
4751 */
4752
4753void
4754xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
4755    xmlXPathEvalMultiplicativeExpr(ctxt);
4756    CHECK_ERROR;
4757    SKIP_BLANKS;
4758    while ((CUR == '+') || (CUR == '-')) {
4759	int plus;
4760
4761        if (CUR == '+') plus = 1;
4762	else plus = 0;
4763	NEXT;
4764	SKIP_BLANKS;
4765        xmlXPathEvalMultiplicativeExpr(ctxt);
4766	CHECK_ERROR;
4767	if (plus) xmlXPathAddValues(ctxt);
4768	else xmlXPathSubValues(ctxt);
4769	SKIP_BLANKS;
4770    }
4771}
4772
4773/**
4774 * xmlXPathEvalRelationalExpr:
4775 * @ctxt:  the XPath Parser context
4776 *
4777 *  [24]   RelationalExpr ::=   AdditiveExpr
4778 *                 | RelationalExpr '<' AdditiveExpr
4779 *                 | RelationalExpr '>' AdditiveExpr
4780 *                 | RelationalExpr '<=' AdditiveExpr
4781 *                 | RelationalExpr '>=' AdditiveExpr
4782 *
4783 *  A <= B > C is allowed ? Answer from James, yes with
4784 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
4785 *  which is basically what got implemented.
4786 *
4787 * Parse and evaluate a Relational expression, then push the result
4788 * on the stack
4789 */
4790
4791void
4792xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
4793    xmlXPathEvalAdditiveExpr(ctxt);
4794    CHECK_ERROR;
4795    SKIP_BLANKS;
4796    while ((CUR == '<') ||
4797           (CUR == '>') ||
4798           ((CUR == '<') && (NXT(1) == '=')) ||
4799           ((CUR == '>') && (NXT(1) == '='))) {
4800	int inf, strict, ret;
4801
4802        if (CUR == '<') inf = 1;
4803	else inf = 0;
4804	if (NXT(1) == '=') strict = 0;
4805	else strict = 1;
4806	NEXT;
4807	if (!strict) NEXT;
4808	SKIP_BLANKS;
4809        xmlXPathEvalAdditiveExpr(ctxt);
4810	CHECK_ERROR;
4811	ret = xmlXPathCompareValues(ctxt, inf, strict);
4812	valuePush(ctxt, xmlXPathNewBoolean(ret));
4813	SKIP_BLANKS;
4814    }
4815}
4816
4817/**
4818 * xmlXPathEvalEqualityExpr:
4819 * @ctxt:  the XPath Parser context
4820 *
4821 *  [23]   EqualityExpr ::=   RelationalExpr
4822 *                 | EqualityExpr '=' RelationalExpr
4823 *                 | EqualityExpr '!=' RelationalExpr
4824 *
4825 *  A != B != C is allowed ? Answer from James, yes with
4826 *  (RelationalExpr = RelationalExpr) = RelationalExpr
4827 *  (RelationalExpr != RelationalExpr) != RelationalExpr
4828 *  which is basically what got implemented.
4829 *
4830 * Parse and evaluate an Equality expression, then push the result on the stack
4831 *
4832 */
4833void
4834xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
4835    xmlXPathEvalRelationalExpr(ctxt);
4836    CHECK_ERROR;
4837    SKIP_BLANKS;
4838    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
4839	xmlXPathObjectPtr res;
4840	int eq, equal;
4841
4842        if (CUR == '=') eq = 1;
4843	else eq = 0;
4844	NEXT;
4845	if (!eq) NEXT;
4846	SKIP_BLANKS;
4847        xmlXPathEvalRelationalExpr(ctxt);
4848	CHECK_ERROR;
4849	equal = xmlXPathEqualValues(ctxt);
4850	if (eq) res = xmlXPathNewBoolean(equal);
4851	else res = xmlXPathNewBoolean(!equal);
4852	valuePush(ctxt, res);
4853	SKIP_BLANKS;
4854    }
4855}
4856
4857/**
4858 * xmlXPathEvalAndExpr:
4859 * @ctxt:  the XPath Parser context
4860 *
4861 *  [22]   AndExpr ::=   EqualityExpr
4862 *                 | AndExpr 'and' EqualityExpr
4863 *
4864 * Parse and evaluate an AND expression, then push the result on the stack
4865 *
4866 */
4867void
4868xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
4869    xmlXPathEvalEqualityExpr(ctxt);
4870    CHECK_ERROR;
4871    SKIP_BLANKS;
4872    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
4873	xmlXPathObjectPtr arg1, arg2;
4874
4875        SKIP(3);
4876	SKIP_BLANKS;
4877        xmlXPathEvalEqualityExpr(ctxt);
4878	CHECK_ERROR;
4879	arg2 = valuePop(ctxt);
4880	arg1 = valuePop(ctxt);
4881	arg1->boolval &= arg2->boolval;
4882	valuePush(ctxt, arg1);
4883	xmlXPathFreeObject(arg2);
4884	SKIP_BLANKS;
4885    }
4886}
4887
4888/**
4889 * xmlXPathEvalExpr:
4890 * @ctxt:  the XPath Parser context
4891 *
4892 *  [14]   Expr ::=   OrExpr
4893 *  [21]   OrExpr ::=   AndExpr
4894 *                 | OrExpr 'or' AndExpr
4895 *
4896 * Parse and evaluate an expression, then push the result on the stack
4897 *
4898 */
4899void
4900xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
4901    xmlXPathEvalAndExpr(ctxt);
4902    CHECK_ERROR;
4903    SKIP_BLANKS;
4904    while ((CUR == 'o') && (NXT(1) == 'r')) {
4905	xmlXPathObjectPtr arg1, arg2;
4906
4907        SKIP(2);
4908	SKIP_BLANKS;
4909        xmlXPathEvalAndExpr(ctxt);
4910	CHECK_ERROR;
4911	arg2 = valuePop(ctxt);
4912	arg1 = valuePop(ctxt);
4913	arg1->boolval |= arg2->boolval;
4914	valuePush(ctxt, arg1);
4915	xmlXPathFreeObject(arg2);
4916	SKIP_BLANKS;
4917    }
4918}
4919
4920/**
4921 * xmlXPathEvaluatePredicateResult:
4922 * @ctxt:  the XPath Parser context
4923 * @res:  the Predicate Expression evaluation result
4924 * @index:  index of the current node in the current list
4925 *
4926 * Evaluate a predicate result for the current node.
4927 * A PredicateExpr is evaluated by evaluating the Expr and converting
4928 * the result to a boolean. If the result is a number, the result will
4929 * be converted to true if the number is equal to the position of the
4930 * context node in the context node list (as returned by the position
4931 * function) and will be converted to false otherwise; if the result
4932 * is not a number, then the result will be converted as if by a call
4933 * to the boolean function.
4934 */
4935int
4936xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
4937                                xmlXPathObjectPtr res) {
4938    if (res == NULL) return(0);
4939    switch (res->type) {
4940        case XPATH_BOOLEAN:
4941	    return(res->boolval);
4942        case XPATH_NUMBER:
4943	    return(res->floatval == ctxt->context->proximityPosition);
4944        case XPATH_NODESET:
4945	    return(res->nodesetval->nodeNr != 0);
4946        case XPATH_STRING:
4947	    return((res->stringval != NULL) &&
4948	           (xmlStrlen(res->stringval) != 0));
4949        default:
4950	    STRANGE
4951    }
4952    return(0);
4953}
4954
4955/**
4956 * xmlXPathEvalPredicate:
4957 * @ctxt:  the XPath Parser context
4958 *
4959 *  [8]   Predicate ::=   '[' PredicateExpr ']'
4960 *  [9]   PredicateExpr ::=   Expr
4961 *
4962 * ---------------------
4963 * For each node in the node-set to be filtered, the PredicateExpr is
4964 * evaluated with that node as the context node, with the number of nodes
4965 * in the node-set as the context size, and with the proximity position
4966 * of the node in the node-set with respect to the axis as the context
4967 * position; if PredicateExpr evaluates to true for that node, the node
4968 * is included in the new node-set; otherwise, it is not included.
4969 * ---------------------
4970 *
4971 * Parse and evaluate a predicate for all the elements of the
4972 * current node list. Then refine the list by removing all
4973 * nodes where the predicate is false.
4974 */
4975void
4976xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
4977    const xmlChar *cur;
4978    xmlXPathObjectPtr res;
4979    xmlXPathObjectPtr obj, tmp;
4980    xmlNodeSetPtr newset = NULL;
4981    xmlNodeSetPtr oldset;
4982    int i;
4983
4984    SKIP_BLANKS;
4985    if (CUR != '[') {
4986	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
4987    }
4988    NEXT;
4989    SKIP_BLANKS;
4990
4991    /*
4992     * Extract the old set, and then evaluate the result of the
4993     * expression for all the element in the set. use it to grow
4994     * up a new set.
4995     */
4996    CHECK_TYPE(XPATH_NODESET);
4997    obj = valuePop(ctxt);
4998    oldset = obj->nodesetval;
4999    ctxt->context->node = NULL;
5000
5001    if ((oldset == NULL) || (oldset->nodeNr == 0)) {
5002	ctxt->context->contextSize = 0;
5003	ctxt->context->proximityPosition = 0;
5004	xmlXPathEvalExpr(ctxt);
5005	res = valuePop(ctxt);
5006	if (res != NULL)
5007	    xmlXPathFreeObject(res);
5008	valuePush(ctxt, obj);
5009	CHECK_ERROR;
5010    } else {
5011	/*
5012	 * Save the expression pointer since we will have to evaluate
5013	 * it multiple times. Initialize the new set.
5014	 */
5015        cur = ctxt->cur;
5016	newset = xmlXPathNodeSetCreate(NULL);
5017
5018        for (i = 0; i < oldset->nodeNr; i++) {
5019	    ctxt->cur = cur;
5020
5021	    /*
5022	     * Run the evaluation with a node list made of a single item
5023	     * in the nodeset.
5024	     */
5025	    ctxt->context->node = oldset->nodeTab[i];
5026	    tmp = xmlXPathNewNodeSet(ctxt->context->node);
5027	    valuePush(ctxt, tmp);
5028	    ctxt->context->contextSize = oldset->nodeNr;
5029	    ctxt->context->proximityPosition = i + 1;
5030
5031	    xmlXPathEvalExpr(ctxt);
5032	    CHECK_ERROR;
5033
5034	    /*
5035	     * The result of the evaluation need to be tested to
5036	     * decided whether the filter succeeded or not
5037	     */
5038	    res = valuePop(ctxt);
5039	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
5040	        xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
5041	    }
5042
5043	    /*
5044	     * Cleanup
5045	     */
5046	    if (res != NULL)
5047		xmlXPathFreeObject(res);
5048	    if (ctxt->value == tmp) {
5049		res = valuePop(ctxt);
5050		xmlXPathFreeObject(res);
5051	    }
5052
5053	    ctxt->context->node = NULL;
5054	}
5055
5056	/*
5057	 * The result is used as the new evaluation set.
5058	 */
5059	xmlXPathFreeObject(obj);
5060	ctxt->context->node = NULL;
5061	ctxt->context->contextSize = -1;
5062	ctxt->context->proximityPosition = -1;
5063	valuePush(ctxt, xmlXPathWrapNodeSet(newset));
5064    }
5065    if (CUR != ']') {
5066	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
5067    }
5068
5069    NEXT;
5070    SKIP_BLANKS;
5071#ifdef DEBUG_STEP
5072    xmlGenericError(xmlGenericErrorContext, "After predicate : ");
5073    xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
5074	    ctxt->value->nodesetval);
5075#endif
5076}
5077
5078/**
5079 * xmlXPathEvalNodeTest:
5080 * @ctxt:  the XPath Parser context
5081 * @test:  pointer to a xmlXPathTestVal
5082 * @type:  pointer to a xmlXPathTypeVal
5083 * @prefix:  placeholder for a possible name prefix
5084 *
5085 * [7] NodeTest ::=   NameTest
5086 *		    | NodeType '(' ')'
5087 *		    | 'processing-instruction' '(' Literal ')'
5088 *
5089 * [37] NameTest ::=  '*'
5090 *		    | NCName ':' '*'
5091 *		    | QName
5092 * [38] NodeType ::= 'comment'
5093 *		   | 'text'
5094 *		   | 'processing-instruction'
5095 *		   | 'node'
5096 *
5097 * Returns the name found and update @test, @type and @prefix appropriately
5098 */
5099xmlChar *
5100xmlXPathEvalNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
5101	             xmlXPathTypeVal *type, xmlChar **prefix, xmlChar *name) {
5102    int blanks;
5103
5104    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
5105	STRANGE;
5106	return(NULL);
5107    }
5108    *type = 0;
5109    *test = 0;
5110    *prefix = NULL;
5111    SKIP_BLANKS;
5112
5113    if ((name == NULL) && (CUR == '*')) {
5114	/*
5115	 * All elements
5116	 */
5117	NEXT;
5118	*test = NODE_TEST_ALL;
5119	return(NULL);
5120    }
5121
5122    if (name == NULL)
5123	name = xmlXPathParseNCName(ctxt);
5124    if (name == NULL) {
5125	XP_ERROR0(XPATH_EXPR_ERROR);
5126    }
5127
5128    blanks = IS_BLANK(CUR);
5129    SKIP_BLANKS;
5130    if (CUR == '(') {
5131	NEXT;
5132	/*
5133	 * NodeType or PI search
5134	 */
5135	if (xmlStrEqual(name, BAD_CAST "comment"))
5136	    *type = NODE_TYPE_COMMENT;
5137	else if (xmlStrEqual(name, BAD_CAST "node"))
5138	    *type = NODE_TYPE_NODE;
5139	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5140	    *type = NODE_TYPE_PI;
5141	else if (xmlStrEqual(name, BAD_CAST "text"))
5142	    *type = NODE_TYPE_TEXT;
5143	else
5144	    XP_ERROR0(XPATH_EXPR_ERROR);
5145
5146	*test = NODE_TEST_TYPE;
5147
5148	SKIP_BLANKS;
5149	if (*type == NODE_TYPE_PI) {
5150	    /*
5151	     * Specific case: search a PI by name.
5152	     */
5153	    xmlXPathObjectPtr cur;
5154
5155	    if (name != NULL)
5156		xmlFree(name);
5157
5158	    xmlXPathEvalLiteral(ctxt);
5159	    CHECK_ERROR 0;
5160	    xmlXPathStringFunction(ctxt, 1);
5161	    CHECK_ERROR0;
5162	    cur = valuePop(ctxt);
5163	    name = xmlStrdup(cur->stringval);
5164	    xmlXPathFreeObject(cur);
5165	    SKIP_BLANKS;
5166	}
5167	if (CUR != ')')
5168	    XP_ERROR0(XPATH_UNCLOSED_ERROR);
5169	NEXT;
5170	return(name);
5171    }
5172    *test = NODE_TEST_NAME;
5173    if ((!blanks) && (CUR == ':')) {
5174	NEXT;
5175
5176	*prefix = name;
5177
5178	if (CUR == '*') {
5179	    /*
5180	     * All elements
5181	     */
5182	    NEXT;
5183	    *test = NODE_TEST_ALL;
5184	    return(NULL);
5185	}
5186
5187	name = xmlXPathParseNCName(ctxt);
5188	if (name == NULL) {
5189	    XP_ERROR0(XPATH_EXPR_ERROR);
5190	}
5191    }
5192    return(name);
5193}
5194
5195/**
5196 * xmlXPathIsAxisName:
5197 * @name:  a preparsed name token
5198 *
5199 * [6] AxisName ::=   'ancestor'
5200 *                  | 'ancestor-or-self'
5201 *                  | 'attribute'
5202 *                  | 'child'
5203 *                  | 'descendant'
5204 *                  | 'descendant-or-self'
5205 *                  | 'following'
5206 *                  | 'following-sibling'
5207 *                  | 'namespace'
5208 *                  | 'parent'
5209 *                  | 'preceding'
5210 *                  | 'preceding-sibling'
5211 *                  | 'self'
5212 *
5213 * Returns the axis or 0
5214 */
5215xmlXPathAxisVal
5216xmlXPathIsAxisName(const xmlChar *name) {
5217    xmlXPathAxisVal ret = 0;
5218    switch (name[0]) {
5219	case 'a':
5220	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
5221		ret = AXIS_ANCESTOR;
5222	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
5223		ret = AXIS_ANCESTOR_OR_SELF;
5224	    if (xmlStrEqual(name, BAD_CAST "attribute"))
5225		ret = AXIS_ATTRIBUTE;
5226	    break;
5227	case 'c':
5228	    if (xmlStrEqual(name, BAD_CAST "child"))
5229		ret = AXIS_CHILD;
5230	    break;
5231	case 'd':
5232	    if (xmlStrEqual(name, BAD_CAST "descendant"))
5233		ret = AXIS_DESCENDANT;
5234	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
5235		ret = AXIS_DESCENDANT_OR_SELF;
5236	    break;
5237	case 'f':
5238	    if (xmlStrEqual(name, BAD_CAST "following"))
5239		ret = AXIS_FOLLOWING;
5240	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
5241		ret = AXIS_FOLLOWING_SIBLING;
5242	    break;
5243	case 'n':
5244	    if (xmlStrEqual(name, BAD_CAST "namespace"))
5245		ret = AXIS_NAMESPACE;
5246	    break;
5247	case 'p':
5248	    if (xmlStrEqual(name, BAD_CAST "parent"))
5249		ret = AXIS_PARENT;
5250	    if (xmlStrEqual(name, BAD_CAST "preceding"))
5251		ret = AXIS_PRECEDING;
5252	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
5253		ret = AXIS_PRECEDING_SIBLING;
5254	    break;
5255	case 's':
5256	    if (xmlStrEqual(name, BAD_CAST "self"))
5257		ret = AXIS_SELF;
5258	    break;
5259    }
5260    return(ret);
5261}
5262
5263/**
5264 * xmlXPathEvalAxisSpecifier:
5265 * @ctxt:  the XPath Parser context
5266 *
5267 *
5268 * Returns the axis found
5269 */
5270xmlXPathAxisVal
5271xmlXPathEvalAxisSpecifier(xmlXPathParserContextPtr ctxt) {
5272    xmlXPathAxisVal ret = AXIS_CHILD;
5273    int blank = 0;
5274    xmlChar *name;
5275
5276    if (CUR == '@') {
5277	NEXT;
5278	return(AXIS_ATTRIBUTE);
5279    } else {
5280	name = xmlXPathParseNCName(ctxt);
5281	if (name == NULL) {
5282	    XP_ERROR0(XPATH_EXPR_ERROR);
5283	}
5284	if (IS_BLANK(CUR))
5285	    blank = 1;
5286	SKIP_BLANKS;
5287	if ((CUR == ':') && (NXT(1) == ':')) {
5288	    ret = xmlXPathIsAxisName(name);
5289	} else if ((blank) && (CUR == ':'))
5290	    XP_ERROR0(XPATH_EXPR_ERROR);
5291
5292	xmlFree(name);
5293    }
5294    return(ret);
5295}
5296
5297/**
5298 * xmlXPathEvalStep:
5299 * @ctxt:  the XPath Parser context
5300 *
5301 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
5302 *                  | AbbreviatedStep
5303 *
5304 * [12] AbbreviatedStep ::=   '.' | '..'
5305 *
5306 * [5] AxisSpecifier ::= AxisName '::'
5307 *                  | AbbreviatedAxisSpecifier
5308 *
5309 * [13] AbbreviatedAxisSpecifier ::= '@'?
5310 *
5311 * Modified for XPtr range support as:
5312 *
5313 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
5314 *                     | AbbreviatedStep
5315 *                     | 'range-to' '(' Expr ')' Predicate*
5316 *
5317 * Evaluate one step in a Location Path
5318 * A location step of . is short for self::node(). This is
5319 * particularly useful in conjunction with //. For example, the
5320 * location path .//para is short for
5321 * self::node()/descendant-or-self::node()/child::para
5322 * and so will select all para descendant elements of the context
5323 * node.
5324 * Similarly, a location step of .. is short for parent::node().
5325 * For example, ../title is short for parent::node()/child::title
5326 * and so will select the title children of the parent of the context
5327 * node.
5328 */
5329void
5330xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
5331    SKIP_BLANKS;
5332    if ((CUR == '.') && (NXT(1) == '.')) {
5333	SKIP(2);
5334	SKIP_BLANKS;
5335	xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
5336			 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
5337    } else if (CUR == '.') {
5338	NEXT;
5339	SKIP_BLANKS;
5340    } else {
5341	xmlChar *name = NULL;
5342	xmlChar *prefix = NULL;
5343	xmlXPathTestVal test;
5344	xmlXPathAxisVal axis;
5345	xmlXPathTypeVal type;
5346
5347	/*
5348	 * The modification needed for XPointer change to the production
5349	 */
5350#ifdef LIBXML_XPTR_ENABLED
5351	if (ctxt->context->xptr) {
5352	    name = xmlXPathParseNCName(ctxt);
5353	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
5354		xmlFree(name);
5355		SKIP_BLANKS;
5356		if (CUR != '(') {
5357		    XP_ERROR(XPATH_EXPR_ERROR);
5358		}
5359		NEXT;
5360		SKIP_BLANKS;
5361
5362		xmlXPtrRangeToFunction(ctxt, 1);
5363		CHECK_ERROR;
5364
5365		SKIP_BLANKS;
5366		if (CUR != ')') {
5367		    XP_ERROR(XPATH_EXPR_ERROR);
5368		}
5369		NEXT;
5370		goto eval_predicates;
5371	    }
5372	}
5373#endif
5374	if (name == NULL)
5375	    name = xmlXPathParseNCName(ctxt);
5376	if (name != NULL) {
5377	    axis = xmlXPathIsAxisName(name);
5378	    if (axis != 0) {
5379		SKIP_BLANKS;
5380		if ((CUR == ':') && (NXT(1) == ':')) {
5381		    SKIP(2);
5382		    xmlFree(name);
5383		    name = NULL;
5384		} else {
5385		    /* an element name can conflict with an axis one :-\ */
5386		    axis = AXIS_CHILD;
5387		}
5388	    } else {
5389	        axis = AXIS_CHILD;
5390	    }
5391	} else if (CUR == '@') {
5392	    NEXT;
5393	    axis = AXIS_ATTRIBUTE;
5394	} else {
5395	    axis = AXIS_CHILD;
5396	}
5397
5398	CHECK_ERROR;
5399
5400	name = xmlXPathEvalNodeTest(ctxt, &test, &type, &prefix, name);
5401	if (test == 0)
5402	    return;
5403
5404#ifdef DEBUG_STEP
5405	xmlGenericError(xmlGenericErrorContext,
5406		"Basis : computing new set\n");
5407#endif
5408	xmlXPathNodeCollectAndTest(ctxt, axis, test, type, prefix, name);
5409#ifdef DEBUG_STEP
5410	xmlGenericError(xmlGenericErrorContext, "Basis : ");
5411	xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
5412#endif
5413	if (name != NULL)
5414	    xmlFree(name);
5415	if (prefix != NULL)
5416	    xmlFree(prefix);
5417
5418eval_predicates:
5419	SKIP_BLANKS;
5420	while (CUR == '[') {
5421	    xmlXPathEvalPredicate(ctxt);
5422	}
5423    }
5424#ifdef DEBUG_STEP
5425    xmlGenericError(xmlGenericErrorContext, "Step : ");
5426    xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
5427	    ctxt->value->nodesetval);
5428#endif
5429}
5430
5431/**
5432 * xmlXPathEvalRelativeLocationPath:
5433 * @ctxt:  the XPath Parser context
5434 *
5435 *  [3]   RelativeLocationPath ::=   Step
5436 *                     | RelativeLocationPath '/' Step
5437 *                     | AbbreviatedRelativeLocationPath
5438 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
5439 *
5440 */
5441void
5442xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
5443    SKIP_BLANKS;
5444    if ((CUR == '/') && (NXT(1) == '/')) {
5445	SKIP(2);
5446	SKIP_BLANKS;
5447	xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
5448			 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
5449    } else if (CUR == '/') {
5450	    NEXT;
5451	SKIP_BLANKS;
5452    }
5453    xmlXPathEvalStep(ctxt);
5454    SKIP_BLANKS;
5455    while (CUR == '/') {
5456	if ((CUR == '/') && (NXT(1) == '/')) {
5457	    SKIP(2);
5458	    SKIP_BLANKS;
5459	    xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
5460			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
5461	    xmlXPathEvalStep(ctxt);
5462	} else if (CUR == '/') {
5463	    NEXT;
5464	    SKIP_BLANKS;
5465	    xmlXPathEvalStep(ctxt);
5466	}
5467	SKIP_BLANKS;
5468    }
5469}
5470
5471/**
5472 * xmlXPathEvalLocationPath:
5473 * @ctxt:  the XPath Parser context
5474 *
5475 *  [1]   LocationPath ::=   RelativeLocationPath
5476 *                     | AbsoluteLocationPath
5477 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
5478 *                     | AbbreviatedAbsoluteLocationPath
5479 *  [10]   AbbreviatedAbsoluteLocationPath ::=
5480 *                           '//' RelativeLocationPath
5481 *
5482 * // is short for /descendant-or-self::node()/. For example,
5483 * //para is short for /descendant-or-self::node()/child::para and
5484 * so will select any para element in the document (even a para element
5485 * that is a document element will be selected by //para since the
5486 * document element node is a child of the root node); div//para is
5487 * short for div/descendant-or-self::node()/child::para and so will
5488 * select all para descendants of div children.
5489 */
5490void
5491xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
5492    SKIP_BLANKS;
5493    if (CUR != '/') {
5494        xmlXPathEvalRelativeLocationPath(ctxt);
5495    } else {
5496	while (CUR == '/') {
5497	    if ((CUR == '/') && (NXT(1) == '/')) {
5498		SKIP(2);
5499		SKIP_BLANKS;
5500		xmlXPathNodeCollectAndTest(ctxt,
5501		                 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
5502				 NODE_TYPE_NODE, NULL, NULL);
5503		xmlXPathEvalRelativeLocationPath(ctxt);
5504	    } else if (CUR == '/') {
5505		NEXT;
5506		SKIP_BLANKS;
5507		if (CUR != 0)
5508		    xmlXPathEvalRelativeLocationPath(ctxt);
5509	    }
5510	}
5511    }
5512}
5513
5514/**
5515 * xmlXPathEval:
5516 * @str:  the XPath expression
5517 * @ctx:  the XPath context
5518 *
5519 * Evaluate the XPath Location Path in the given context.
5520 *
5521 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
5522 *         the caller has to free the object.
5523 */
5524xmlXPathObjectPtr
5525xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
5526    xmlXPathParserContextPtr ctxt;
5527    xmlXPathObjectPtr res = NULL, tmp, init = NULL;
5528    int stack = 0;
5529
5530    xmlXPathInit();
5531
5532    CHECK_CONTEXT(ctx)
5533
5534    ctxt = xmlXPathNewParserContext(str, ctx);
5535    if (ctx->node != NULL) {
5536	init = xmlXPathNewNodeSet(ctx->node);
5537	valuePush(ctxt, init);
5538    }
5539    xmlXPathEvalExpr(ctxt);
5540
5541    if (ctxt->value == NULL) {
5542	xmlGenericError(xmlGenericErrorContext,
5543		"xmlXPathEval: evaluation failed\n");
5544    } else {
5545	res = valuePop(ctxt);
5546    }
5547
5548    do {
5549        tmp = valuePop(ctxt);
5550	if (tmp != NULL) {
5551	    if (tmp != init)
5552		stack++;
5553	    xmlXPathFreeObject(tmp);
5554        }
5555    } while (tmp != NULL);
5556    if (stack != 0) {
5557	xmlGenericError(xmlGenericErrorContext,
5558		"xmlXPathEval: %d object left on the stack\n",
5559	        stack);
5560    }
5561    if (ctxt->error != XPATH_EXPRESSION_OK) {
5562	xmlXPathFreeObject(res);
5563	res = NULL;
5564    }
5565
5566    xmlXPathFreeParserContext(ctxt);
5567    return(res);
5568}
5569
5570/**
5571 * xmlXPathEvalExpression:
5572 * @str:  the XPath expression
5573 * @ctxt:  the XPath context
5574 *
5575 * Evaluate the XPath expression in the given context.
5576 *
5577 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
5578 *         the caller has to free the object.
5579 */
5580xmlXPathObjectPtr
5581xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
5582    xmlXPathParserContextPtr pctxt;
5583    xmlXPathObjectPtr res, tmp;
5584    int stack = 0;
5585
5586    xmlXPathInit();
5587
5588    CHECK_CONTEXT(ctxt)
5589
5590    pctxt = xmlXPathNewParserContext(str, ctxt);
5591    xmlXPathEvalExpr(pctxt);
5592
5593    res = valuePop(pctxt);
5594    do {
5595        tmp = valuePop(pctxt);
5596	if (tmp != NULL) {
5597	    xmlXPathFreeObject(tmp);
5598	    stack++;
5599	}
5600    } while (tmp != NULL);
5601    if (stack != 0) {
5602	xmlGenericError(xmlGenericErrorContext,
5603		"xmlXPathEvalExpression: %d object left on the stack\n",
5604	        stack);
5605    }
5606    xmlXPathFreeParserContext(pctxt);
5607    return(res);
5608}
5609
5610void
5611xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
5612{
5613    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
5614                         xmlXPathBooleanFunction);
5615    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
5616                         xmlXPathCeilingFunction);
5617    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
5618                         xmlXPathCountFunction);
5619    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
5620                         xmlXPathConcatFunction);
5621    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
5622                         xmlXPathContainsFunction);
5623    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
5624                         xmlXPathIdFunction);
5625    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
5626                         xmlXPathFalseFunction);
5627    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
5628                         xmlXPathFloorFunction);
5629    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
5630                         xmlXPathLastFunction);
5631    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
5632                         xmlXPathLangFunction);
5633    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
5634                         xmlXPathLocalNameFunction);
5635    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
5636                         xmlXPathNotFunction);
5637    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
5638                         xmlXPathNameFunction);
5639    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
5640                         xmlXPathNamespaceURIFunction);
5641    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
5642                         xmlXPathNormalizeFunction);
5643    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
5644                         xmlXPathNumberFunction);
5645    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
5646                         xmlXPathPositionFunction);
5647    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
5648                         xmlXPathRoundFunction);
5649    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
5650                         xmlXPathStringFunction);
5651    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
5652                         xmlXPathStringLengthFunction);
5653    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
5654                         xmlXPathStartsWithFunction);
5655    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
5656                         xmlXPathSubstringFunction);
5657    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
5658                         xmlXPathSubstringBeforeFunction);
5659    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
5660                         xmlXPathSubstringAfterFunction);
5661    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
5662                         xmlXPathSumFunction);
5663    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
5664                         xmlXPathTrueFunction);
5665    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
5666                         xmlXPathTranslateFunction);
5667}
5668
5669#endif /* LIBXML_XPATH_ENABLED */
5670