xpath.c revision e3d88efb8d24028a9893e12ae20633c8ee32fa49
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 Working Draft internal 5 July 1999
7 *     http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html
8 * Public reference:
9 *     http://www.w3.org/TR/WD-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 <stdio.h>
23#include <string.h>
24
25#ifdef HAVE_SYS_TYPES_H
26#include <sys/types.h>
27#endif
28#ifdef HAVE_MATH_H
29#include <math.h>
30#endif
31#ifdef HAVE_MATH_H
32#include <float.h>
33#endif
34#ifdef HAVE_IEEEFP_H
35#include <ieeefp.h>
36#endif
37#ifdef HAVE_NAN_H
38#include <nan.h>
39#endif
40#ifdef HAVE_CTYPE_H
41#include <ctype.h>
42#endif
43
44#include "xmlmemory.h"
45#include "tree.h"
46#include "valid.h"
47#include "xpath.h"
48#include "parserInternals.h"
49
50/* #define DEBUG */
51/* #define DEBUG_STEP */
52/* #define DEBUG_EXPR */
53
54/*
55 * Setup stuff for floating point
56 * The lack of portability of this section of the libc is annoying !
57 */
58double xmlXPathNAN = 0;
59double xmlXPathPINF = 1;
60double xmlXPathMINF = -1;
61
62#ifndef isinf
63#ifndef HAVE_ISINF
64
65#if HAVE_FPCLASS
66
67int isinf(double d) {
68    fpclass_t	type = fpclass(d);
69    switch (type) {
70	case FP_NINF:
71	    return(-1);
72	case FP_PINF:
73	    return(1);
74	default:
75	    return(0);
76    }
77    return(0);
78}
79
80#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
81
82#if HAVE_FP_CLASS_H
83#include <fp_class.h>
84#endif
85
86int isinf(double d) {
87#if HAVE_FP_CLASS
88    int	fpclass = fp_class(d);
89#else
90    int	fpclass = fp_class_d(d);
91#endif
92    if (fpclass == FP_POS_INF)
93	return(1);
94    if (fpclass == FP_NEG_INF)
95	return(-1);
96    return(0);
97}
98
99#elif defined(HAVE_CLASS)
100
101int isinf(double d) {
102    int	fpclass = class(d);
103    if (fpclass == FP_PLUS_INF)
104	return(1);
105    if (fpclass == FP_MINUS_INF)
106	return(-1);
107    return(0);
108}
109#elif defined(finite) || defined(HAVE_FINITE)
110int isinf(double x) { return !finite(x) && x==x; }
111#elif defined(HUGE_VAL)
112static int isinf(double x)
113{
114    if (x == HUGE_VAL)
115        return(1);
116    if (x == -HUGE_VAL)
117        return(-1);
118    return(0);
119}
120#endif
121
122#endif /* ! HAVE_ISINF */
123#endif /* ! defined(isinf) */
124
125#ifndef isnan
126#ifndef HAVE_ISNAN
127
128#ifdef HAVE_ISNAND
129#define isnan(f) isnand(f)
130#endif /* HAVE_iSNAND */
131
132#endif /* ! HAVE_iSNAN */
133#endif /* ! defined(isnan) */
134
135/**
136 * xmlXPathInit:
137 *
138 * Initialize the XPath environment
139 */
140void
141xmlXPathInit(void) {
142    static int initialized = 0;
143
144    if (initialized) return;
145
146    xmlXPathNAN = 0;
147    xmlXPathNAN /= 0;
148
149    xmlXPathPINF = 1;
150    xmlXPathPINF /= 0;
151
152    xmlXPathMINF = -1;
153    xmlXPathMINF /= 0;
154
155    initialized = 1;
156}
157
158FILE *xmlXPathDebug = NULL;
159
160#define TODO 								\
161    fprintf(xmlXPathDebug, "Unimplemented block at %s:%d\n",		\
162            __FILE__, __LINE__);
163
164#define STRANGE 							\
165    fprintf(xmlXPathDebug, "Internal error at %s:%d\n",			\
166            __FILE__, __LINE__);
167
168double xmlXPathStringEvalNumber(const xmlChar *str);
169void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
170
171/************************************************************************
172 *									*
173 * 		Parser stacks related functions and macros		*
174 *									*
175 ************************************************************************/
176
177/*
178 * Generic function for accessing stacks in the Parser Context
179 */
180
181#define PUSH_AND_POP(type, name)					\
182extern int name##Push(xmlXPathParserContextPtr ctxt, type value) {	\
183    if (ctxt->name##Nr >= ctxt->name##Max) {				\
184	ctxt->name##Max *= 2;						\
185        ctxt->name##Tab = (void *) xmlRealloc(ctxt->name##Tab,		\
186	             ctxt->name##Max * sizeof(ctxt->name##Tab[0]));	\
187        if (ctxt->name##Tab == NULL) {					\
188	    fprintf(xmlXPathDebug, "realloc failed !\n");		\
189	    return(0);							\
190	}								\
191    }									\
192    ctxt->name##Tab[ctxt->name##Nr] = value;				\
193    ctxt->name = value;							\
194    return(ctxt->name##Nr++);						\
195}									\
196extern type name##Pop(xmlXPathParserContextPtr ctxt) {			\
197    type ret;								\
198    if (ctxt->name##Nr <= 0) return(0);					\
199    ctxt->name##Nr--;							\
200    if (ctxt->name##Nr > 0)						\
201	ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1];		\
202    else								\
203        ctxt->name = NULL;						\
204    ret = ctxt->name##Tab[ctxt->name##Nr];				\
205    ctxt->name##Tab[ctxt->name##Nr] = 0;				\
206    return(ret);							\
207}									\
208
209PUSH_AND_POP(xmlXPathObjectPtr, value)
210
211/*
212 * Macros for accessing the content. Those should be used only by the parser,
213 * and not exported.
214 *
215 * Dirty macros, i.e. one need to make assumption on the context to use them
216 *
217 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
218 *   CUR     returns the current xmlChar value, i.e. a 8 bit value if compiled
219 *           in ISO-Latin or UTF-8, and the current 16 bit value if compiled
220 *           in UNICODE mode. This should be used internally by the parser
221 *           only to compare to ASCII values otherwise it would break when
222 *           running with UTF-8 encoding.
223 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
224 *           to compare on ASCII based substring.
225 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
226 *           strings within the parser.
227 *   CURRENT Returns the current char value, with the full decoding of
228 *           UTF-8 if we are using this mode. It returns an int.
229 *   NEXT    Skip to the next character, this does the proper decoding
230 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
231 *           It returns the pointer to the current xmlChar.
232 */
233
234#define CUR (*ctxt->cur)
235#define SKIP(val) ctxt->cur += (val)
236#define NXT(val) ctxt->cur[(val)]
237#define CUR_PTR ctxt->cur
238
239#define SKIP_BLANKS 							\
240    while (IS_BLANK(*(ctxt->cur))) NEXT
241
242#ifndef USE_UTF_8
243#define CURRENT (*ctxt->cur)
244#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
245#else
246#endif
247
248/************************************************************************
249 *									*
250 *			Error handling routines				*
251 *									*
252 ************************************************************************/
253
254#define XPATH_EXPRESSION_OK		0
255#define XPATH_NUMBER_ERROR		1
256#define XPATH_UNFINISHED_LITERAL_ERROR	2
257#define XPATH_START_LITERAL_ERROR	3
258#define XPATH_VARIABLE_REF_ERROR	4
259#define XPATH_UNDEF_VARIABLE_ERROR	5
260#define XPATH_INVALID_PREDICATE_ERROR	6
261#define XPATH_EXPR_ERROR		7
262#define XPATH_UNCLOSED_ERROR		8
263#define XPATH_UNKNOWN_FUNC_ERROR	9
264#define XPATH_INVALID_OPERAND		10
265#define XPATH_INVALID_TYPE		11
266#define XPATH_INVALID_ARITY		12
267
268const char *xmlXPathErrorMessages[] = {
269    "Ok",
270    "Number encoding",
271    "Unfinished litteral",
272    "Start of litteral",
273    "Expected $ for variable reference",
274    "Undefined variable",
275    "Invalid predicate",
276    "Invalid expression",
277    "Missing closing curly brace",
278    "Unregistered function",
279    "Invalid operand",
280    "Invalid type",
281    "Invalid number of arguments",
282};
283
284/**
285 * xmlXPathError:
286 * @ctxt:  the XPath Parser context
287 * @file:  the file name
288 * @line:  the line number
289 * @no:  the error number
290 *
291 * Create a new xmlNodeSetPtr of type double and of value @val
292 *
293 * Returns the newly created object.
294 */
295void
296xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
297              int line, int no) {
298    int n;
299    const xmlChar *cur;
300    const xmlChar *base;
301
302    fprintf(xmlXPathDebug, "Error %s:%d: %s\n", file, line,
303            xmlXPathErrorMessages[no]);
304
305    cur = ctxt->cur;
306    base = ctxt->base;
307    while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
308	cur--;
309    }
310    n = 0;
311    while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
312        cur--;
313    if ((*cur == '\n') || (*cur == '\r')) cur++;
314    base = cur;
315    n = 0;
316    while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
317        fprintf(xmlXPathDebug, "%c", (unsigned char) *cur++);
318	n++;
319    }
320    fprintf(xmlXPathDebug, "\n");
321    cur = ctxt->cur;
322    while ((*cur == '\n') || (*cur == '\r'))
323	cur--;
324    n = 0;
325    while ((cur != base) && (n++ < 80)) {
326        fprintf(xmlXPathDebug, " ");
327        base++;
328    }
329    fprintf(xmlXPathDebug,"^\n");
330}
331
332#define CHECK_ERROR							\
333    if (ctxt->error != XPATH_EXPRESSION_OK) return
334
335#define ERROR(X)							\
336    { xmlXPatherror(ctxt, __FILE__, __LINE__, X);			\
337      ctxt->error = (X); return; }
338
339#define ERROR0(X)							\
340    { xmlXPatherror(ctxt, __FILE__, __LINE__, X);			\
341      ctxt->error = (X); return(0); }
342
343#define CHECK_TYPE(typeval)						\
344    if ((ctxt->value == NULL) || (ctxt->value->type != typeval))	\
345        ERROR(XPATH_INVALID_TYPE)					\
346
347
348/************************************************************************
349 *									*
350 *			Routines to handle NodeSets			*
351 *									*
352 ************************************************************************/
353
354#define XML_NODESET_DEFAULT	10
355/**
356 * xmlXPathNodeSetCreate:
357 * @val:  an initial xmlNodePtr, or NULL
358 *
359 * Create a new xmlNodeSetPtr of type double and of value @val
360 *
361 * Returns the newly created object.
362 */
363xmlNodeSetPtr
364xmlXPathNodeSetCreate(xmlNodePtr val) {
365    xmlNodeSetPtr ret;
366
367    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
368    if (ret == NULL) {
369        fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
370	return(NULL);
371    }
372    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
373    if (val != NULL) {
374        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
375					     sizeof(xmlNodePtr));
376	if (ret->nodeTab == NULL) {
377	    fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
378	    return(NULL);
379	}
380	memset(ret->nodeTab, 0 ,
381	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
382        ret->nodeMax = XML_NODESET_DEFAULT;
383	ret->nodeTab[ret->nodeNr++] = val;
384    }
385    return(ret);
386}
387
388/**
389 * xmlXPathNodeSetAdd:
390 * @cur:  the initial node set
391 * @val:  a new xmlNodePtr
392 *
393 * add a new xmlNodePtr ot an existing NodeSet
394 */
395void
396xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
397    int i;
398
399    if (val == NULL) return;
400
401    /*
402     * check against doublons
403     */
404    for (i = 0;i < cur->nodeNr;i++)
405        if (cur->nodeTab[i] == val) return;
406
407    /*
408     * grow the nodeTab if needed
409     */
410    if (cur->nodeMax == 0) {
411        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
412					     sizeof(xmlNodePtr));
413	if (cur->nodeTab == NULL) {
414	    fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
415	    return;
416	}
417	memset(cur->nodeTab, 0 ,
418	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
419        cur->nodeMax = XML_NODESET_DEFAULT;
420    } else if (cur->nodeNr == cur->nodeMax) {
421        xmlNodePtr *temp;
422
423        cur->nodeMax *= 2;
424	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
425				      sizeof(xmlNodePtr));
426	if (temp == NULL) {
427	    fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
428	    return;
429	}
430	cur->nodeTab = temp;
431    }
432    cur->nodeTab[cur->nodeNr++] = val;
433}
434
435/**
436 * xmlXPathNodeSetMerge:
437 * @val1:  the first NodeSet
438 * @val2:  the second NodeSet
439 *
440 * Merges two nodesets, all nodes from @val2 are added to @val1
441 *
442 * Returns val1 once extended or NULL in case of error.
443 */
444xmlNodeSetPtr
445xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
446    int i;
447
448    if (val1 == NULL) return(NULL);
449    if (val2 == NULL) return(val1);
450
451    /*
452     * !!!!! this can be optimized a lot, knowing that both
453     *       val1 and val2 already have unicity of their values.
454     */
455
456    for (i = 0;i < val2->nodeNr;i++)
457        xmlXPathNodeSetAdd(val1, val2->nodeTab[i]);
458
459    return(val1);
460}
461
462/**
463 * xmlXPathNodeSetDel:
464 * @cur:  the initial node set
465 * @val:  an xmlNodePtr
466 *
467 * Removes an xmlNodePtr from an existing NodeSet
468 */
469void
470xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
471    int i;
472
473    if (cur == NULL) return;
474    if (val == NULL) return;
475
476    /*
477     * check against doublons
478     */
479    for (i = 0;i < cur->nodeNr;i++)
480        if (cur->nodeTab[i] == val) break;
481
482    if (i >= cur->nodeNr) {
483#ifdef DEBUG
484        fprintf(xmlXPathDebug,
485	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
486		val->name);
487#endif
488        return;
489    }
490    cur->nodeNr--;
491    for (;i < cur->nodeNr;i++)
492        cur->nodeTab[i] = cur->nodeTab[i + 1];
493    cur->nodeTab[cur->nodeNr] = NULL;
494}
495
496/**
497 * xmlXPathNodeSetRemove:
498 * @cur:  the initial node set
499 * @val:  the index to remove
500 *
501 * Removes an entry from an existing NodeSet list.
502 */
503void
504xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
505    if (cur == NULL) return;
506    if (val >= cur->nodeNr) return;
507    cur->nodeNr--;
508    for (;val < cur->nodeNr;val++)
509        cur->nodeTab[val] = cur->nodeTab[val + 1];
510    cur->nodeTab[cur->nodeNr] = NULL;
511}
512
513/**
514 * xmlXPathFreeNodeSet:
515 * @obj:  the xmlNodeSetPtr to free
516 *
517 * Free the NodeSet compound (not the actual nodes !).
518 */
519void
520xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
521    if (obj == NULL) return;
522    if (obj->nodeTab != NULL) {
523#ifdef DEBUG
524	memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
525#endif
526	xmlFree(obj->nodeTab);
527    }
528#ifdef DEBUG
529    memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
530#endif
531    xmlFree(obj);
532}
533
534#if defined(DEBUG) || defined(DEBUG_STEP)
535/**
536 * xmlXPathDebugNodeSet:
537 * @output:  a FILE * for the output
538 * @obj:  the xmlNodeSetPtr to free
539 *
540 * Quick display of a NodeSet
541 */
542void
543xmlXPathDebugNodeSet(FILE *output, xmlNodeSetPtr obj) {
544    int i;
545
546    if (output == NULL) output = xmlXPathDebug;
547    if (obj == NULL)  {
548        fprintf(output, "NodeSet == NULL !\n");
549	return;
550    }
551    if (obj->nodeNr == 0) {
552        fprintf(output, "NodeSet is empty\n");
553	return;
554    }
555    if (obj->nodeTab == NULL) {
556	fprintf(output, " nodeTab == NULL !\n");
557	return;
558    }
559    for (i = 0; i < obj->nodeNr; i++) {
560        if (obj->nodeTab[i] == NULL) {
561	    fprintf(output, " NULL !\n");
562	    return;
563        }
564	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
565	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
566	    fprintf(output, " /");
567	else if (obj->nodeTab[i]->name == NULL)
568	    fprintf(output, " noname!");
569	else fprintf(output, " %s", obj->nodeTab[i]->name);
570    }
571    fprintf(output, "\n");
572}
573#endif
574
575/************************************************************************
576 *									*
577 *			Routines to handle Variable			*
578 *									*
579 *			UNIMPLEMENTED CURRENTLY				*
580 *									*
581 ************************************************************************/
582
583/**
584 * xmlXPathVariablelookup:
585 * @ctxt:  the XPath Parser context
586 * @prefix:  the variable name namespace if any
587 * @name:  the variable name
588 *
589 * Search in the Variable array of the context for the given
590 * variable value.
591 *
592 * UNIMPLEMENTED: always return NULL.
593 *
594 * Returns the value or NULL if not found
595 */
596xmlXPathObjectPtr
597xmlXPathVariablelookup(xmlXPathParserContextPtr ctxt,
598                       const xmlChar *prefix, const xmlChar *name) {
599    return(NULL);
600}
601
602/************************************************************************
603 *									*
604 *			Routines to handle Values			*
605 *									*
606 ************************************************************************/
607
608/* Allocations are terrible, one need to optimize all this !!! */
609
610/**
611 * xmlXPathNewFloat:
612 * @val:  the double value
613 *
614 * Create a new xmlXPathObjectPtr of type double and of value @val
615 *
616 * Returns the newly created object.
617 */
618xmlXPathObjectPtr
619xmlXPathNewFloat(double val) {
620    xmlXPathObjectPtr ret;
621
622    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
623    if (ret == NULL) {
624        fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
625	return(NULL);
626    }
627    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
628    ret->type = XPATH_NUMBER;
629    ret->floatval = val;
630    return(ret);
631}
632
633/**
634 * xmlXPathNewBoolean:
635 * @val:  the boolean value
636 *
637 * Create a new xmlXPathObjectPtr of type boolean and of value @val
638 *
639 * Returns the newly created object.
640 */
641xmlXPathObjectPtr
642xmlXPathNewBoolean(int val) {
643    xmlXPathObjectPtr ret;
644
645    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
646    if (ret == NULL) {
647        fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
648	return(NULL);
649    }
650    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
651    ret->type = XPATH_BOOLEAN;
652    ret->boolval = (val != 0);
653    return(ret);
654}
655
656/**
657 * xmlXPathNewString:
658 * @val:  the xmlChar * value
659 *
660 * Create a new xmlXPathObjectPtr of type string and of value @val
661 *
662 * Returns the newly created object.
663 */
664xmlXPathObjectPtr
665xmlXPathNewString(const xmlChar *val) {
666    xmlXPathObjectPtr ret;
667
668    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
669    if (ret == NULL) {
670        fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
671	return(NULL);
672    }
673    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
674    ret->type = XPATH_STRING;
675    ret->stringval = xmlStrdup(val);
676    return(ret);
677}
678
679/**
680 * xmlXPathNewCString:
681 * @val:  the char * value
682 *
683 * Create a new xmlXPathObjectPtr of type string and of value @val
684 *
685 * Returns the newly created object.
686 */
687xmlXPathObjectPtr
688xmlXPathNewCString(const char *val) {
689    xmlXPathObjectPtr ret;
690
691    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
692    if (ret == NULL) {
693        fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
694	return(NULL);
695    }
696    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
697    ret->type = XPATH_STRING;
698    ret->stringval = xmlStrdup(BAD_CAST val);
699    return(ret);
700}
701
702/**
703 * xmlXPathNewNodeSet:
704 * @val:  the NodePtr value
705 *
706 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
707 * it with the single Node @val
708 *
709 * Returns the newly created object.
710 */
711xmlXPathObjectPtr
712xmlXPathNewNodeSet(xmlNodePtr val) {
713    xmlXPathObjectPtr ret;
714
715    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
716    if (ret == NULL) {
717        fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
718	return(NULL);
719    }
720    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
721    ret->type = XPATH_NODESET;
722    ret->nodesetval = xmlXPathNodeSetCreate(val);
723    return(ret);
724}
725
726/**
727 * xmlXPathNewNodeSetList:
728 * @val:  an existing NodeSet
729 *
730 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
731 * it with the Nodeset @val
732 *
733 * Returns the newly created object.
734 */
735xmlXPathObjectPtr
736xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
737    xmlXPathObjectPtr ret;
738
739    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
740    if (ret == NULL) {
741        fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
742	return(NULL);
743    }
744    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
745    ret->type = XPATH_NODESET;
746    ret->nodesetval = val;
747    return(ret);
748}
749
750/**
751 * xmlXPathFreeNodeSetList:
752 * @obj:  an existing NodeSetList object
753 *
754 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
755 * the list contrary to xmlXPathFreeObject().
756 */
757void
758xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
759    if (obj == NULL) return;
760#ifdef DEBUG
761    memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
762#endif
763    xmlFree(obj);
764}
765
766/**
767 * xmlXPathFreeObject:
768 * @obj:  the object to free
769 *
770 * Free up an xmlXPathObjectPtr object.
771 */
772void
773xmlXPathFreeObject(xmlXPathObjectPtr obj) {
774    if (obj == NULL) return;
775    if (obj->nodesetval != NULL)
776        xmlXPathFreeNodeSet(obj->nodesetval);
777    if (obj->stringval != NULL)
778        xmlFree(obj->stringval);
779#ifdef DEBUG
780    memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
781#endif
782    xmlFree(obj);
783}
784
785/************************************************************************
786 *									*
787 *		Routines to handle XPath contexts			*
788 *									*
789 ************************************************************************/
790
791/**
792 * xmlXPathNewContext:
793 * @doc:  the XML document
794 *
795 * Create a new xmlXPathContext
796 *
797 * Returns the xmlXPathContext just allocated.
798 */
799xmlXPathContextPtr
800xmlXPathNewContext(xmlDocPtr doc) {
801    xmlXPathContextPtr ret;
802
803    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
804    if (ret == NULL) {
805        fprintf(xmlXPathDebug, "xmlXPathNewContext: out of memory\n");
806	return(NULL);
807    }
808    memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
809    ret->doc = doc;
810 /***********
811    ret->node = (xmlNodePtr) doc;
812    ret->nodelist = xmlXPathNodeSetCreate(ret->node);
813  ***********/
814    ret->node = NULL;
815    ret->nodelist = NULL;
816
817    ret->nb_variables = 0;
818    ret->max_variables = 0;
819    ret->variables = NULL;
820
821    ret->nb_types = 0;
822    ret->max_types = 0;
823    ret->types = NULL;
824
825    ret->nb_funcs = 0;
826    ret->max_funcs = 0;
827    ret->funcs = NULL;
828
829    ret->nb_axis = 0;
830    ret->max_axis = 0;
831    ret->axis = NULL;
832
833    ret->namespaces = NULL;
834    ret->user = NULL;
835    ret->nsNr = 0;
836    return(ret);
837}
838
839/**
840 * xmlXPathFreeContext:
841 * @ctxt:  the context to free
842 *
843 * Free up an xmlXPathContext
844 */
845void
846xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
847    if (ctxt->namespaces != NULL)
848        xmlFree(ctxt->namespaces);
849
850 /***********
851    if (ctxt->nodelist != NULL)
852        xmlXPathFreeNodeSet(ctxt->nodelist);
853  ***********/
854#ifdef DEBUG
855    memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
856#endif
857    xmlFree(ctxt);
858}
859
860/************************************************************************
861 *									*
862 *		Routines to handle XPath parser contexts		*
863 *									*
864 ************************************************************************/
865
866#define CHECK_CTXT							\
867    if (ctxt == NULL) { 						\
868        fprintf(xmlXPathDebug, "%s:%d Internal error: ctxt == NULL\n",	\
869	        __FILE__, __LINE__);					\
870    }									\
871
872
873#define CHECK_CONTEXT							\
874    if (ctxt == NULL) { 						\
875        fprintf(xmlXPathDebug, "%s:%d Internal error: no context\n",	\
876	        __FILE__, __LINE__);					\
877    }									\
878    if (ctxt->doc == NULL) { 						\
879        fprintf(xmlXPathDebug, "%s:%d Internal error: no document\n",	\
880	        __FILE__, __LINE__);					\
881    }									\
882    if (ctxt->doc->root == NULL) { 					\
883        fprintf(xmlXPathDebug,						\
884	        "%s:%d Internal error: document without root\n",	\
885	        __FILE__, __LINE__);					\
886    }									\
887
888
889/**
890 * xmlXPathNewParserContext:
891 * @str:  the XPath expression
892 * @ctxt:  the XPath context
893 *
894 * Create a new xmlXPathParserContext
895 *
896 * Returns the xmlXPathParserContext just allocated.
897 */
898xmlXPathParserContextPtr
899xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
900    xmlXPathParserContextPtr ret;
901
902    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
903    if (ret == NULL) {
904        fprintf(xmlXPathDebug, "xmlXPathNewParserContext: out of memory\n");
905	return(NULL);
906    }
907    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
908    ret->cur = ret->base = str;
909    ret->context = ctxt;
910
911    /* Allocate the value stack */
912    ret->valueTab = (xmlXPathObjectPtr *)
913                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
914    ret->valueNr = 0;
915    ret->valueMax = 10;
916    ret->value = NULL;
917    return(ret);
918}
919
920/**
921 * xmlXPathFreeParserContext:
922 * @ctxt:  the context to free
923 *
924 * Free up an xmlXPathParserContext
925 */
926void
927xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
928    if (ctxt->valueTab != NULL) {
929#ifdef DEBUG
930        memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
931#endif
932        xmlFree(ctxt->valueTab);
933    }
934#ifdef DEBUG
935    memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
936#endif
937    xmlFree(ctxt);
938}
939
940/************************************************************************
941 *									*
942 *		The implicit core function library			*
943 *									*
944 ************************************************************************/
945
946/*
947 * Auto-pop and cast to a number
948 */
949void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
950
951#define CHECK_ARITY(x)						\
952    if (nargs != (x)) {						\
953        ERROR(XPATH_INVALID_ARITY);				\
954    }								\
955
956
957#define POP_FLOAT						\
958    arg = valuePop(ctxt);					\
959    if (arg == NULL) {						\
960	ERROR(XPATH_INVALID_OPERAND);				\
961    }								\
962    if (arg->type != XPATH_NUMBER) {				\
963        valuePush(ctxt, arg);					\
964        xmlXPathNumberFunction(ctxt, 1);			\
965	arg = valuePop(ctxt);					\
966    }
967
968/**
969 * xmlXPathEqualNodeSetString
970 * @arg:  the nodeset object argument
971 * @str:  the string to compare to.
972 *
973 * Implement the equal operation on XPath objects content: @arg1 == @arg2
974 * If one object to be compared is a node-set and the other is a string,
975 * then the comparison will be true if and only if there is a node in
976 * the node-set such that the result of performing the comparison on the
977 * string-value of the node and the other string is true.
978 *
979 * Returns 0 or 1 depending on the results of the test.
980 */
981int
982xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
983    int i;
984    xmlNodeSetPtr ns;
985    xmlChar *str2;
986
987    if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
988        return(0);
989    ns = arg->nodesetval;
990    for (i = 0;i < ns->nodeNr;i++) {
991         str2 = xmlNodeGetContent(ns->nodeTab[i]);
992	 if ((str2 != NULL) && (!xmlStrcmp(str, str2))) {
993	     xmlFree(str2);
994	     return(1);
995	 }
996	 xmlFree(str2);
997    }
998    return(0);
999}
1000
1001/**
1002 * xmlXPathEqualNodeSetFloat
1003 * @arg:  the nodeset object argument
1004 * @f:  the float to compare to
1005 *
1006 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1007 * If one object to be compared is a node-set and the other is a number,
1008 * then the comparison will be true if and only if there is a node in
1009 * the node-set such that the result of performing the comparison on the
1010 * number to be compared and on the result of converting the string-value
1011 * of that node to a number using the number function is true.
1012 *
1013 * Returns 0 or 1 depending on the results of the test.
1014 */
1015int
1016xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
1017    char buf[100] = "";
1018
1019    if ((arg == NULL) || (arg->type != XPATH_NODESET))
1020        return(0);
1021
1022    if (isnan(f))
1023	sprintf(buf, "NaN");
1024    else if (isinf(f) > 0)
1025	sprintf(buf, "+Infinity");
1026    else if (isinf(f) < 0)
1027	sprintf(buf, "-Infinity");
1028    else
1029	sprintf(buf, "%0g", f);
1030
1031    return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
1032}
1033
1034
1035/**
1036 * xmlXPathEqualNodeSets
1037 * @arg1:  first nodeset object argument
1038 * @arg2:  second nodeset object argument
1039 *
1040 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1041 * If both objects to be compared are node-sets, then the comparison
1042 * will be true if and only if there is a node in the first node-set and
1043 * a node in the second node-set such that the result of performing the
1044 * comparison on the string-values of the two nodes is true.
1045 *
1046 * (needless to say, this is a costly operation)
1047 *
1048 * Returns 0 or 1 depending on the results of the test.
1049 */
1050int
1051xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1052    int i;
1053    xmlNodeSetPtr ns;
1054    xmlChar *str;
1055
1056    if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
1057        return(0);
1058    if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
1059        return(0);
1060
1061    ns = arg1->nodesetval;
1062    for (i = 0;i < ns->nodeNr;i++) {
1063         str = xmlNodeGetContent(ns->nodeTab[i]);
1064	 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
1065	     xmlFree(str);
1066	     return(1);
1067	 }
1068	 xmlFree(str);
1069    }
1070    return(0);
1071}
1072
1073/**
1074 * xmlXPathEqualValues:
1075 * @ctxt:  the XPath Parser context
1076 *
1077 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1078 *
1079 * Returns 0 or 1 depending on the results of the test.
1080 */
1081int
1082xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1083    xmlXPathObjectPtr arg1, arg2;
1084    int ret = 0;
1085
1086    arg1 = valuePop(ctxt);
1087    if (arg1 == NULL)
1088	ERROR0(XPATH_INVALID_OPERAND);
1089
1090    arg2 = valuePop(ctxt);
1091    if (arg2 == NULL) {
1092	xmlXPathFreeObject(arg1);
1093	ERROR0(XPATH_INVALID_OPERAND);
1094    }
1095
1096    if (arg1 == arg2) {
1097#ifdef DEBUG_EXPR
1098        fprintf(xmlXPathDebug, "Equal: by pointer\n");
1099#endif
1100        return(1);
1101    }
1102
1103    switch (arg1->type) {
1104        case XPATH_UNDEFINED:
1105#ifdef DEBUG_EXPR
1106	    fprintf(xmlXPathDebug, "Equal: undefined\n");
1107#endif
1108	    break;
1109        case XPATH_NODESET:
1110	    switch (arg2->type) {
1111	        case XPATH_UNDEFINED:
1112#ifdef DEBUG_EXPR
1113		    fprintf(xmlXPathDebug, "Equal: undefined\n");
1114#endif
1115		    break;
1116		case XPATH_NODESET:
1117		    ret = xmlXPathEqualNodeSets(arg1, arg2);
1118		    break;
1119		case XPATH_BOOLEAN:
1120		    if ((arg1->nodesetval == NULL) ||
1121			(arg1->nodesetval->nodeNr == 0)) ret = 0;
1122		    else
1123			ret = 1;
1124		    ret = (ret == arg2->boolval);
1125		    break;
1126		case XPATH_NUMBER:
1127		    ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
1128		    break;
1129		case XPATH_STRING:
1130		    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
1131		    break;
1132	    }
1133	    break;
1134        case XPATH_BOOLEAN:
1135	    switch (arg2->type) {
1136	        case XPATH_UNDEFINED:
1137#ifdef DEBUG_EXPR
1138		    fprintf(xmlXPathDebug, "Equal: undefined\n");
1139#endif
1140		    break;
1141		case XPATH_NODESET:
1142		    if ((arg2->nodesetval == NULL) ||
1143			(arg2->nodesetval->nodeNr == 0)) ret = 0;
1144		    else
1145			ret = 1;
1146		    break;
1147		case XPATH_BOOLEAN:
1148#ifdef DEBUG_EXPR
1149		    fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
1150			    arg1->boolval, arg2->boolval);
1151#endif
1152		    ret = (arg1->boolval == arg2->boolval);
1153		    break;
1154		case XPATH_NUMBER:
1155		    if (arg2->floatval) ret = 1;
1156		    else ret = 0;
1157		    ret = (arg1->boolval == ret);
1158		    break;
1159		case XPATH_STRING:
1160		    if ((arg2->stringval == NULL) ||
1161			(arg2->stringval[0] == 0)) ret = 0;
1162		    else
1163			ret = 1;
1164		    ret = (arg1->boolval == ret);
1165		    break;
1166	    }
1167	    break;
1168        case XPATH_NUMBER:
1169	    switch (arg2->type) {
1170	        case XPATH_UNDEFINED:
1171#ifdef DEBUG_EXPR
1172		    fprintf(xmlXPathDebug, "Equal: undefined\n");
1173#endif
1174		    break;
1175		case XPATH_NODESET:
1176		    ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
1177		    break;
1178		case XPATH_BOOLEAN:
1179		    if (arg1->floatval) ret = 1;
1180		    else ret = 0;
1181		    ret = (arg2->boolval == ret);
1182		    break;
1183		case XPATH_STRING:
1184		    valuePush(ctxt, arg2);
1185		    xmlXPathNumberFunction(ctxt, 1);
1186		    arg2 = valuePop(ctxt);
1187		    /* no break on purpose */
1188		case XPATH_NUMBER:
1189		    ret = (arg1->floatval == arg2->floatval);
1190		    break;
1191	    }
1192	    break;
1193        case XPATH_STRING:
1194	    switch (arg2->type) {
1195	        case XPATH_UNDEFINED:
1196#ifdef DEBUG_EXPR
1197		    fprintf(xmlXPathDebug, "Equal: undefined\n");
1198#endif
1199		    break;
1200		case XPATH_NODESET:
1201		    ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
1202		    break;
1203		case XPATH_BOOLEAN:
1204		    if ((arg1->stringval == NULL) ||
1205			(arg1->stringval[0] == 0)) ret = 0;
1206		    else
1207			ret = 1;
1208		    ret = (arg2->boolval == ret);
1209		    break;
1210		case XPATH_STRING:
1211		    ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
1212		    break;
1213		case XPATH_NUMBER:
1214		    valuePush(ctxt, arg1);
1215		    xmlXPathNumberFunction(ctxt, 1);
1216		    arg1 = valuePop(ctxt);
1217		    ret = (arg1->floatval == arg2->floatval);
1218		    break;
1219	    }
1220	    break;
1221    }
1222    xmlXPathFreeObject(arg1);
1223    xmlXPathFreeObject(arg2);
1224    return(ret);
1225}
1226
1227/**
1228 * xmlXPathCompareValues:
1229 * @ctxt:  the XPath Parser context
1230 * @inf:  less than (1) or greater than (2)
1231 * @strict:  is the comparison strict
1232 *
1233 * Implement the compare operation on XPath objects:
1234 *     @arg1 < @arg2    (1, 1, ...
1235 *     @arg1 <= @arg2   (1, 0, ...
1236 *     @arg1 > @arg2    (0, 1, ...
1237 *     @arg1 >= @arg2   (0, 0, ...
1238 *
1239 * When neither object to be compared is a node-set and the operator is
1240 * <=, <, >=, >, then the objects are compared by converted both objects
1241 * to numbers and comparing the numbers according to IEEE 754. The <
1242 * comparison will be true if and only if the first number is less than the
1243 * second number. The <= comparison will be true if and only if the first
1244 * number is less than or equal to the second number. The > comparison
1245 * will be true if and only if the first number is greater than the second
1246 * number. The >= comparison will be true if and only if the first number
1247 * is greater than or equal to the second number.
1248 */
1249int
1250xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1251    int ret = 0;
1252    xmlXPathObjectPtr arg1, arg2;
1253
1254    arg2 = valuePop(ctxt);
1255    if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1256        if (arg2 != NULL)
1257	    xmlXPathFreeObject(arg2);
1258	ERROR0(XPATH_INVALID_OPERAND);
1259    }
1260
1261    arg1 = valuePop(ctxt);
1262    if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1263        if (arg1 != NULL)
1264	    xmlXPathFreeObject(arg1);
1265	xmlXPathFreeObject(arg2);
1266	ERROR0(XPATH_INVALID_OPERAND);
1267    }
1268
1269    if (arg1->type != XPATH_NUMBER) {
1270	valuePush(ctxt, arg1);
1271	xmlXPathNumberFunction(ctxt, 1);
1272	arg1 = valuePop(ctxt);
1273    }
1274    if (arg1->type != XPATH_NUMBER) {
1275	xmlXPathFreeObject(arg1);
1276	xmlXPathFreeObject(arg2);
1277	ERROR0(XPATH_INVALID_OPERAND);
1278    }
1279    if (arg2->type != XPATH_NUMBER) {
1280	valuePush(ctxt, arg2);
1281	xmlXPathNumberFunction(ctxt, 1);
1282	arg2 = valuePop(ctxt);
1283    }
1284    if (arg2->type != XPATH_NUMBER) {
1285	xmlXPathFreeObject(arg1);
1286	xmlXPathFreeObject(arg2);
1287	ERROR0(XPATH_INVALID_OPERAND);
1288    }
1289    /*
1290     * Add tests for infinity and nan
1291     * => feedback on 3.4 for Inf and NaN
1292     */
1293    if (inf && strict)
1294        ret = (arg1->floatval < arg2->floatval);
1295    else if (inf && !strict)
1296        ret = (arg1->floatval <= arg2->floatval);
1297    else if (!inf && strict)
1298        ret = (arg1->floatval > arg2->floatval);
1299    else if (!inf && !strict)
1300        ret = (arg1->floatval >= arg2->floatval);
1301    xmlXPathFreeObject(arg1);
1302    xmlXPathFreeObject(arg2);
1303    return(ret);
1304}
1305
1306/**
1307 * xmlXPathValueFlipSign:
1308 * @ctxt:  the XPath Parser context
1309 *
1310 * Implement the unary - operation on an XPath object
1311 * The numeric operators convert their operands to numbers as if
1312 * by calling the number function.
1313 */
1314void
1315xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1316    xmlXPathObjectPtr arg;
1317
1318    POP_FLOAT
1319    arg->floatval = -arg->floatval;
1320    valuePush(ctxt, arg);
1321}
1322
1323/**
1324 * xmlXPathAddValues:
1325 * @ctxt:  the XPath Parser context
1326 *
1327 * Implement the add operation on XPath objects:
1328 * The numeric operators convert their operands to numbers as if
1329 * by calling the number function.
1330 */
1331void
1332xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1333    xmlXPathObjectPtr arg;
1334    double val;
1335
1336    POP_FLOAT
1337    val = arg->floatval;
1338    xmlXPathFreeObject(arg);
1339
1340    POP_FLOAT
1341    arg->floatval += val;
1342    valuePush(ctxt, arg);
1343}
1344
1345/**
1346 * xmlXPathSubValues:
1347 * @ctxt:  the XPath Parser context
1348 *
1349 * Implement the substraction operation on XPath objects:
1350 * The numeric operators convert their operands to numbers as if
1351 * by calling the number function.
1352 */
1353void
1354xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1355    xmlXPathObjectPtr arg;
1356    double val;
1357
1358    POP_FLOAT
1359    val = arg->floatval;
1360    xmlXPathFreeObject(arg);
1361
1362    POP_FLOAT
1363    arg->floatval -= val;
1364    valuePush(ctxt, arg);
1365}
1366
1367/**
1368 * xmlXPathMultValues:
1369 * @ctxt:  the XPath Parser context
1370 *
1371 * Implement the multiply operation on XPath objects:
1372 * The numeric operators convert their operands to numbers as if
1373 * by calling the number function.
1374 */
1375void
1376xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1377    xmlXPathObjectPtr arg;
1378    double val;
1379
1380    POP_FLOAT
1381    val = arg->floatval;
1382    xmlXPathFreeObject(arg);
1383
1384    POP_FLOAT
1385    arg->floatval *= val;
1386    valuePush(ctxt, arg);
1387}
1388
1389/**
1390 * xmlXPathDivValues:
1391 * @ctxt:  the XPath Parser context
1392 *
1393 * Implement the div operation on XPath objects:
1394 * The numeric operators convert their operands to numbers as if
1395 * by calling the number function.
1396 */
1397void
1398xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1399    xmlXPathObjectPtr arg;
1400    double val;
1401
1402    POP_FLOAT
1403    val = arg->floatval;
1404    xmlXPathFreeObject(arg);
1405
1406    POP_FLOAT
1407    arg->floatval /= val;
1408    valuePush(ctxt, arg);
1409}
1410
1411/**
1412 * xmlXPathModValues:
1413 * @ctxt:  the XPath Parser context
1414 *
1415 * Implement the div operation on XPath objects: @arg1 / @arg2
1416 * The numeric operators convert their operands to numbers as if
1417 * by calling the number function.
1418 */
1419void
1420xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1421    xmlXPathObjectPtr arg;
1422    double val;
1423
1424    POP_FLOAT
1425    val = arg->floatval;
1426    xmlXPathFreeObject(arg);
1427
1428    POP_FLOAT
1429    arg->floatval /= val;
1430    valuePush(ctxt, arg);
1431}
1432
1433/************************************************************************
1434 *									*
1435 *		The traversal functions					*
1436 *									*
1437 ************************************************************************/
1438
1439#define AXIS_ANCESTOR			1
1440#define AXIS_ANCESTOR_OR_SELF		2
1441#define AXIS_ATTRIBUTE			3
1442#define AXIS_CHILD			4
1443#define AXIS_DESCENDANT			5
1444#define AXIS_DESCENDANT_OR_SELF		6
1445#define AXIS_FOLLOWING			7
1446#define AXIS_FOLLOWING_SIBLING		8
1447#define AXIS_NAMESPACE			9
1448#define AXIS_PARENT			10
1449#define AXIS_PRECEDING			11
1450#define AXIS_PRECEDING_SIBLING		12
1451#define AXIS_SELF			13
1452
1453/*
1454 * A traversal function enumerates nodes along an axis.
1455 * Initially it must be called with NULL, and it indicates
1456 * termination on the axis by returning NULL.
1457 */
1458typedef xmlNodePtr (*xmlXPathTraversalFunction)
1459                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1460
1461/**
1462 * mlXPathNextSelf:
1463 * @ctxt:  the XPath Parser context
1464 * @cur:  the current node in the traversal
1465 *
1466 * Traversal function for the "self" direction
1467 * he self axis contains just the context node itself
1468 *
1469 * Returns the next element following that axis
1470 */
1471xmlNodePtr
1472xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1473    if (cur == NULL)
1474        return(ctxt->context->node);
1475    return(NULL);
1476}
1477
1478/**
1479 * mlXPathNextChild:
1480 * @ctxt:  the XPath Parser context
1481 * @cur:  the current node in the traversal
1482 *
1483 * Traversal function for the "child" direction
1484 * The child axis contains the children of the context node in document order.
1485 *
1486 * Returns the next element following that axis
1487 */
1488xmlNodePtr
1489xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1490    if (cur == NULL) {
1491	if (ctxt->context->node == NULL) return(NULL);
1492	switch (ctxt->context->node->type) {
1493            case XML_ELEMENT_NODE:
1494            case XML_TEXT_NODE:
1495            case XML_CDATA_SECTION_NODE:
1496            case XML_ENTITY_REF_NODE:
1497            case XML_ENTITY_NODE:
1498            case XML_PI_NODE:
1499            case XML_COMMENT_NODE:
1500            case XML_NOTATION_NODE:
1501		return(ctxt->context->node->childs);
1502            case XML_ATTRIBUTE_NODE:
1503		return(NULL);
1504            case XML_DOCUMENT_NODE:
1505            case XML_DOCUMENT_TYPE_NODE:
1506            case XML_DOCUMENT_FRAG_NODE:
1507            case XML_HTML_DOCUMENT_NODE:
1508		return(((xmlDocPtr) ctxt->context->node)->root);
1509	}
1510	return(NULL);
1511    }
1512    if ((cur->type == XML_DOCUMENT_NODE) ||
1513        (cur->type == XML_HTML_DOCUMENT_NODE))
1514	return(NULL);
1515    return(cur->next);
1516}
1517
1518/**
1519 * mlXPathNextDescendant:
1520 * @ctxt:  the XPath Parser context
1521 * @cur:  the current node in the traversal
1522 *
1523 * Traversal function for the "descendant" direction
1524 * the descendant axis contains the descendants of the context node in document
1525 * order; a descendant is a child or a child of a child and so on.
1526 *
1527 * Returns the next element following that axis
1528 */
1529xmlNodePtr
1530xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1531    if (cur == NULL) {
1532	if (ctxt->context->node == NULL)
1533	    return(NULL);
1534	if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
1535	    return(NULL);
1536
1537        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1538	    return(ctxt->context->doc->root);
1539        return(ctxt->context->node->childs);
1540    }
1541
1542    if (cur->childs != NULL) return(cur->childs);
1543    if (cur->next != NULL) return(cur->next);
1544
1545    do {
1546        cur = cur->parent;
1547	if (cur == NULL) return(NULL);
1548	if (cur == ctxt->context->node) return(NULL);
1549	if (cur->next != NULL) {
1550	    cur = cur->next;
1551	    return(cur);
1552	}
1553    } while (cur != NULL);
1554    return(cur);
1555}
1556
1557/**
1558 * mlXPathNextDescendantOrSelf:
1559 * @ctxt:  the XPath Parser context
1560 * @cur:  the current node in the traversal
1561 *
1562 * Traversal function for the "descendant-or-self" direction
1563 * the descendant-or-self axis contains the context node and the descendants
1564 * of the context node in document order; thus the context node is the first
1565 * node on the axis, and the first child of the context node is the second node
1566 * on the axis
1567 *
1568 * Returns the next element following that axis
1569 */
1570xmlNodePtr
1571xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1572    if (cur == NULL) {
1573	if (ctxt->context->node == NULL)
1574	    return(NULL);
1575	if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
1576	    return(NULL);
1577        return(ctxt->context->node);
1578    }
1579
1580    return(xmlXPathNextDescendant(ctxt, cur));
1581}
1582
1583/**
1584 * xmlXPathNextParent:
1585 * @ctxt:  the XPath Parser context
1586 * @cur:  the current node in the traversal
1587 *
1588 * Traversal function for the "parent" direction
1589 * The parent axis contains the parent of the context node, if there is one.
1590 *
1591 * Returns the next element following that axis
1592 */
1593xmlNodePtr
1594xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1595    /*
1596     * the parent of an attribute or namespace node is the element
1597     * to which the attribute or namespace node is attached
1598     * Namespace handling !!!
1599     */
1600    if (cur == NULL) {
1601	if (ctxt->context->node == NULL) return(NULL);
1602	switch (ctxt->context->node->type) {
1603            case XML_ELEMENT_NODE:
1604            case XML_TEXT_NODE:
1605            case XML_CDATA_SECTION_NODE:
1606            case XML_ENTITY_REF_NODE:
1607            case XML_ENTITY_NODE:
1608            case XML_PI_NODE:
1609            case XML_COMMENT_NODE:
1610            case XML_NOTATION_NODE:
1611		if (ctxt->context->node->parent == NULL)
1612		    return((xmlNodePtr) ctxt->context->doc);
1613		return(ctxt->context->node->parent);
1614            case XML_ATTRIBUTE_NODE: {
1615		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
1616
1617		return(att->node);
1618	    }
1619            case XML_DOCUMENT_NODE:
1620            case XML_DOCUMENT_TYPE_NODE:
1621            case XML_DOCUMENT_FRAG_NODE:
1622            case XML_HTML_DOCUMENT_NODE:
1623                return(NULL);
1624	}
1625    }
1626    return(NULL);
1627}
1628
1629/**
1630 * xmlXPathNextAncestor:
1631 * @ctxt:  the XPath Parser context
1632 * @cur:  the current node in the traversal
1633 *
1634 * Traversal function for the "ancestor" direction
1635 * the ancestor axis contains the ancestors of the context node; the ancestors
1636 * of the context node consist of the parent of context node and the parent's
1637 * parent and so on; the nodes are ordered in reverse document order; thus the
1638 * parent is the first node on the axis, and the parent's parent is the second
1639 * node on the axis
1640 *
1641 * Returns the next element following that axis
1642 */
1643xmlNodePtr
1644xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1645    /*
1646     * the parent of an attribute or namespace node is the element
1647     * to which the attribute or namespace node is attached
1648     * !!!!!!!!!!!!!
1649     */
1650    if (cur == NULL) {
1651	if (ctxt->context->node == NULL) return(NULL);
1652	switch (ctxt->context->node->type) {
1653            case XML_ELEMENT_NODE:
1654            case XML_TEXT_NODE:
1655            case XML_CDATA_SECTION_NODE:
1656            case XML_ENTITY_REF_NODE:
1657            case XML_ENTITY_NODE:
1658            case XML_PI_NODE:
1659            case XML_COMMENT_NODE:
1660            case XML_NOTATION_NODE:
1661		if (ctxt->context->node->parent == NULL)
1662		    return((xmlNodePtr) ctxt->context->doc);
1663		return(ctxt->context->node->parent);
1664            case XML_ATTRIBUTE_NODE: {
1665		xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
1666
1667		return(cur->node);
1668	    }
1669            case XML_DOCUMENT_NODE:
1670            case XML_DOCUMENT_TYPE_NODE:
1671            case XML_DOCUMENT_FRAG_NODE:
1672            case XML_HTML_DOCUMENT_NODE:
1673                return(NULL);
1674	}
1675	return(NULL);
1676    }
1677    if (cur == ctxt->context->doc->root)
1678	return((xmlNodePtr) ctxt->context->doc);
1679    if (cur == (xmlNodePtr) ctxt->context->doc)
1680	return(NULL);
1681    switch (cur->type) {
1682	case XML_ELEMENT_NODE:
1683	case XML_TEXT_NODE:
1684	case XML_CDATA_SECTION_NODE:
1685	case XML_ENTITY_REF_NODE:
1686	case XML_ENTITY_NODE:
1687	case XML_PI_NODE:
1688	case XML_COMMENT_NODE:
1689	case XML_NOTATION_NODE:
1690	    return(cur->parent);
1691	case XML_ATTRIBUTE_NODE: {
1692	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
1693
1694	    return(att->node);
1695	}
1696	case XML_DOCUMENT_NODE:
1697	case XML_DOCUMENT_TYPE_NODE:
1698	case XML_DOCUMENT_FRAG_NODE:
1699	case XML_HTML_DOCUMENT_NODE:
1700	    return(NULL);
1701    }
1702    return(NULL);
1703}
1704
1705/**
1706 * xmlXPathNextAncestorOrSelf:
1707 * @ctxt:  the XPath Parser context
1708 * @cur:  the current node in the traversal
1709 *
1710 * Traversal function for the "ancestor-or-self" direction
1711 * he ancestor-or-self axis contains the context node and ancestors of
1712 * the context node in reverse document order; thus the context node is
1713 * the first node on the axis, and the context node's parent the second;
1714 * parent here is defined the same as with the parent axis.
1715 *
1716 * Returns the next element following that axis
1717 */
1718xmlNodePtr
1719xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1720    if (cur == NULL)
1721        return(ctxt->context->node);
1722    return(xmlXPathNextAncestor(ctxt, cur));
1723}
1724
1725/**
1726 * xmlXPathNextFollowingSibling:
1727 * @ctxt:  the XPath Parser context
1728 * @cur:  the current node in the traversal
1729 *
1730 * Traversal function for the "following-sibling" direction
1731 * The following-sibling axis contains the following siblings of the context
1732 * node in document order.
1733 *
1734 * Returns the next element following that axis
1735 */
1736xmlNodePtr
1737xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1738    if (cur == (xmlNodePtr) ctxt->context->doc)
1739        return(NULL);
1740    if (cur == NULL)
1741        return(ctxt->context->node->next);
1742    return(cur->next);
1743}
1744
1745/**
1746 * xmlXPathNextPrecedingSibling:
1747 * @ctxt:  the XPath Parser context
1748 * @cur:  the current node in the traversal
1749 *
1750 * Traversal function for the "preceding-sibling" direction
1751 * The preceding-sibling axis contains the preceding siblings of the context
1752 * node in reverse document order; the first preceding sibling is first on the
1753 * axis; the sibling preceding that node is the second on the axis and so on.
1754 *
1755 * Returns the next element following that axis
1756 */
1757xmlNodePtr
1758xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1759    if (cur == (xmlNodePtr) ctxt->context->doc)
1760        return(NULL);
1761    if (cur == NULL)
1762        return(ctxt->context->node->prev);
1763    return(cur->prev);
1764}
1765
1766/**
1767 * xmlXPathNextFollowing:
1768 * @ctxt:  the XPath Parser context
1769 * @cur:  the current node in the traversal
1770 *
1771 * Traversal function for the "following" direction
1772 * The following axis contains all nodes in the same document as the context
1773 * node that are after the context node in document order, excluding any
1774 * descendants and excluding attribute nodes and namespace nodes; the nodes
1775 * are ordered in document order
1776 *
1777 * Returns the next element following that axis
1778 */
1779xmlNodePtr
1780xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1781    if (cur == (xmlNodePtr) ctxt->context->doc)
1782        return(NULL);
1783    if (cur == NULL)
1784        return(ctxt->context->node->next);; /* !!!!!!!!! */
1785    if (cur->childs != NULL) return(cur->childs);
1786    if (cur->next != NULL) return(cur->next);
1787
1788    do {
1789        cur = cur->parent;
1790	if (cur == NULL) return(NULL);
1791	if (cur == ctxt->context->doc->root) return(NULL);
1792	if (cur->next != NULL) {
1793	    cur = cur->next;
1794	    return(cur);
1795	}
1796    } while (cur != NULL);
1797    return(cur);
1798}
1799
1800/**
1801 * xmlXPathNextPreceding:
1802 * @ctxt:  the XPath Parser context
1803 * @cur:  the current node in the traversal
1804 *
1805 * Traversal function for the "preceding" direction
1806 * the preceding axis contains all nodes in the same document as the context
1807 * node that are before the context node in document order, excluding any
1808 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
1809 * ordered in reverse document order
1810 *
1811 * Returns the next element following that axis
1812 */
1813xmlNodePtr
1814xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1815    if (cur == (xmlNodePtr) ctxt->context->doc)
1816        return(NULL);
1817    if (cur == NULL)
1818        return(ctxt->context->node->prev); /* !!!!!!!!! */
1819    if (cur->last != NULL) return(cur->last);
1820    if (cur->prev != NULL) return(cur->prev);
1821
1822    do {
1823        cur = cur->parent;
1824	if (cur == NULL) return(NULL);
1825	if (cur == ctxt->context->doc->root) return(NULL);
1826	if (cur->prev != NULL) {
1827	    cur = cur->prev;
1828	    return(cur);
1829	}
1830    } while (cur != NULL);
1831    return(cur);
1832}
1833
1834/**
1835 * xmlXPathNextNamespace:
1836 * @ctxt:  the XPath Parser context
1837 * @cur:  the current attribute in the traversal
1838 *
1839 * Traversal function for the "namespace" direction
1840 * the namespace axis contains the namespace nodes of the context node;
1841 * the order of nodes on this axis is implementation-defined; the axis will
1842 * be empty unless the context node is an element
1843 *
1844 * Returns the next element following that axis
1845 */
1846xmlNsPtr
1847xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
1848    if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
1849        if (ctxt->context->namespaces != NULL)
1850	    xmlFree(ctxt->context->namespaces);
1851	ctxt->context->namespaces =
1852	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
1853	if (ctxt->context->namespaces == NULL) return(NULL);
1854	ctxt->context->nsNr = 0;
1855    }
1856    return(ctxt->context->namespaces[ctxt->context->nsNr++]);
1857}
1858
1859/**
1860 * xmlXPathNextAttribute:
1861 * @ctxt:  the XPath Parser context
1862 * @cur:  the current attribute in the traversal
1863 *
1864 * Traversal function for the "attribute" direction
1865 * TODO: support DTD inherited default attributes
1866 *
1867 * Returns the next element following that axis
1868 */
1869xmlAttrPtr
1870xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
1871    if (cur == NULL) {
1872        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1873	    return(NULL);
1874        return(ctxt->context->node->properties);
1875    }
1876    return(cur->next);
1877}
1878
1879/************************************************************************
1880 *									*
1881 *		NodeTest Functions					*
1882 *									*
1883 ************************************************************************/
1884
1885#define NODE_TEST_NONE	0
1886#define NODE_TEST_TYPE	1
1887#define NODE_TEST_PI	2
1888#define NODE_TEST_ALL	3
1889#define NODE_TEST_NS	4
1890#define NODE_TEST_NAME	5
1891
1892#define NODE_TYPE_COMMENT		50
1893#define NODE_TYPE_TEXT			51
1894#define NODE_TYPE_PI			52
1895#define NODE_TYPE_NODE			53
1896
1897#define IS_FUNCTION			200
1898
1899/**
1900 * xmlXPathNodeCollectAndTest:
1901 * @ctxt:  the XPath Parser context
1902 * @cur:  the current node to test
1903 *
1904 * This is the function implementing a step: based on the current list
1905 * of nodes, it builds up a new list, looking at all nodes under that
1906 * axis and selecting them.
1907 *
1908 * Returns the new NodeSet resulting from the search.
1909 */
1910xmlNodeSetPtr
1911xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, int axis,
1912                 int test, int type, const xmlChar *prefix, const xmlChar *name) {
1913#ifdef DEBUG_STEP
1914    int n = 0, t = 0;
1915#endif
1916    int i;
1917    xmlNodeSetPtr ret;
1918    xmlXPathTraversalFunction next = NULL;
1919    xmlNodePtr cur = NULL;
1920
1921    if (ctxt->context->nodelist == NULL) {
1922	if (ctxt->context->node == NULL) {
1923	    fprintf(xmlXPathDebug,
1924	     "xmlXPathNodeCollectAndTest %s:%d : nodelist and node are NULL\n",
1925	            __FILE__, __LINE__);
1926	    return(NULL);
1927	}
1928        STRANGE
1929        return(NULL);
1930    }
1931#ifdef DEBUG_STEP
1932    fprintf(xmlXPathDebug, "new step : ");
1933#endif
1934    switch (axis) {
1935        case AXIS_ANCESTOR:
1936#ifdef DEBUG_STEP
1937	    fprintf(xmlXPathDebug, "axis 'ancestors' ");
1938#endif
1939	    next = xmlXPathNextAncestor; break;
1940        case AXIS_ANCESTOR_OR_SELF:
1941#ifdef DEBUG_STEP
1942	    fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
1943#endif
1944	    next = xmlXPathNextAncestorOrSelf; break;
1945        case AXIS_ATTRIBUTE:
1946#ifdef DEBUG_STEP
1947	    fprintf(xmlXPathDebug, "axis 'attributes' ");
1948#endif
1949	    next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
1950	    break;
1951        case AXIS_CHILD:
1952#ifdef DEBUG_STEP
1953	    fprintf(xmlXPathDebug, "axis 'child' ");
1954#endif
1955	    next = xmlXPathNextChild; break;
1956        case AXIS_DESCENDANT:
1957#ifdef DEBUG_STEP
1958	    fprintf(xmlXPathDebug, "axis 'descendant' ");
1959#endif
1960	    next = xmlXPathNextDescendant; break;
1961        case AXIS_DESCENDANT_OR_SELF:
1962#ifdef DEBUG_STEP
1963	    fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
1964#endif
1965	    next = xmlXPathNextDescendantOrSelf; break;
1966        case AXIS_FOLLOWING:
1967#ifdef DEBUG_STEP
1968	    fprintf(xmlXPathDebug, "axis 'following' ");
1969#endif
1970	    next = xmlXPathNextFollowing; break;
1971        case AXIS_FOLLOWING_SIBLING:
1972#ifdef DEBUG_STEP
1973	    fprintf(xmlXPathDebug, "axis 'following-siblings' ");
1974#endif
1975	    next = xmlXPathNextFollowingSibling; break;
1976        case AXIS_NAMESPACE:
1977#ifdef DEBUG_STEP
1978	    fprintf(xmlXPathDebug, "axis 'namespace' ");
1979#endif
1980	    next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
1981	    break;
1982        case AXIS_PARENT:
1983#ifdef DEBUG_STEP
1984	    fprintf(xmlXPathDebug, "axis 'parent' ");
1985#endif
1986	    next = xmlXPathNextParent; break;
1987        case AXIS_PRECEDING:
1988#ifdef DEBUG_STEP
1989	    fprintf(xmlXPathDebug, "axis 'preceding' ");
1990#endif
1991	    next = xmlXPathNextPreceding; break;
1992        case AXIS_PRECEDING_SIBLING:
1993#ifdef DEBUG_STEP
1994	    fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
1995#endif
1996	    next = xmlXPathNextPrecedingSibling; break;
1997        case AXIS_SELF:
1998#ifdef DEBUG_STEP
1999	    fprintf(xmlXPathDebug, "axis 'self' ");
2000#endif
2001	    next = xmlXPathNextSelf; break;
2002    }
2003    if (next == NULL) return(NULL);
2004    ret = xmlXPathNodeSetCreate(NULL);
2005#ifdef DEBUG_STEP
2006    fprintf(xmlXPathDebug, " context contains %d nodes\n",
2007            ctxt->context->nodelist->nodeNr);
2008    switch (test) {
2009	case NODE_TEST_NONE:
2010	    fprintf(xmlXPathDebug, "           searching for none !!!\n");
2011	    break;
2012	case NODE_TEST_TYPE:
2013	    fprintf(xmlXPathDebug, "           searching for type %d\n", type);
2014	    break;
2015	case NODE_TEST_PI:
2016	    fprintf(xmlXPathDebug, "           searching for PI !!!\n");
2017	    break;
2018	case NODE_TEST_ALL:
2019	    fprintf(xmlXPathDebug, "           searching for *\n");
2020	    break;
2021	case NODE_TEST_NS:
2022	    fprintf(xmlXPathDebug, "           searching for namespace %s\n",
2023	            prefix);
2024	    break;
2025	case NODE_TEST_NAME:
2026	    fprintf(xmlXPathDebug, "           searching for name %s\n", name);
2027	    if (prefix != NULL)
2028		fprintf(xmlXPathDebug, "           with namespace %s\n",
2029		        prefix);
2030	    break;
2031    }
2032    fprintf(xmlXPathDebug, "Testing : ");
2033#endif
2034    for (i = 0;i < ctxt->context->nodelist->nodeNr; i++) {
2035        ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
2036
2037	cur = NULL;
2038	do {
2039	    cur = next(ctxt, cur);
2040	    if (cur == NULL) break;
2041#ifdef DEBUG_STEP
2042            t++;
2043            fprintf(xmlXPathDebug, " %s", cur->name);
2044#endif
2045	    switch (test) {
2046                case NODE_TEST_NONE:
2047		    STRANGE
2048		    return(NULL);
2049                case NODE_TEST_TYPE:
2050		    if ((cur->type == type) ||
2051		        ((type == XML_ELEMENT_NODE) &&
2052			 ((cur->type == XML_DOCUMENT_NODE) ||
2053			  (cur->type == XML_HTML_DOCUMENT_NODE)))) {
2054#ifdef DEBUG_STEP
2055                        n++;
2056#endif
2057		        xmlXPathNodeSetAdd(ret, cur);
2058		    }
2059		    break;
2060                case NODE_TEST_PI:
2061		    if (cur->type == XML_PI_NODE) {
2062		        if ((name != NULL) &&
2063			    (xmlStrcmp(name, cur->name)))
2064			    break;
2065#ifdef DEBUG_STEP
2066			n++;
2067#endif
2068			xmlXPathNodeSetAdd(ret, cur);
2069		    }
2070		    break;
2071                case NODE_TEST_ALL:
2072		    if ((cur->type == XML_ELEMENT_NODE) ||
2073		        (cur->type == XML_ATTRIBUTE_NODE)) {
2074			/* !!! || (cur->type == XML_TEXT_NODE)) { */
2075#ifdef DEBUG_STEP
2076                        n++;
2077#endif
2078		        xmlXPathNodeSetAdd(ret, cur);
2079		    }
2080		    break;
2081                case NODE_TEST_NS: {
2082		    TODO /* namespace search */
2083		    break;
2084		}
2085                case NODE_TEST_NAME:
2086		    switch (cur->type) {
2087		        case XML_ELEMENT_NODE:
2088			    if (!xmlStrcmp(name, cur->name) &&
2089				(((prefix == NULL) ||
2090				  ((cur->ns != NULL) &&
2091				   (!xmlStrcmp(prefix, cur->ns->href)))))) {
2092#ifdef DEBUG_STEP
2093			    n++;
2094#endif
2095				xmlXPathNodeSetAdd(ret, cur);
2096			    }
2097			    break;
2098		        case XML_ATTRIBUTE_NODE: {
2099			    xmlAttrPtr attr = (xmlAttrPtr) cur;
2100			    if (!xmlStrcmp(name, attr->name)) {
2101#ifdef DEBUG_STEP
2102			    n++;
2103#endif
2104				xmlXPathNodeSetAdd(ret, cur);
2105			    }
2106			    break;
2107			}
2108			default:
2109			    break;
2110		    }
2111	            break;
2112
2113	    }
2114	} while (cur != NULL);
2115    }
2116#ifdef DEBUG_STEP
2117    fprintf(xmlXPathDebug,
2118            "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2119#endif
2120    return(ret);
2121}
2122
2123
2124/************************************************************************
2125 *									*
2126 *		Implicit tree core function library			*
2127 *									*
2128 ************************************************************************/
2129
2130/**
2131 * xmlXPathRoot:
2132 * @ctxt:  the XPath Parser context
2133 *
2134 * Initialize the context to the root of the document
2135 */
2136void
2137xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
2138    if (ctxt->context->nodelist != NULL)
2139        xmlXPathFreeNodeSet(ctxt->context->nodelist);
2140    ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
2141    ctxt->context->nodelist = xmlXPathNodeSetCreate(ctxt->context->node);
2142}
2143
2144/************************************************************************
2145 *									*
2146 *		The explicit core function library			*
2147 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
2148 *									*
2149 ************************************************************************/
2150
2151
2152/**
2153 * xmlXPathLastFunction:
2154 * @ctxt:  the XPath Parser context
2155 *
2156 * Implement the last() XPath function
2157 * The last function returns the number of nodes in the context node list.
2158 */
2159void
2160xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2161    CHECK_ARITY(0);
2162    if ((ctxt->context->nodelist == NULL) ||
2163        (ctxt->context->node == NULL) ||
2164        (ctxt->context->nodelist->nodeNr == 0)) {
2165	valuePush(ctxt, xmlXPathNewFloat((double) 0));
2166    } else {
2167	valuePush(ctxt,
2168	          xmlXPathNewFloat((double) ctxt->context->nodelist->nodeNr));
2169    }
2170}
2171
2172/**
2173 * xmlXPathPositionFunction:
2174 * @ctxt:  the XPath Parser context
2175 *
2176 * Implement the position() XPath function
2177 * The position function returns the position of the context node in the
2178 * context node list. The first position is 1, and so the last positionr
2179 * will be equal to last().
2180 */
2181void
2182xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2183    int i;
2184
2185    CHECK_ARITY(0);
2186    if ((ctxt->context->nodelist == NULL) ||
2187        (ctxt->context->node == NULL) ||
2188        (ctxt->context->nodelist->nodeNr == 0)) {
2189	valuePush(ctxt, xmlXPathNewFloat((double) 0));
2190    }
2191    for (i = 0; i < ctxt->context->nodelist->nodeNr;i++) {
2192        if (ctxt->context->node == ctxt->context->nodelist->nodeTab[i]) {
2193	    valuePush(ctxt, xmlXPathNewFloat((double) i + 1));
2194	    return;
2195	}
2196    }
2197    valuePush(ctxt, xmlXPathNewFloat((double) 0));
2198}
2199
2200/**
2201 * xmlXPathCountFunction:
2202 * @ctxt:  the XPath Parser context
2203 *
2204 * Implement the count() XPath function
2205 */
2206void
2207xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2208    xmlXPathObjectPtr cur;
2209
2210    CHECK_ARITY(1);
2211    CHECK_TYPE(XPATH_NODESET);
2212    cur = valuePop(ctxt);
2213
2214    valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
2215    xmlXPathFreeObject(cur);
2216}
2217
2218/**
2219 * xmlXPathIdFunction:
2220 * @ctxt:  the XPath Parser context
2221 *
2222 * Implement the id() XPath function
2223 * The id function selects elements by their unique ID
2224 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2225 * then the result is the union of the result of applying id to the
2226 * string value of each of the nodes in the argument node-set. When the
2227 * argument to id is of any other type, the argument is converted to a
2228 * string as if by a call to the string function; the string is split
2229 * into a whitespace-separated list of tokens (whitespace is any sequence
2230 * of characters matching the production S); the result is a node-set
2231 * containing the elements in the same document as the context node that
2232 * have a unique ID equal to any of the tokens in the list.
2233 */
2234void
2235xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2236    const xmlChar *tokens;
2237    const xmlChar *cur;
2238    xmlChar *ID;
2239    xmlAttrPtr attr;
2240    xmlNodePtr elem = NULL;
2241    xmlXPathObjectPtr ret, obj;
2242
2243    CHECK_ARITY(1);
2244    obj = valuePop(ctxt);
2245    if (obj == NULL) ERROR(XPATH_INVALID_OPERAND);
2246    if (obj->type == XPATH_NODESET) {
2247        TODO /* ID function in case of NodeSet */
2248    }
2249    if (obj->type != XPATH_STRING) {
2250        valuePush(ctxt, obj);
2251	xmlXPathStringFunction(ctxt, 1);
2252	obj = valuePop(ctxt);
2253	if (obj->type != XPATH_STRING) {
2254	    xmlXPathFreeObject(obj);
2255	    return;
2256	}
2257    }
2258    tokens = obj->stringval;
2259
2260    ret = xmlXPathNewNodeSet(NULL);
2261    valuePush(ctxt, ret);
2262    if (tokens == NULL) {
2263	xmlXPathFreeObject(obj);
2264        return;
2265    }
2266
2267    cur = tokens;
2268
2269    while (IS_BLANK(*cur)) cur++;
2270    while (*cur != 0) {
2271	while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2272	       (*cur == '.') || (*cur == '-') ||
2273	       (*cur == '_') || (*cur == ':') ||
2274	       (IS_COMBINING(*cur)) ||
2275	       (IS_EXTENDER(*cur)))
2276	       cur++;
2277
2278	if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2279
2280        ID = xmlStrndup(tokens, cur - tokens);
2281	attr = xmlGetID(ctxt->context->doc, ID);
2282	if (attr != NULL) {
2283	    elem = attr->node;
2284            xmlXPathNodeSetAdd(ret->nodesetval, elem);
2285        }
2286	if (ID != NULL)
2287	    xmlFree(ID);
2288
2289	while (IS_BLANK(*cur)) cur++;
2290	tokens = cur;
2291    }
2292    xmlXPathFreeObject(obj);
2293    return;
2294}
2295
2296/**
2297 * xmlXPathLocalPartFunction:
2298 * @ctxt:  the XPath Parser context
2299 *
2300 * Implement the local-part() XPath function
2301 * The local-part function returns a string containing the local part
2302 * of the name of the node in the argument node-set that is first in
2303 * document order. If the node-set is empty or the first node has no
2304 * name, an empty string is returned. If the argument is omitted it
2305 * defaults to the context node.
2306 */
2307void
2308xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2309    xmlXPathObjectPtr cur;
2310
2311    CHECK_ARITY(1);
2312    CHECK_TYPE(XPATH_NODESET);
2313    cur = valuePop(ctxt);
2314
2315    if (cur->nodesetval->nodeNr == 0) {
2316	valuePush(ctxt, xmlXPathNewCString(""));
2317    } else {
2318	int i = 0; /* Should be first in document order !!!!! */
2319	valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2320    }
2321    xmlXPathFreeObject(cur);
2322}
2323
2324/**
2325 * xmlXPathNamespaceFunction:
2326 * @ctxt:  the XPath Parser context
2327 *
2328 * Implement the namespace() XPath function
2329 * The namespace function returns a string containing the namespace URI
2330 * of the expanded name of the node in the argument node-set that is
2331 * first in document order. If the node-set is empty, the first node has
2332 * no name, or the expanded name has no namespace URI, an empty string
2333 * is returned. If the argument is omitted it defaults to the context node.
2334 */
2335void
2336xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2337    xmlXPathObjectPtr cur;
2338
2339    if (nargs == 0) {
2340        valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2341	nargs = 1;
2342    }
2343    CHECK_ARITY(1);
2344    CHECK_TYPE(XPATH_NODESET);
2345    cur = valuePop(ctxt);
2346
2347    if (cur->nodesetval->nodeNr == 0) {
2348	valuePush(ctxt, xmlXPathNewCString(""));
2349    } else {
2350	int i = 0; /* Should be first in document order !!!!! */
2351
2352	if (cur->nodesetval->nodeTab[i]->ns == NULL)
2353	    valuePush(ctxt, xmlXPathNewCString(""));
2354	else
2355	    valuePush(ctxt, xmlXPathNewString(
2356		      cur->nodesetval->nodeTab[i]->ns->href));
2357    }
2358    xmlXPathFreeObject(cur);
2359}
2360
2361/**
2362 * xmlXPathNameFunction:
2363 * @ctxt:  the XPath Parser context
2364 *
2365 * Implement the name() XPath function
2366 * The name function returns a string containing a QName representing
2367 * the name of the node in the argument node-set that is first in documenti
2368 * order. The QName must represent the name with respect to the namespace
2369 * declarations in effect on the node whose name is being represented.
2370 * Typically, this will be the form in which the name occurred in the XML
2371 * source. This need not be the case if there are namespace declarations
2372 * in effect on the node that associate multiple prefixes with the same
2373 * namespace. However, an implementation may include information about
2374 * the original prefix in its representation of nodes; in this case, an
2375 * implementation can ensure that the returned string is always the same
2376 * as the QName used in the XML source. If the argument it omitted it
2377 * defaults to the context node.
2378 * Libxml keep the original prefix so the "real qualified name" used is
2379 * returned.
2380 */
2381void
2382xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2383    xmlXPathObjectPtr cur;
2384
2385    CHECK_ARITY(1);
2386    CHECK_TYPE(XPATH_NODESET);
2387    cur = valuePop(ctxt);
2388
2389    if (cur->nodesetval->nodeNr == 0) {
2390	valuePush(ctxt, xmlXPathNewCString(""));
2391    } else {
2392	int i = 0; /* Should be first in document order !!!!! */
2393
2394	if (cur->nodesetval->nodeTab[i]->ns == NULL)
2395	    valuePush(ctxt, xmlXPathNewString(
2396	                cur->nodesetval->nodeTab[i]->name));
2397
2398	else {
2399	    char name[2000];
2400	    sprintf(name, "%s:%s",
2401	            (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2402	            (char *) cur->nodesetval->nodeTab[i]->name);
2403	    valuePush(ctxt, xmlXPathNewCString(name));
2404        }
2405    }
2406    xmlXPathFreeObject(cur);
2407}
2408
2409/**
2410 * xmlXPathStringFunction:
2411 * @ctxt:  the XPath Parser context
2412 *
2413 * Implement the string() XPath function
2414 * he string function converts an object to a string as follows:
2415 *    - A node-set is converted to a string by returning the value of
2416 *      the node in the node-set that is first in document order.
2417 *      If the node-set is empty, an empty string is returned.
2418 *    - A number is converted to a string as follows
2419 *      + NaN is converted to the string NaN
2420 *      + positive zero is converted to the string 0
2421 *      + negative zero is converted to the string 0
2422 *      + positive infinity is converted to the string Infinity
2423 *      + negative infinity is converted to the string -Infinity
2424 *      + if the number is an integer, the number is represented in
2425 *        decimal form as a Number with no decimal point and no leading
2426 *        zeros, preceded by a minus sign (-) if the number is negative
2427 *      + otherwise, the number is represented in decimal form as a
2428 *        Number including a decimal point with at least one digit
2429 *        before the decimal point and at least one digit after the
2430 *        decimal point, preceded by a minus sign (-) if the number
2431 *        is negative; there must be no leading zeros before the decimal
2432 *        point apart possibly from the one required digit immediatelyi
2433 *        before the decimal point; beyond the one required digit
2434 *        after the decimal point there must be as many, but only as
2435 *        many, more digits as are needed to uniquely distinguish the
2436 *        number from all other IEEE 754 numeric values.
2437 *    - The boolean false value is converted to the string false.
2438 *      The boolean true value is converted to the string true.
2439 */
2440void
2441xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2442    xmlXPathObjectPtr cur;
2443
2444    CHECK_ARITY(1);
2445    cur = valuePop(ctxt);
2446    if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2447    switch (cur->type) {
2448        case XPATH_NODESET:
2449	    if (cur->nodesetval->nodeNr == 0) {
2450		valuePush(ctxt, xmlXPathNewCString(""));
2451	    } else {
2452		xmlChar *res;
2453	        int i = 0; /* Should be first in document order !!!!! */
2454		res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
2455		valuePush(ctxt, xmlXPathNewString(res));
2456		xmlFree(res);
2457	    }
2458	    xmlXPathFreeObject(cur);
2459	    return;
2460	case XPATH_STRING:
2461	    valuePush(ctxt, cur);
2462	    return;
2463        case XPATH_BOOLEAN:
2464	    if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
2465	    else valuePush(ctxt, xmlXPathNewCString("false"));
2466	    xmlXPathFreeObject(cur);
2467	    return;
2468	case XPATH_NUMBER: {
2469	    char buf[100];
2470
2471	    if (isnan(cur->floatval))
2472	        sprintf(buf, "NaN");
2473	    else if (isinf(cur->floatval) > 0)
2474	        sprintf(buf, "+Infinity");
2475	    else if (isinf(cur->floatval) < 0)
2476	        sprintf(buf, "-Infinity");
2477	    else
2478		sprintf(buf, "%0g", cur->floatval);
2479	    valuePush(ctxt, xmlXPathNewCString(buf));
2480	    xmlXPathFreeObject(cur);
2481	    return;
2482	}
2483    }
2484    STRANGE
2485}
2486
2487/**
2488 * xmlXPathStringLengthFunction:
2489 * @ctxt:  the XPath Parser context
2490 *
2491 * Implement the string-length() XPath function
2492 * The string-length returns the number of characters in the string
2493 * (see [3.6 Strings]). If the argument is omitted, it defaults to
2494 * the context node converted to a string, in other words the value
2495 * of the context node.
2496 */
2497void
2498xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2499    xmlXPathObjectPtr cur;
2500
2501    if (nargs == 0) {
2502	if (ctxt->context->node == NULL) {
2503	    valuePush(ctxt, xmlXPathNewFloat(0));
2504	} else {
2505	    xmlChar *content;
2506
2507	    content = xmlNodeGetContent(ctxt->context->node);
2508	    valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
2509	    xmlFree(content);
2510	}
2511	return;
2512    }
2513    CHECK_ARITY(1);
2514    CHECK_TYPE(XPATH_STRING);
2515    cur = valuePop(ctxt);
2516    valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
2517    xmlXPathFreeObject(cur);
2518}
2519
2520/**
2521 * xmlXPathConcatFunction:
2522 * @ctxt:  the XPath Parser context
2523 *
2524 * Implement the concat() XPath function
2525 * The concat function returns the concatenation of its arguments.
2526 */
2527void
2528xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2529    xmlXPathObjectPtr cur, new;
2530    xmlChar *tmp;
2531
2532    if (nargs < 2) {
2533	CHECK_ARITY(2);
2534    }
2535
2536    cur = valuePop(ctxt);
2537    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
2538        xmlXPathFreeObject(cur);
2539	return;
2540    }
2541    nargs--;
2542
2543    while (nargs > 0) {
2544	new = valuePop(ctxt);
2545	if ((new == NULL) || (new->type != XPATH_STRING)) {
2546	    xmlXPathFreeObject(new);
2547	    xmlXPathFreeObject(cur);
2548	    ERROR(XPATH_INVALID_TYPE);
2549	}
2550	tmp = xmlStrcat(new->stringval, cur->stringval);
2551	new->stringval = cur->stringval;
2552	cur->stringval = tmp;
2553
2554	xmlXPathFreeObject(new);
2555	nargs--;
2556    }
2557    valuePush(ctxt, cur);
2558}
2559
2560/**
2561 * xmlXPathContainsFunction:
2562 * @ctxt:  the XPath Parser context
2563 *
2564 * Implement the contains() XPath function
2565 * The contains function returns true if the first argument string
2566 * contains the second argument string, and otherwise returns false.
2567 */
2568void
2569xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2570    xmlXPathObjectPtr hay, needle;
2571
2572    CHECK_ARITY(2);
2573    CHECK_TYPE(XPATH_STRING);
2574    needle = valuePop(ctxt);
2575    hay = valuePop(ctxt);
2576    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2577        xmlXPathFreeObject(hay);
2578        xmlXPathFreeObject(needle);
2579	ERROR(XPATH_INVALID_TYPE);
2580    }
2581    if (xmlStrstr(hay->stringval, needle->stringval))
2582        valuePush(ctxt, xmlXPathNewBoolean(1));
2583    else
2584        valuePush(ctxt, xmlXPathNewBoolean(0));
2585    xmlXPathFreeObject(hay);
2586    xmlXPathFreeObject(needle);
2587}
2588
2589/**
2590 * xmlXPathStartsWithFunction:
2591 * @ctxt:  the XPath Parser context
2592 *
2593 * Implement the starts-with() XPath function
2594 * The starts-with function returns true if the first argument string
2595 * starts with the second argument string, and otherwise returns false.
2596 */
2597void
2598xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2599    xmlXPathObjectPtr hay, needle;
2600    int n;
2601
2602    CHECK_ARITY(2);
2603    CHECK_TYPE(XPATH_STRING);
2604    needle = valuePop(ctxt);
2605    hay = valuePop(ctxt);
2606    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2607        xmlXPathFreeObject(hay);
2608        xmlXPathFreeObject(needle);
2609	ERROR(XPATH_INVALID_TYPE);
2610    }
2611    n = xmlStrlen(needle->stringval);
2612    if (xmlStrncmp(hay->stringval, needle->stringval, n))
2613        valuePush(ctxt, xmlXPathNewBoolean(0));
2614    else
2615        valuePush(ctxt, xmlXPathNewBoolean(1));
2616    xmlXPathFreeObject(hay);
2617    xmlXPathFreeObject(needle);
2618}
2619
2620/**
2621 * xmlXPathSubstringFunction:
2622 * @ctxt:  the XPath Parser context
2623 *
2624 * Implement the substring() XPath function
2625 * The substring function returns the substring of the first argument
2626 * starting at the position specified in the second argument with
2627 * length specified in the third argument. For example,
2628 * substring("12345",2,3) returns "234". If the third argument is not
2629 * specified, it returns the substring starting at the position specified
2630 * in the second argument and continuing to the end of the string. For
2631 * example, substring("12345",2) returns "2345".  More precisely, each
2632 * character in the string (see [3.6 Strings]) is considered to have a
2633 * numeric position: the position of the first character is 1, the position
2634 * of the second character is 2 and so on. The returned substring contains
2635 * those characters for which the position of the character is greater than
2636 * or equal to the second argument and, if the third argument is specified,
2637 * less than the sum of the second and third arguments; the comparisons
2638 * and addition used for the above follow the standard IEEE 754 rules. Thus:
2639 *  - substring("12345", 1.5, 2.6) returns "234"
2640 *  - substring("12345", 0, 3) returns "12"
2641 *  - substring("12345", 0 div 0, 3) returns ""
2642 *  - substring("12345", 1, 0 div 0) returns ""
2643 *  - substring("12345", -42, 1 div 0) returns "12345"
2644 *  - substring("12345", -1 div 0, 1 div 0) returns ""
2645 */
2646void
2647xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2648    xmlXPathObjectPtr str, start, len;
2649    double le, in;
2650    int i, l;
2651    xmlChar *ret;
2652
2653    /*
2654     * Conformance needs to be checked !!!!!
2655     */
2656    if (nargs < 2) {
2657	CHECK_ARITY(2);
2658    }
2659    if (nargs > 3) {
2660	CHECK_ARITY(3);
2661    }
2662    if (nargs == 3) {
2663	CHECK_TYPE(XPATH_NUMBER);
2664	len = valuePop(ctxt);
2665	le = len->floatval;
2666        xmlXPathFreeObject(len);
2667    } else {
2668	le = 2000000000;
2669    }
2670    CHECK_TYPE(XPATH_NUMBER);
2671    start = valuePop(ctxt);
2672    in = start->floatval;
2673    xmlXPathFreeObject(start);
2674    CHECK_TYPE(XPATH_STRING);
2675    str = valuePop(ctxt);
2676    le += in;
2677
2678    /* integer index of the first char */
2679    i = in;
2680    if (((double)i) != in) i++;
2681
2682    /* integer index of the last char */
2683    l = le;
2684    if (((double)l) != le) l++;
2685
2686    /* back to a zero based len */
2687    i--;
2688    l--;
2689
2690    /* check against the string len */
2691    if (l > 1024) {
2692        l = xmlStrlen(str->stringval);
2693    }
2694    if (i < 0) {
2695        i = 0;
2696    }
2697
2698    /* number of chars to copy */
2699    l -= i;
2700
2701    ret = xmlStrsub(str->stringval, i, l);
2702    if (ret == NULL)
2703	valuePush(ctxt, xmlXPathNewCString(""));
2704    else {
2705	valuePush(ctxt, xmlXPathNewString(ret));
2706	xmlFree(ret);
2707    }
2708    xmlXPathFreeObject(str);
2709}
2710
2711/**
2712 * xmlXPathSubstringBeforeFunction:
2713 * @ctxt:  the XPath Parser context
2714 *
2715 * Implement the substring-before() XPath function
2716 * The substring-before function returns the substring of the first
2717 * argument string that precedes the first occurrence of the second
2718 * argument string in the first argument string, or the empty string
2719 * if the first argument string does not contain the second argument
2720 * string. For example, substring-before("1999/04/01","/") returns 1999.
2721 */
2722void
2723xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2724    CHECK_ARITY(2);
2725    TODO /* substring before */
2726}
2727
2728/**
2729 * xmlXPathSubstringAfterFunction:
2730 * @ctxt:  the XPath Parser context
2731 *
2732 * Implement the substring-after() XPath function
2733 * The substring-after function returns the substring of the first
2734 * argument string that follows the first occurrence of the second
2735 * argument string in the first argument string, or the empty stringi
2736 * if the first argument string does not contain the second argument
2737 * string. For example, substring-after("1999/04/01","/") returns 04/01,
2738 * and substring-after("1999/04/01","19") returns 99/04/01.
2739 */
2740void
2741xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2742    CHECK_ARITY(2);
2743    TODO /* substring after */
2744}
2745
2746/**
2747 * xmlXPathNormalizeFunction:
2748 * @ctxt:  the XPath Parser context
2749 *
2750 * Implement the normalize() XPath function
2751 * The normalize function returns the argument string with white
2752 * space normalized by stripping leading and trailing whitespace
2753 * and replacing sequences of whitespace characters by a single
2754 * space. Whitespace characters are the same allowed by the S production
2755 * in XML. If the argument is omitted, it defaults to the context
2756 * node converted to a string, in other words the value of the context node.
2757 */
2758void
2759xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2760    CHECK_ARITY(1);
2761    TODO /* normalize isn't as boring as translate, but pretty much */
2762}
2763
2764/**
2765 * xmlXPathTranslateFunction:
2766 * @ctxt:  the XPath Parser context
2767 *
2768 * Implement the translate() XPath function
2769 * The translate function returns the first argument string with
2770 * occurrences of characters in the second argument string replaced
2771 * by the character at the corresponding position in the third argument
2772 * string. For example, translate("bar","abc","ABC") returns the string
2773 * BAr. If there is a character in the second argument string with no
2774 * character at a corresponding position in the third argument string
2775 * (because the second argument string is longer than the third argument
2776 * string), then occurrences of that character in the first argument
2777 * string are removed. For example, translate("--aaa--","abc-","ABC")
2778 * returns "AAA". If a character occurs more than once in second
2779 * argument string, then the first occurrence determines the replacement
2780 * character. If the third argument string is longer than the second
2781 * argument string, then excess characters are ignored.
2782 */
2783void
2784xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2785    CHECK_ARITY(3);
2786    TODO /* translate is boring, waiting for UTF-8 representation too */
2787}
2788
2789/**
2790 * xmlXPathBooleanFunction:
2791 * @ctxt:  the XPath Parser context
2792 *
2793 * Implement the boolean() XPath function
2794 * he boolean function converts its argument to a boolean as follows:
2795 *    - a number is true if and only if it is neither positive or
2796 *      negative zero nor NaN
2797 *    - a node-set is true if and only if it is non-empty
2798 *    - a string is true if and only if its length is non-zero
2799 */
2800void
2801xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2802    xmlXPathObjectPtr cur;
2803    int res = 0;
2804
2805    CHECK_ARITY(1);
2806    cur = valuePop(ctxt);
2807    if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2808    switch (cur->type) {
2809        case XPATH_NODESET:
2810	    if ((cur->nodesetval == NULL) ||
2811	        (cur->nodesetval->nodeNr == 0)) res = 0;
2812	    else
2813	        res = 1;
2814	    break;
2815	case XPATH_STRING:
2816	    if ((cur->stringval == NULL) ||
2817	        (cur->stringval[0] == 0)) res = 0;
2818	    else
2819	        res = 1;
2820	    break;
2821        case XPATH_BOOLEAN:
2822	    valuePush(ctxt, cur);
2823	    return;
2824	case XPATH_NUMBER:
2825	    if (cur->floatval) res = 1;
2826	    break;
2827	default:
2828	    STRANGE
2829    }
2830    xmlXPathFreeObject(cur);
2831    valuePush(ctxt, xmlXPathNewBoolean(res));
2832}
2833
2834/**
2835 * xmlXPathNotFunction:
2836 * @ctxt:  the XPath Parser context
2837 *
2838 * Implement the not() XPath function
2839 * The not function returns true if its argument is false,
2840 * and false otherwise.
2841 */
2842void
2843xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2844    CHECK_ARITY(1);
2845    CHECK_TYPE(XPATH_BOOLEAN);
2846    ctxt->value->boolval = ! ctxt->value->boolval;
2847}
2848
2849/**
2850 * xmlXPathTrueFunction:
2851 * @ctxt:  the XPath Parser context
2852 *
2853 * Implement the true() XPath function
2854 */
2855void
2856xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2857    CHECK_ARITY(0);
2858    valuePush(ctxt, xmlXPathNewBoolean(1));
2859}
2860
2861/**
2862 * xmlXPathFalseFunction:
2863 * @ctxt:  the XPath Parser context
2864 *
2865 * Implement the false() XPath function
2866 */
2867void
2868xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2869    CHECK_ARITY(0);
2870    valuePush(ctxt, xmlXPathNewBoolean(0));
2871}
2872
2873/**
2874 * xmlXPathLangFunction:
2875 * @ctxt:  the XPath Parser context
2876 *
2877 * Implement the lang() XPath function
2878 * The lang function returns true or false depending on whether the
2879 * language of the context node as specified by xml:lang attributes
2880 * is the same as or is a sublanguage of the language specified by
2881 * the argument string. The language of the context node is determined
2882 * by the value of the xml:lang attribute on the context node, or, if
2883 * the context node has no xml:lang attribute, by the value of the
2884 * xml:lang attribute on the nearest ancestor of the context node that
2885 * has an xml:lang attribute. If there is no such attribute, then lang
2886 * returns false. If there is such an attribute, then lang returns
2887 * true if the attribute value is equal to the argument ignoring case,
2888 * or if there is some suffix starting with - such that the attribute
2889 * value is equal to the argument ignoring that suffix of the attribute
2890 * value and ignoring case.
2891 */
2892void
2893xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2894    xmlXPathObjectPtr val;
2895    const xmlChar *theLang;
2896    const xmlChar *lang;
2897    int ret = 0;
2898    int i;
2899
2900    CHECK_ARITY(1);
2901    CHECK_TYPE(XPATH_STRING);
2902    val = valuePop(ctxt);
2903    lang = val->stringval;
2904    theLang = xmlNodeGetLang(ctxt->context->node);
2905    if ((theLang != NULL) && (lang != NULL)) {
2906        for (i = 0;lang[i] != 0;i++)
2907	    if (toupper(lang[i]) != toupper(theLang[i]))
2908	        goto not_equal;
2909        ret = 1;
2910    }
2911not_equal:
2912    xmlXPathFreeObject(val);
2913    valuePush(ctxt, xmlXPathNewBoolean(ret));
2914}
2915
2916/**
2917 * xmlXPathNumberFunction:
2918 * @ctxt:  the XPath Parser context
2919 *
2920 * Implement the number() XPath function
2921 */
2922void
2923xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2924    xmlXPathObjectPtr cur;
2925    double res;
2926
2927    CHECK_ARITY(1);
2928    cur = valuePop(ctxt);
2929    switch (cur->type) {
2930        case XPATH_NODESET:
2931	    valuePush(ctxt, cur);
2932	    xmlXPathStringFunction(ctxt, 1);
2933	    cur = valuePop(ctxt);
2934	case XPATH_STRING:
2935	    res = xmlXPathStringEvalNumber(cur->stringval);
2936	    valuePush(ctxt, xmlXPathNewFloat(res));
2937	    xmlXPathFreeObject(cur);
2938	    return;
2939        case XPATH_BOOLEAN:
2940	    if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
2941	    else valuePush(ctxt, xmlXPathNewFloat(0.0));
2942	    xmlXPathFreeObject(cur);
2943	    return;
2944	case XPATH_NUMBER:
2945	    valuePush(ctxt, cur);
2946	    return;
2947    }
2948    STRANGE
2949}
2950
2951/**
2952 * xmlXPathSumFunction:
2953 * @ctxt:  the XPath Parser context
2954 *
2955 * Implement the sum() XPath function
2956 * The sum function returns the sum of the values of the nodes in
2957 * the argument node-set.
2958 */
2959void
2960xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2961    CHECK_ARITY(1);
2962    TODO /* BUG Sum : don't understand the definition */
2963}
2964
2965/**
2966 * xmlXPathFloorFunction:
2967 * @ctxt:  the XPath Parser context
2968 *
2969 * Implement the floor() XPath function
2970 * The floor function returns the largest (closest to positive infinity)
2971 * number that is not greater than the argument and that is an integer.
2972 */
2973void
2974xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2975    CHECK_ARITY(1);
2976    CHECK_TYPE(XPATH_NUMBER);
2977    /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
2978    ctxt->value->floatval = (double)((int) ctxt->value->floatval);
2979}
2980
2981/**
2982 * xmlXPathCeilingFunction:
2983 * @ctxt:  the XPath Parser context
2984 *
2985 * Implement the ceiling() XPath function
2986 * The ceiling function returns the smallest (closest to negative infinity)
2987 * number that is not less than the argument and that is an integer.
2988 */
2989void
2990xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2991    double f;
2992
2993    CHECK_ARITY(1);
2994    CHECK_TYPE(XPATH_NUMBER);
2995    f = (double)((int) ctxt->value->floatval);
2996    if (f != ctxt->value->floatval)
2997	ctxt->value->floatval = f + 1;
2998}
2999
3000/**
3001 * xmlXPathRoundFunction:
3002 * @ctxt:  the XPath Parser context
3003 *
3004 * Implement the round() XPath function
3005 * The round function returns the number that is closest to the
3006 * argument and that is an integer. If there are two such numbers,
3007 * then the one that is even is returned.
3008 */
3009void
3010xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3011    double f;
3012
3013    CHECK_ARITY(1);
3014    CHECK_TYPE(XPATH_NUMBER);
3015    /* round(0.50000001) => 0  !!!!! */
3016    f = (double)((int) ctxt->value->floatval);
3017    if (ctxt->value->floatval < f + 0.5)
3018        ctxt->value->floatval = f;
3019    else if (ctxt->value->floatval == f + 0.5)
3020        ctxt->value->floatval = f; /* !!!! Not following the spec here */
3021    else
3022        ctxt->value->floatval = f + 1;
3023}
3024
3025/************************************************************************
3026 *									*
3027 *			The Parser					*
3028 *									*
3029 ************************************************************************/
3030
3031/*
3032 * a couple of forward declarations since we use a recursive call based
3033 * implementation.
3034 */
3035void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
3036void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
3037void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
3038void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
3039
3040/**
3041 * xmlXPathParseNCName:
3042 * @ctxt:  the XPath Parser context
3043 *
3044 * parse an XML namespace non qualified name.
3045 *
3046 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
3047 *
3048 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
3049 *                       CombiningChar | Extender
3050 *
3051 * Returns the namespace name or NULL
3052 */
3053
3054xmlChar *
3055xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
3056    const xmlChar *q;
3057    xmlChar *ret = NULL;
3058
3059    if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
3060    q = NEXT;
3061
3062    while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
3063           (CUR == '.') || (CUR == '-') ||
3064	   (CUR == '_') ||
3065	   (IS_COMBINING(CUR)) ||
3066	   (IS_EXTENDER(CUR)))
3067	NEXT;
3068
3069    ret = xmlStrndup(q, CUR_PTR - q);
3070
3071    return(ret);
3072}
3073
3074/**
3075 * xmlXPathParseQName:
3076 * @ctxt:  the XPath Parser context
3077 * @prefix:  a xmlChar **
3078 *
3079 * parse an XML qualified name
3080 *
3081 * [NS 5] QName ::= (Prefix ':')? LocalPart
3082 *
3083 * [NS 6] Prefix ::= NCName
3084 *
3085 * [NS 7] LocalPart ::= NCName
3086 *
3087 * Returns the function returns the local part, and prefix is updated
3088 *   to get the Prefix if any.
3089 */
3090
3091xmlChar *
3092xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
3093    xmlChar *ret = NULL;
3094
3095    *prefix = NULL;
3096    ret = xmlXPathParseNCName(ctxt);
3097    if (CUR == ':') {
3098        *prefix = ret;
3099	NEXT;
3100	ret = xmlXPathParseNCName(ctxt);
3101    }
3102    return(ret);
3103}
3104
3105/**
3106 * xmlXPathStringEvalNumber:
3107 * @str:  A string to scan
3108 *
3109 *  [30]   Number ::=   Digits ('.' Digits)?
3110 *                    | '.' Digits
3111 *  [31]   Digits ::=   [0-9]+
3112 *
3113 * Parse and evaluate a Number in the string
3114 *
3115 * BUG: "1.' is not valid ... James promised correction
3116 *       as Digits ('.' Digits?)?
3117 *
3118 * Returns the double value.
3119 */
3120double
3121xmlXPathStringEvalNumber(const xmlChar *str) {
3122    const xmlChar *cur = str;
3123    double ret = 0.0;
3124    double mult = 1;
3125    int ok = 0;
3126
3127    while (*cur == ' ') cur++;
3128    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
3129        return(xmlXPathNAN);
3130    }
3131    while ((*cur >= '0') && (*cur <= '9')) {
3132        ret = ret * 10 + (*cur - '0');
3133	ok = 1;
3134	cur++;
3135    }
3136    if (*cur == '.') {
3137        cur++;
3138	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
3139	    return(xmlXPathNAN);
3140	}
3141	while ((*cur >= '0') && (*cur <= '9')) {
3142	    mult /= 10;
3143	    ret = ret  + (*cur - '0') * mult;
3144	    cur++;
3145	}
3146    }
3147    while (*cur == ' ') cur++;
3148    if (*cur != 0) return(xmlXPathNAN);
3149    return(ret);
3150}
3151
3152/**
3153 * xmlXPathEvalNumber:
3154 * @ctxt:  the XPath Parser context
3155 *
3156 *  [30]   Number ::=   Digits ('.' Digits)?
3157 *                    | '.' Digits
3158 *  [31]   Digits ::=   [0-9]+
3159 *
3160 * Parse and evaluate a Number, then push it on the stack
3161 *
3162 * BUG: "1.' is not valid ... James promised correction
3163 *       as Digits ('.' Digits?)?
3164 */
3165void
3166xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
3167    double ret = 0.0;
3168    double mult = 1;
3169    int ok = 0;
3170
3171    CHECK_ERROR;
3172    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
3173        ERROR(XPATH_NUMBER_ERROR);
3174    }
3175    while ((CUR >= '0') && (CUR <= '9')) {
3176        ret = ret * 10 + (CUR - '0');
3177	ok = 1;
3178	NEXT;
3179    }
3180    if (CUR == '.') {
3181        NEXT;
3182	if (((CUR < '0') || (CUR > '9')) && (!ok)) {
3183	     ERROR(XPATH_NUMBER_ERROR);
3184	}
3185	while ((CUR >= '0') && (CUR <= '9')) {
3186	    mult /= 10;
3187	    ret = ret  + (CUR - '0') * mult;
3188	    NEXT;
3189	}
3190    }
3191    valuePush(ctxt, xmlXPathNewFloat(ret));
3192}
3193
3194/**
3195 * xmlXPathEvalLiteral:
3196 * @ctxt:  the XPath Parser context
3197 *
3198 * Parse a Literal and push it on the stack.
3199 *
3200 *  [29]   Literal ::=   '"' [^"]* '"'
3201 *                    | "'" [^']* "'"
3202 *
3203 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
3204 */
3205void
3206xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
3207    const xmlChar *q;
3208    xmlChar *ret = NULL;
3209
3210    if (CUR == '"') {
3211        NEXT;
3212	q = CUR_PTR;
3213	while ((IS_CHAR(CUR)) && (CUR != '"'))
3214	    NEXT;
3215	if (!IS_CHAR(CUR)) {
3216	    ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3217	} else {
3218	    ret = xmlStrndup(q, CUR_PTR - q);
3219	    NEXT;
3220        }
3221    } else if (CUR == '\'') {
3222        NEXT;
3223	q = CUR_PTR;
3224	while ((IS_CHAR(CUR)) && (CUR != '\''))
3225	    NEXT;
3226	if (!IS_CHAR(CUR)) {
3227	    ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3228	} else {
3229	    ret = xmlStrndup(q, CUR_PTR - q);
3230	    NEXT;
3231        }
3232    } else {
3233	ERROR(XPATH_START_LITERAL_ERROR);
3234    }
3235    if (ret == NULL) return;
3236    valuePush(ctxt, xmlXPathNewString(ret));
3237    xmlFree(ret);
3238}
3239
3240/**
3241 * xmlXPathEvalVariableReference:
3242 * @ctxt:  the XPath Parser context
3243 *
3244 * Parse a VariableReference, evaluate it and push it on the stack.
3245 *
3246 * The variable bindings consist of a mapping from variable names
3247 * to variable values. The value of a variable is an object, which
3248 * of any of the types that are possible for the value of an expression,
3249 * and may also be of additional types not specified here.
3250 *
3251 * Early evaluation is possible since:
3252 * The variable bindings [...] used to evaluate a subexpression are
3253 * always the same as those used to evaluate the containing expression.
3254 *
3255 *  [36]   VariableReference ::=   '$' QName
3256 */
3257void
3258xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
3259    xmlChar *name;
3260    xmlChar *prefix;
3261    xmlXPathObjectPtr value;
3262
3263    if (CUR != '$') {
3264	ERROR(XPATH_VARIABLE_REF_ERROR);
3265    }
3266    name = xmlXPathParseQName(ctxt, &prefix);
3267    if (name == NULL) {
3268	ERROR(XPATH_VARIABLE_REF_ERROR);
3269    }
3270    value = xmlXPathVariablelookup(ctxt, prefix, name);
3271    if (value == NULL) {
3272	ERROR(XPATH_UNDEF_VARIABLE_ERROR);
3273    }
3274    valuePush(ctxt, value);
3275    if (prefix != NULL) xmlFree(prefix);
3276    xmlFree(name);
3277}
3278
3279
3280/**
3281 * xmlXPathFunctionLookup:
3282 * @ctxt:  the XPath Parser context
3283 * @name:  a name string
3284 *
3285 * Search for a function of the given name
3286 *
3287 *  [35]   FunctionName ::=   QName - NodeType
3288 *
3289 * TODO: for the moment the function list is hardcoded from the spec !!!!
3290 *
3291 * Returns the xmlXPathFunction if found, or NULL otherwise
3292 */
3293xmlXPathFunction
3294xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
3295    switch (name[0]) {
3296        case 'b':
3297	    if (!xmlStrcmp(name, BAD_CAST "boolean"))
3298	        return(xmlXPathBooleanFunction);
3299	    break;
3300        case 'c':
3301	    if (!xmlStrcmp(name, BAD_CAST "ceiling"))
3302	        return(xmlXPathCeilingFunction);
3303	    if (!xmlStrcmp(name, BAD_CAST "count"))
3304	        return(xmlXPathCountFunction);
3305	    if (!xmlStrcmp(name, BAD_CAST "concat"))
3306	        return(xmlXPathConcatFunction);
3307	    if (!xmlStrcmp(name, BAD_CAST "contains"))
3308	        return(xmlXPathContainsFunction);
3309	    break;
3310        case 'i':
3311	    if (!xmlStrcmp(name, BAD_CAST "id"))
3312	        return(xmlXPathIdFunction);
3313	    break;
3314        case 'f':
3315	    if (!xmlStrcmp(name, BAD_CAST "false"))
3316	        return(xmlXPathFalseFunction);
3317	    if (!xmlStrcmp(name, BAD_CAST "floor"))
3318	        return(xmlXPathFloorFunction);
3319	    break;
3320        case 'l':
3321	    if (!xmlStrcmp(name, BAD_CAST "last"))
3322	        return(xmlXPathLastFunction);
3323	    if (!xmlStrcmp(name, BAD_CAST "lang"))
3324	        return(xmlXPathLangFunction);
3325	    if (!xmlStrcmp(name, BAD_CAST "local-part"))
3326	        return(xmlXPathLocalPartFunction);
3327	    break;
3328        case 'n':
3329	    if (!xmlStrcmp(name, BAD_CAST "not"))
3330	        return(xmlXPathNotFunction);
3331	    if (!xmlStrcmp(name, BAD_CAST "name"))
3332	        return(xmlXPathNameFunction);
3333	    if (!xmlStrcmp(name, BAD_CAST "namespace"))
3334	        return(xmlXPathNamespaceFunction);
3335	    if (!xmlStrcmp(name, BAD_CAST "normalize-space"))
3336	        return(xmlXPathNormalizeFunction);
3337	    if (!xmlStrcmp(name, BAD_CAST "normalize"))
3338	        return(xmlXPathNormalizeFunction);
3339	    if (!xmlStrcmp(name, BAD_CAST "number"))
3340	        return(xmlXPathNumberFunction);
3341	    break;
3342        case 'p':
3343	    if (!xmlStrcmp(name, BAD_CAST "position"))
3344	        return(xmlXPathPositionFunction);
3345	    break;
3346        case 'r':
3347	    if (!xmlStrcmp(name, BAD_CAST "round"))
3348	        return(xmlXPathRoundFunction);
3349	    break;
3350        case 's':
3351	    if (!xmlStrcmp(name, BAD_CAST "string"))
3352	        return(xmlXPathStringFunction);
3353	    if (!xmlStrcmp(name, BAD_CAST "string-length"))
3354	        return(xmlXPathStringLengthFunction);
3355	    if (!xmlStrcmp(name, BAD_CAST "starts-with"))
3356	        return(xmlXPathStartsWithFunction);
3357	    if (!xmlStrcmp(name, BAD_CAST "substring"))
3358	        return(xmlXPathSubstringFunction);
3359	    if (!xmlStrcmp(name, BAD_CAST "substring-before"))
3360	        return(xmlXPathSubstringBeforeFunction);
3361	    if (!xmlStrcmp(name, BAD_CAST "substring-after"))
3362	        return(xmlXPathSubstringAfterFunction);
3363	    if (!xmlStrcmp(name, BAD_CAST "sum"))
3364	        return(xmlXPathSumFunction);
3365	    break;
3366        case 't':
3367	    if (!xmlStrcmp(name, BAD_CAST "true"))
3368	        return(xmlXPathTrueFunction);
3369	    if (!xmlStrcmp(name, BAD_CAST "translate"))
3370	        return(xmlXPathTranslateFunction);
3371	    break;
3372    }
3373    return(NULL);
3374}
3375
3376/**
3377 * xmlXPathEvalLocationPathName:
3378 * @ctxt:  the XPath Parser context
3379 * @name:  a name string
3380 *
3381 * Various names in the beginning of a LocationPath expression
3382 * indicate whether that's an Axis, a node type,
3383 *
3384 *  [6]   AxisName ::=   'ancestor'
3385 *               | 'ancestor-or-self'
3386 *               | 'attribute'
3387 *               | 'child'
3388 *               | 'descendant'
3389 *               | 'descendant-or-self'
3390 *               | 'following'
3391 *               | 'following-sibling'
3392 *               | 'namespace'
3393 *               | 'parent'
3394 *               | 'preceding'
3395 *               | 'preceding-sibling'
3396 *               | 'self'
3397 *  [38]   NodeType ::=   'comment'
3398 *                    | 'text'
3399 *                    | 'processing-instruction'
3400 *                    | 'node'
3401 */
3402int
3403xmlXPathGetNameType(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
3404    switch (name[0]) {
3405        case 'a':
3406	    if (!xmlStrcmp(name, BAD_CAST "ancestor")) return(AXIS_ANCESTOR);
3407	    if (!xmlStrcmp(name, BAD_CAST "ancestor-or-self"))
3408	        return(AXIS_ANCESTOR_OR_SELF);
3409            if (!xmlStrcmp(name, BAD_CAST "attribute")) return(AXIS_ATTRIBUTE);
3410	    break;
3411        case 'c':
3412            if (!xmlStrcmp(name, BAD_CAST "child")) return(AXIS_CHILD);
3413            if (!xmlStrcmp(name, BAD_CAST "comment")) return(NODE_TYPE_COMMENT);
3414	    break;
3415        case 'd':
3416            if (!xmlStrcmp(name, BAD_CAST "descendant"))
3417	        return(AXIS_DESCENDANT);
3418            if (!xmlStrcmp(name, BAD_CAST "descendant-or-self"))
3419	        return(AXIS_DESCENDANT_OR_SELF);
3420	    break;
3421        case 'f':
3422            if (!xmlStrcmp(name, BAD_CAST "following")) return(AXIS_FOLLOWING);
3423            if (!xmlStrcmp(name, BAD_CAST "following-sibling"))
3424	        return(AXIS_FOLLOWING_SIBLING);
3425	    break;
3426        case 'n':
3427            if (!xmlStrcmp(name, BAD_CAST "namespace")) return(AXIS_NAMESPACE);
3428            if (!xmlStrcmp(name, BAD_CAST "node")) return(NODE_TYPE_NODE);
3429	    break;
3430        case 'p':
3431            if (!xmlStrcmp(name, BAD_CAST "parent")) return(AXIS_PARENT);
3432            if (!xmlStrcmp(name, BAD_CAST "preceding")) return(AXIS_PRECEDING);
3433            if (!xmlStrcmp(name, BAD_CAST "preceding-sibling"))
3434	        return(AXIS_PRECEDING_SIBLING);
3435            if (!xmlStrcmp(name, BAD_CAST "processing-instruction"))
3436	        return(NODE_TYPE_PI);
3437	    break;
3438        case 's':
3439            if (!xmlStrcmp(name, BAD_CAST "self")) return(AXIS_SELF);
3440	    break;
3441        case 't':
3442            if (!xmlStrcmp(name, BAD_CAST "text")) return(NODE_TYPE_TEXT);
3443	    break;
3444    }
3445    if (xmlXPathIsFunction(ctxt, name)) return(IS_FUNCTION);
3446    return(0);
3447}
3448
3449/**
3450 * xmlXPathEvalFunctionCall:
3451 * @ctxt:  the XPath Parser context
3452 *
3453 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
3454 *  [17]   Argument ::=   Expr
3455 *
3456 * Parse and evaluate a function call, the evaluation of all arguments are
3457 * pushed on the stack
3458 */
3459void
3460xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
3461    xmlChar *name;
3462    xmlChar *prefix;
3463    xmlXPathFunction func;
3464    int nbargs = 0;
3465
3466    name = xmlXPathParseQName(ctxt, &prefix);
3467    if (name == NULL) {
3468	ERROR(XPATH_EXPR_ERROR);
3469    }
3470    SKIP_BLANKS;
3471    func = xmlXPathIsFunction(ctxt, name);
3472    if (func == NULL) {
3473        xmlFree(name);
3474	ERROR(XPATH_UNKNOWN_FUNC_ERROR);
3475    }
3476#ifdef DEBUG_EXPR
3477    fprintf(xmlXPathDebug, "Calling function %s\n", name);
3478#endif
3479
3480    if (CUR != '(') {
3481        xmlFree(name);
3482	ERROR(XPATH_EXPR_ERROR);
3483    }
3484    NEXT;
3485    SKIP_BLANKS;
3486
3487    while (CUR != ')') {
3488        xmlXPathEvalExpr(ctxt);
3489	nbargs++;
3490	if (CUR == ')') break;
3491	if (CUR != ',') {
3492	    xmlFree(name);
3493	    ERROR(XPATH_EXPR_ERROR);
3494	}
3495	NEXT;
3496	SKIP_BLANKS;
3497    }
3498    NEXT;
3499    SKIP_BLANKS;
3500    xmlFree(name);
3501    func(ctxt, nbargs);
3502}
3503
3504/**
3505 * xmlXPathEvalPrimaryExpr:
3506 * @ctxt:  the XPath Parser context
3507 *
3508 *  [15]   PrimaryExpr ::=   VariableReference
3509 *                | '(' Expr ')'
3510 *                | Literal
3511 *                | Number
3512 *                | FunctionCall
3513 *
3514 * Parse and evaluate a primary expression, then push the result on the stack
3515 */
3516void
3517xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
3518    SKIP_BLANKS;
3519    if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
3520    else if (CUR == '(') {
3521        NEXT;
3522	SKIP_BLANKS;
3523        xmlXPathEvalExpr(ctxt);
3524	if (CUR != ')') {
3525	    ERROR(XPATH_EXPR_ERROR);
3526	}
3527	NEXT;
3528	SKIP_BLANKS;
3529    } else if (IS_DIGIT(CUR)) {
3530        xmlXPathEvalNumber(ctxt);
3531    } else if ((CUR == '\'') || (CUR == '"')) {
3532        xmlXPathEvalLiteral(ctxt);
3533    } else {
3534        xmlXPathEvalFunctionCall(ctxt);
3535    }
3536}
3537
3538/**
3539 * xmlXPathEvalFilterExpr:
3540 * @ctxt:  the XPath Parser context
3541 *
3542 *  [20]   FilterExpr ::=   PrimaryExpr
3543 *               | FilterExpr Predicate
3544 *
3545 * Parse and evaluate a filter expression, then push the result on the stack
3546 * Square brackets are used to filter expressions in the same way that
3547 * they are used in location paths. It is an error if the expression to
3548 * be filtered does not evaluate to a node-set. The context node list
3549 * used for evaluating the expression in square brackets is the node-set
3550 * to be filtered listed in document order.
3551 */
3552
3553void
3554xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
3555    /****
3556    xmlNodeSetPtr oldset = NULL;
3557    xmlXPathObjectPtr arg;
3558     ****/
3559
3560    xmlXPathEvalPrimaryExpr(ctxt);
3561    CHECK_ERROR;
3562    SKIP_BLANKS;
3563
3564    if (CUR != '[') return;
3565
3566    CHECK_TYPE(XPATH_NODESET);
3567
3568    while (CUR == '[') {
3569	xmlXPathEvalPredicate(ctxt);
3570	SKIP_BLANKS;
3571    }
3572
3573
3574}
3575
3576/**
3577 * xmlXPathScanName:
3578 * @ctxt:  the XPath Parser context
3579 *
3580 * Trickery: parse an XML name but without consuming the input flow
3581 * Needed for rollback cases.
3582 *
3583 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
3584 *                  CombiningChar | Extender
3585 *
3586 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
3587 *
3588 * [6] Names ::= Name (S Name)*
3589 *
3590 * Returns the Name parsed or NULL
3591 */
3592
3593xmlChar *
3594xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
3595    xmlChar buf[XML_MAX_NAMELEN];
3596    int len = 0;
3597
3598    SKIP_BLANKS;
3599    if (!IS_LETTER(CUR) && (CUR != '_') &&
3600        (CUR != ':')) {
3601	return(NULL);
3602    }
3603
3604    while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3605           (NXT(len) == '.') || (NXT(len) == '-') ||
3606	   (NXT(len) == '_') || (NXT(len) == ':') ||
3607	   (IS_COMBINING(NXT(len))) ||
3608	   (IS_EXTENDER(NXT(len)))) {
3609	buf[len] = NXT(len);
3610	len++;
3611	if (len >= XML_MAX_NAMELEN) {
3612	    fprintf(stderr,
3613	       "xmlScanName: reached XML_MAX_NAMELEN limit\n");
3614	    while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3615		   (NXT(len) == '.') || (NXT(len) == '-') ||
3616		   (NXT(len) == '_') || (NXT(len) == ':') ||
3617		   (IS_COMBINING(NXT(len))) ||
3618		   (IS_EXTENDER(NXT(len))))
3619		 len++;
3620	    break;
3621	}
3622    }
3623    return(xmlStrndup(buf, len));
3624}
3625
3626/**
3627 * xmlXPathEvalPathExpr:
3628 * @ctxt:  the XPath Parser context
3629 *
3630 *  [19]   PathExpr ::=   LocationPath
3631 *               | FilterExpr
3632 *               | FilterExpr '/' RelativeLocationPath
3633 *               | FilterExpr '//' RelativeLocationPath
3634 *
3635 * Parse and evaluate a path expression, then push the result on the stack
3636 * The / operator and // operators combine an arbitrary expression
3637 * and a relative location path. It is an error if the expression
3638 * does not evaluate to a node-set.
3639 * The / operator does composition in the same way as when / is
3640 * used in a location path. As in location paths, // is short for
3641 * /descendant-or-self::node()/.
3642 */
3643
3644void
3645xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
3646    xmlNodeSetPtr newset = NULL;
3647
3648    SKIP_BLANKS;
3649    if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
3650        (CUR == '\'') || (CUR == '"')) {
3651	xmlXPathEvalFilterExpr(ctxt);
3652	CHECK_ERROR;
3653	if ((CUR == '/') && (NXT(1) == '/')) {
3654	    SKIP(2);
3655	    SKIP_BLANKS;
3656	    if (ctxt->context->nodelist == NULL) {
3657		STRANGE
3658		xmlXPathRoot(ctxt);
3659	    }
3660	    newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
3661			     NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
3662	    if (ctxt->context->nodelist != NULL)
3663		xmlXPathFreeNodeSet(ctxt->context->nodelist);
3664	    ctxt->context->nodelist = newset;
3665	    ctxt->context->node = NULL;
3666	    xmlXPathEvalRelativeLocationPath(ctxt);
3667	} else if (CUR == '/') {
3668	    xmlXPathEvalRelativeLocationPath(ctxt);
3669	}
3670    } else {
3671        /******* !!!!!!!!!! @attname */
3672        xmlChar *name;
3673
3674	name = xmlXPathScanName(ctxt);
3675	if ((name == NULL) || (!xmlXPathIsFunction(ctxt, name)))
3676	    xmlXPathEvalLocationPath(ctxt);
3677	else
3678	    xmlXPathEvalFilterExpr(ctxt);
3679	if (name != NULL)
3680	    xmlFree(name);
3681    }
3682}
3683
3684/**
3685 * xmlXPathEvalUnionExpr:
3686 * @ctxt:  the XPath Parser context
3687 *
3688 *  [18]   UnionExpr ::=   PathExpr
3689 *               | UnionExpr '|' PathExpr
3690 *
3691 * Parse and evaluate an union expression, then push the result on the stack
3692 */
3693
3694void
3695xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
3696    xmlXPathEvalPathExpr(ctxt);
3697    CHECK_ERROR;
3698    SKIP_BLANKS;
3699    if (CUR == '|') {
3700	xmlNodeSetPtr old = ctxt->context->nodelist;
3701
3702	NEXT;
3703	SKIP_BLANKS;
3704	xmlXPathEvalPathExpr(ctxt);
3705
3706	if (ctxt->context->nodelist == NULL)
3707	    ctxt->context->nodelist = old;
3708	else {
3709	    ctxt->context->nodelist =
3710	        xmlXPathNodeSetMerge(ctxt->context->nodelist, old);
3711	    xmlXPathFreeNodeSet(old);
3712	}
3713    }
3714}
3715
3716/**
3717 * xmlXPathEvalUnaryExpr:
3718 * @ctxt:  the XPath Parser context
3719 *
3720 *  [27]   UnaryExpr ::=   UnionExpr
3721 *                   | '-' UnaryExpr
3722 *
3723 * Parse and evaluate an unary expression, then push the result on the stack
3724 */
3725
3726void
3727xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
3728    int minus = 0;
3729
3730    SKIP_BLANKS;
3731    if (CUR == '-') {
3732        minus = 1;
3733	NEXT;
3734	SKIP_BLANKS;
3735    }
3736    xmlXPathEvalUnionExpr(ctxt);
3737    CHECK_ERROR;
3738    if (minus) {
3739        xmlXPathValueFlipSign(ctxt);
3740    }
3741}
3742
3743/**
3744 * xmlXPathEvalMultiplicativeExpr:
3745 * @ctxt:  the XPath Parser context
3746 *
3747 *  [26]   MultiplicativeExpr ::=   UnaryExpr
3748 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
3749 *                   | MultiplicativeExpr 'div' UnaryExpr
3750 *                   | MultiplicativeExpr 'mod' UnaryExpr
3751 *  [34]   MultiplyOperator ::=   '*'
3752 *
3753 * Parse and evaluate an Additive expression, then push the result on the stack
3754 */
3755
3756void
3757xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
3758    xmlXPathEvalUnaryExpr(ctxt);
3759    CHECK_ERROR;
3760    SKIP_BLANKS;
3761    while ((CUR == '*') ||
3762           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
3763           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
3764	int op = -1;
3765
3766        if (CUR == '*') {
3767	    op = 0;
3768	    NEXT;
3769	} else if (CUR == 'd') {
3770	    op = 1;
3771	    SKIP(3);
3772	} else if (CUR == 'm') {
3773	    op = 2;
3774	    SKIP(3);
3775	}
3776	SKIP_BLANKS;
3777        xmlXPathEvalUnaryExpr(ctxt);
3778	CHECK_ERROR;
3779	switch (op) {
3780	    case 0:
3781	        xmlXPathMultValues(ctxt);
3782		break;
3783	    case 1:
3784	        xmlXPathDivValues(ctxt);
3785		break;
3786	    case 2:
3787	        xmlXPathModValues(ctxt);
3788		break;
3789	}
3790    }
3791}
3792
3793/**
3794 * xmlXPathEvalAdditiveExpr:
3795 * @ctxt:  the XPath Parser context
3796 *
3797 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
3798 *                   | AdditiveExpr '+' MultiplicativeExpr
3799 *                   | AdditiveExpr '-' MultiplicativeExpr
3800 *
3801 * Parse and evaluate an Additive expression, then push the result on the stack
3802 */
3803
3804void
3805xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
3806    xmlXPathEvalMultiplicativeExpr(ctxt);
3807    CHECK_ERROR;
3808    SKIP_BLANKS;
3809    while ((CUR == '+') || (CUR == '-')) {
3810	int plus;
3811
3812        if (CUR == '+') plus = 1;
3813	else plus = 0;
3814	NEXT;
3815	SKIP_BLANKS;
3816        xmlXPathEvalMultiplicativeExpr(ctxt);
3817	CHECK_ERROR;
3818	if (plus) xmlXPathAddValues(ctxt);
3819	else xmlXPathSubValues(ctxt);
3820    }
3821}
3822
3823/**
3824 * xmlXPathEvalRelationalExpr:
3825 * @ctxt:  the XPath Parser context
3826 *
3827 *  [24]   RelationalExpr ::=   AdditiveExpr
3828 *                 | RelationalExpr '<' AdditiveExpr
3829 *                 | RelationalExpr '>' AdditiveExpr
3830 *                 | RelationalExpr '<=' AdditiveExpr
3831 *                 | RelationalExpr '>=' AdditiveExpr
3832 *
3833 *  A <= B > C is allowed ? Answer from James, yes with
3834 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
3835 *  which is basically what got implemented.
3836 *
3837 * Parse and evaluate a Relational expression, then push the result
3838 * on the stack
3839 */
3840
3841void
3842xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
3843    xmlXPathEvalAdditiveExpr(ctxt);
3844    CHECK_ERROR;
3845    SKIP_BLANKS;
3846    while ((CUR == '<') ||
3847           (CUR == '>') ||
3848           ((CUR == '<') && (NXT(1) == '=')) ||
3849           ((CUR == '>') && (NXT(1) == '='))) {
3850	int inf, strict, ret;
3851
3852        if (CUR == '<') inf = 1;
3853	else inf = 0;
3854	if (NXT(1) == '=') strict = 0;
3855	else strict = 1;
3856	NEXT;
3857	if (!strict) NEXT;
3858	SKIP_BLANKS;
3859        xmlXPathEvalAdditiveExpr(ctxt);
3860	CHECK_ERROR;
3861	ret = xmlXPathCompareValues(ctxt, inf, strict);
3862	valuePush(ctxt, xmlXPathNewBoolean(ret));
3863    }
3864}
3865
3866/**
3867 * xmlXPathEvalEqualityExpr:
3868 * @ctxt:  the XPath Parser context
3869 *
3870 *  [23]   EqualityExpr ::=   RelationalExpr
3871 *                 | EqualityExpr '=' RelationalExpr
3872 *                 | EqualityExpr '!=' RelationalExpr
3873 *
3874 *  A != B != C is allowed ? Answer from James, yes with
3875 *  (RelationalExpr = RelationalExpr) = RelationalExpr
3876 *  (RelationalExpr != RelationalExpr) != RelationalExpr
3877 *  which is basically what got implemented.
3878 *
3879 * Parse and evaluate an Equality expression, then push the result on the stack
3880 *
3881 */
3882void
3883xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
3884    xmlXPathEvalRelationalExpr(ctxt);
3885    CHECK_ERROR;
3886    SKIP_BLANKS;
3887    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
3888	xmlXPathObjectPtr res;
3889	int eq, equal;
3890
3891        if (CUR == '=') eq = 1;
3892	else eq = 0;
3893	NEXT;
3894	if (!eq) NEXT;
3895	SKIP_BLANKS;
3896        xmlXPathEvalRelationalExpr(ctxt);
3897	CHECK_ERROR;
3898	equal = xmlXPathEqualValues(ctxt);
3899	if (eq) res = xmlXPathNewBoolean(equal);
3900	else res = xmlXPathNewBoolean(!equal);
3901	valuePush(ctxt, res);
3902    }
3903}
3904
3905/**
3906 * xmlXPathEvalAndExpr:
3907 * @ctxt:  the XPath Parser context
3908 *
3909 *  [22]   AndExpr ::=   EqualityExpr
3910 *                 | AndExpr 'and' EqualityExpr
3911 *
3912 * Parse and evaluate an AND expression, then push the result on the stack
3913 *
3914 */
3915void
3916xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
3917    xmlXPathEvalEqualityExpr(ctxt);
3918    CHECK_ERROR;
3919    SKIP_BLANKS;
3920    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'n')) {
3921	xmlXPathObjectPtr arg1, arg2;
3922
3923        SKIP(3);
3924	SKIP_BLANKS;
3925        xmlXPathEvalEqualityExpr(ctxt);
3926	CHECK_ERROR;
3927	arg2 = valuePop(ctxt);
3928	arg1 = valuePop(ctxt);
3929	arg1->boolval &= arg2->boolval;
3930	valuePush(ctxt, arg1);
3931	xmlXPathFreeObject(arg2);
3932    }
3933}
3934
3935/**
3936 * xmlXPathEvalExpr:
3937 * @ctxt:  the XPath Parser context
3938 *
3939 *  [14]   Expr ::=   OrExpr
3940 *  [21]   OrExpr ::=   AndExpr
3941 *                 | OrExpr 'or' AndExpr
3942 *
3943 * Parse and evaluate an expression, then push the result on the stack
3944 *
3945 */
3946void
3947xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
3948    xmlXPathEvalAndExpr(ctxt);
3949    CHECK_ERROR;
3950    SKIP_BLANKS;
3951    while ((CUR == 'o') && (NXT(1) == 'r')) {
3952	xmlXPathObjectPtr arg1, arg2;
3953
3954        SKIP(2);
3955	SKIP_BLANKS;
3956        xmlXPathEvalAndExpr(ctxt);
3957	CHECK_ERROR;
3958	arg2 = valuePop(ctxt);
3959	arg1 = valuePop(ctxt);
3960	arg1->boolval |= arg2->boolval;
3961	valuePush(ctxt, arg1);
3962	xmlXPathFreeObject(arg2);
3963    }
3964}
3965
3966/**
3967 * xmlXPathEvaluatePredicateResult:
3968 * @ctxt:  the XPath Parser context
3969 * @res:  the Predicate Expression evaluation result
3970 * @index:  index of the current node in the current list
3971 *
3972 * Evaluate a predicate result for the current node.
3973 * A PredicateExpr is evaluated by evaluating the Expr and converting
3974 * the result to a boolean. If the result is a number, the result will
3975 * be converted to true if the number is equal to the position of the
3976 * context node in the context node list (as returned by the position
3977 * function) and will be converted to false otherwise; if the result
3978 * is not a number, then the result will be converted as if by a call
3979 * to the boolean function.
3980 */
3981int
3982xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
3983                                xmlXPathObjectPtr res, int index) {
3984    if (res == NULL) return(0);
3985    switch (res->type) {
3986        case XPATH_BOOLEAN:
3987	    return(res->boolval);
3988        case XPATH_NUMBER:
3989	    return(res->floatval == index);
3990        case XPATH_NODESET:
3991	    return(res->nodesetval->nodeNr != 0);
3992        case XPATH_STRING:
3993	    return((res->stringval != NULL) &&
3994	           (xmlStrlen(res->stringval) != 0));
3995        default:
3996	    STRANGE
3997    }
3998    return(0);
3999}
4000
4001/**
4002 * xmlXPathEvalPredicate:
4003 * @ctxt:  the XPath Parser context
4004 *
4005 *  [8]   Predicate ::=   '[' PredicateExpr ']'
4006 *  [9]   PredicateExpr ::=   Expr
4007 *
4008 * Parse and evaluate a predicate for all the elements of the
4009 * current node list. Then refine the list by removing all
4010 * nodes where the predicate is false.
4011 */
4012void
4013xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
4014    const xmlChar *cur;
4015    xmlXPathObjectPtr res;
4016    xmlNodeSetPtr newset = NULL;
4017    int i;
4018
4019    SKIP_BLANKS;
4020    if (CUR != '[') {
4021	ERROR(XPATH_INVALID_PREDICATE_ERROR);
4022    }
4023    NEXT;
4024    SKIP_BLANKS;
4025    if ((ctxt->context->nodelist == NULL) ||
4026        (ctxt->context->nodelist->nodeNr == 0)) {
4027        ctxt->context->node = NULL;
4028	xmlXPathEvalExpr(ctxt);
4029	CHECK_ERROR;
4030	res = valuePop(ctxt);
4031	if (res != NULL)
4032	    xmlXPathFreeObject(res);
4033    } else {
4034        cur = ctxt->cur;
4035	newset = xmlXPathNodeSetCreate(NULL);
4036        for (i = 0; i < ctxt->context->nodelist->nodeNr; i++) {
4037	    ctxt->cur = cur;
4038	    ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
4039	    xmlXPathEvalExpr(ctxt);
4040	    CHECK_ERROR;
4041	    res = valuePop(ctxt);
4042	    if (xmlXPathEvaluatePredicateResult(ctxt, res, i + 1))
4043	        xmlXPathNodeSetAdd(newset,
4044		                   ctxt->context->nodelist->nodeTab[i]);
4045	    if (res != NULL)
4046	    xmlXPathFreeObject(res);
4047	}
4048	if (ctxt->context->nodelist != NULL)
4049	    xmlXPathFreeNodeSet(ctxt->context->nodelist);
4050	ctxt->context->nodelist = newset;
4051	ctxt->context->node = NULL;
4052    }
4053    if (CUR != ']') {
4054	ERROR(XPATH_INVALID_PREDICATE_ERROR);
4055    }
4056    NEXT;
4057    SKIP_BLANKS;
4058#ifdef DEBUG_STEP
4059    fprintf(xmlXPathDebug, "After predicate : ");
4060    xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4061#endif
4062}
4063
4064/**
4065 * xmlXPathEvalBasis:
4066 * @ctxt:  the XPath Parser context
4067 *
4068 *  [5]   Basis ::=   AxisName '::' NodeTest
4069 *            | AbbreviatedBasis
4070 *  [13]   AbbreviatedBasis ::=   NodeTest
4071 *                           | '@' NodeTest
4072 *  [7]   NodeTest ::=   WildcardName
4073 *              | NodeType '(' ')'
4074 *              | 'processing-instruction' '(' Literal ')'
4075 *  [37]   WildcardName ::=   '*'
4076 *                    | NCName ':' '*'
4077 *                    | QName
4078 *
4079 * Evaluate one step in a Location Path
4080 */
4081void
4082xmlXPathEvalBasis(xmlXPathParserContextPtr ctxt) {
4083    xmlChar *name = NULL;
4084    xmlChar *prefix = NULL;
4085    int type = 0;
4086    int axis = AXIS_CHILD; /* the default on abbreviated syntax */
4087    int nodetest = NODE_TEST_NONE;
4088    int nodetype = 0;
4089    xmlNodeSetPtr newset = NULL;
4090
4091    if (CUR == '@') {
4092        NEXT;
4093	axis = AXIS_ATTRIBUTE;
4094	goto parse_NodeTest;
4095    } else if (CUR == '*') {
4096        NEXT;
4097        nodetest = NODE_TEST_ALL;
4098    } else {
4099        name = xmlXPathParseNCName(ctxt);
4100	if (name == NULL) {
4101	    ERROR(XPATH_EXPR_ERROR);
4102	}
4103	type = xmlXPathGetNameType(ctxt, name);
4104	switch (type) {
4105	    case IS_FUNCTION: {
4106		xmlXPathFunction func;
4107		int nbargs = 0;
4108		xmlXPathObjectPtr top;
4109
4110                top = ctxt->value;
4111		func = xmlXPathIsFunction(ctxt, name);
4112		if (func == NULL) {
4113		    xmlFree(name);
4114		    ERROR(XPATH_UNKNOWN_FUNC_ERROR);
4115		}
4116#ifdef DEBUG_EXPR
4117		fprintf(xmlXPathDebug, "Calling function %s\n", name);
4118#endif
4119
4120		if (CUR != '(') {
4121		    xmlFree(name);
4122		    ERROR(XPATH_EXPR_ERROR);
4123		}
4124		NEXT;
4125
4126		while (CUR != ')') {
4127		    xmlXPathEvalExpr(ctxt);
4128		    nbargs++;
4129		    if (CUR == ')') break;
4130		    if (CUR != ',') {
4131			xmlFree(name);
4132			ERROR(XPATH_EXPR_ERROR);
4133		    }
4134		    NEXT;
4135		}
4136		NEXT;
4137		xmlFree(name);
4138		func(ctxt, nbargs);
4139		if ((ctxt->value != top) &&
4140		    (ctxt->value != NULL) &&
4141		    (ctxt->value->type == XPATH_NODESET)) {
4142		    xmlXPathObjectPtr cur;
4143
4144		    cur = valuePop(ctxt);
4145		    ctxt->context->nodelist = cur->nodesetval;
4146		    ctxt->context->node = NULL;
4147		    cur->nodesetval = NULL;
4148                    xmlXPathFreeObject(cur);
4149		}
4150	        return;
4151	    }
4152	    /*
4153	     * Simple case: no axis seach all given node types.
4154	     */
4155            case NODE_TYPE_COMMENT:
4156	        if ((CUR != '(') || (NXT(1) != ')')) break;
4157		SKIP(2);
4158		nodetest = NODE_TEST_TYPE;
4159		nodetype = XML_COMMENT_NODE;
4160		goto search_nodes;
4161            case NODE_TYPE_TEXT:
4162	        if ((CUR != '(') || (NXT(1) != ')')) break;
4163		SKIP(2);
4164		nodetest = NODE_TEST_TYPE;
4165		nodetype = XML_TEXT_NODE;
4166		goto search_nodes;
4167            case NODE_TYPE_NODE:
4168	        if ((CUR != '(') || (NXT(1) != ')')) {
4169		    nodetest = NODE_TEST_NAME;
4170		    break;
4171		}
4172		SKIP(2);
4173		nodetest = NODE_TEST_TYPE;
4174		nodetype = XML_ELEMENT_NODE;
4175		goto search_nodes;
4176            case NODE_TYPE_PI:
4177	        if (CUR != '(') break;
4178		if (name != NULL) xmlFree(name);
4179		name = NULL;
4180		if (NXT(1) != ')') {
4181		    xmlXPathObjectPtr cur;
4182
4183		    /*
4184		     * Specific case: search a PI by name.
4185		     */
4186                    NEXT;
4187		    nodetest = NODE_TEST_PI;
4188		    xmlXPathEvalLiteral(ctxt);
4189		    CHECK_ERROR;
4190		    if (CUR != ')')
4191			ERROR(XPATH_UNCLOSED_ERROR);
4192                    NEXT;
4193		    xmlXPathStringFunction(ctxt, 1);
4194		    CHECK_ERROR;
4195		    cur = valuePop(ctxt);
4196		    name = xmlStrdup(cur->stringval);
4197		    xmlXPathFreeObject(cur);
4198		} else
4199		    SKIP(2);
4200		nodetest = NODE_TEST_PI;
4201		goto search_nodes;
4202
4203	    /*
4204	     * Handling of the compund form: got the axis.
4205	     */
4206            case AXIS_ANCESTOR:
4207            case AXIS_ANCESTOR_OR_SELF:
4208            case AXIS_ATTRIBUTE:
4209            case AXIS_CHILD:
4210            case AXIS_DESCENDANT:
4211            case AXIS_DESCENDANT_OR_SELF:
4212            case AXIS_FOLLOWING:
4213            case AXIS_FOLLOWING_SIBLING:
4214            case AXIS_NAMESPACE:
4215            case AXIS_PARENT:
4216            case AXIS_PRECEDING:
4217            case AXIS_PRECEDING_SIBLING:
4218            case AXIS_SELF:
4219	        if ((CUR != ':') || (NXT(1) != ':')) {
4220		    nodetest = NODE_TEST_NAME;
4221		    break;
4222		}
4223		SKIP(2);
4224		axis = type;
4225		break;
4226
4227	    /*
4228	     * Default: abbreviated syntax the axis is AXIS_CHILD
4229	     */
4230	    default:
4231	        nodetest = NODE_TEST_NAME;
4232	}
4233parse_NodeTest:
4234	if (nodetest == NODE_TEST_NONE) {
4235	    if (CUR == '*') {
4236		NEXT;
4237		nodetest = NODE_TEST_ALL;
4238	    } else {
4239		if (name != NULL)
4240		    xmlFree(name);
4241		name = xmlXPathParseQName(ctxt, &prefix);
4242		if (name == NULL) {
4243		    ERROR(XPATH_EXPR_ERROR);
4244		}
4245		type = xmlXPathGetNameType(ctxt, name);
4246		switch (type) {
4247		    /*
4248		     * Simple case: no axis seach all given node types.
4249		     */
4250		    case NODE_TYPE_COMMENT:
4251			if ((CUR != '(') || (NXT(1) != ')')) break;
4252			SKIP(2);
4253			nodetest = NODE_TEST_TYPE;
4254			nodetype = XML_COMMENT_NODE;
4255			goto search_nodes;
4256		    case NODE_TYPE_TEXT:
4257			if ((CUR != '(') || (NXT(1) != ')')) break;
4258			SKIP(2);
4259			nodetest = NODE_TEST_TYPE;
4260			nodetype = XML_TEXT_NODE;
4261			goto search_nodes;
4262		    case NODE_TYPE_NODE:
4263			if ((CUR != '(') || (NXT(1) != ')')) {
4264			    nodetest = NODE_TEST_NAME;
4265			    break;
4266			}
4267			SKIP(2);
4268			nodetest = NODE_TEST_TYPE;
4269			nodetype = XML_ELEMENT_NODE;
4270			goto search_nodes;
4271		    case NODE_TYPE_PI:
4272			if (CUR != '(') break;
4273			if (name != NULL) xmlFree(name);
4274			name = NULL;
4275			if (NXT(1) != ')') {
4276			    xmlXPathObjectPtr cur;
4277
4278			    /*
4279			     * Specific case: search a PI by name.
4280			     */
4281			    NEXT;
4282			    nodetest = NODE_TEST_PI;
4283			    xmlXPathEvalLiteral(ctxt);
4284			    CHECK_ERROR;
4285			    if (CUR != ')')
4286				ERROR(XPATH_UNCLOSED_ERROR);
4287			    NEXT;
4288			    xmlXPathStringFunction(ctxt, 1);
4289			    CHECK_ERROR;
4290			    cur = valuePop(ctxt);
4291			    name = xmlStrdup(cur->stringval);
4292			    xmlXPathFreeObject(cur);
4293			} else
4294			    SKIP(2);
4295			nodetest = NODE_TEST_PI;
4296			goto search_nodes;
4297		}
4298		nodetest = NODE_TEST_NAME;
4299	    }
4300	} else if ((CUR == ':') && (nodetest == NODE_TEST_NAME)) {
4301	    NEXT;
4302	    prefix = name;
4303	    if (CUR == '*') {
4304	        NEXT;
4305		nodetest = NODE_TEST_ALL;
4306	    } else
4307		name = xmlXPathParseNCName(ctxt);
4308	} else if (name == NULL)
4309	    ERROR(XPATH_EXPR_ERROR);
4310    }
4311
4312search_nodes:
4313
4314#ifdef DEBUG_STEP
4315    fprintf(xmlXPathDebug, "Basis : computing new set\n");
4316#endif
4317    newset = xmlXPathNodeCollectAndTest(ctxt, axis, nodetest, nodetype,
4318                                        prefix, name);
4319    if (ctxt->context->nodelist != NULL)
4320	xmlXPathFreeNodeSet(ctxt->context->nodelist);
4321    ctxt->context->nodelist = newset;
4322    ctxt->context->node = NULL;
4323#ifdef DEBUG_STEP
4324    fprintf(xmlXPathDebug, "Basis : ");
4325    xmlXPathDebugNodeSet(stdout, ctxt->context->nodelist);
4326#endif
4327    if (name != NULL) xmlFree(name);
4328    if (prefix != NULL) xmlFree(prefix);
4329}
4330
4331/**
4332 * xmlXPathEvalStep:
4333 * @ctxt:  the XPath Parser context
4334 *
4335 *  [4]   Step ::=   Basis Predicate*
4336 *                     | AbbreviatedStep
4337 *  [12]   AbbreviatedStep ::=   '.'
4338 *                           | '..'
4339 *
4340 * Evaluate one step in a Location Path
4341 * A location step of . is short for self::node(). This is
4342 * particularly useful in conjunction with //. For example, the
4343 * location path .//para is short for
4344 * self::node()/descendant-or-self::node()/child::para
4345 * and so will select all para descendant elements of the context
4346 * node.
4347 * Similarly, a location step of .. is short for parent::node().
4348 * For example, ../title is short for parent::node()/child::title
4349 * and so will select the title children of the parent of the context
4350 * node.
4351 */
4352void
4353xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
4354    xmlNodeSetPtr newset = NULL;
4355
4356    SKIP_BLANKS;
4357    if ((CUR == '.') && (NXT(1) == '.')) {
4358	SKIP(2);
4359	SKIP_BLANKS;
4360	if (ctxt->context->nodelist == NULL) {
4361	    STRANGE
4362	    xmlXPathRoot(ctxt);
4363	}
4364	newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
4365			 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4366	if (ctxt->context->nodelist != NULL)
4367	    xmlXPathFreeNodeSet(ctxt->context->nodelist);
4368	ctxt->context->nodelist = newset;
4369	ctxt->context->node = NULL;
4370    } else if (CUR == '.') {
4371	NEXT;
4372	SKIP_BLANKS;
4373    } else {
4374	xmlXPathEvalBasis(ctxt);
4375	SKIP_BLANKS;
4376	while (CUR == '[') {
4377	    xmlXPathEvalPredicate(ctxt);
4378	}
4379    }
4380#ifdef DEBUG_STEP
4381    fprintf(xmlXPathDebug, "Step : ");
4382    xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4383#endif
4384}
4385
4386/**
4387 * xmlXPathEvalRelativeLocationPath:
4388 * @ctxt:  the XPath Parser context
4389 *
4390 *  [3]   RelativeLocationPath ::=   Step
4391 *                     | RelativeLocationPath '/' Step
4392 *                     | AbbreviatedRelativeLocationPath
4393 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
4394 *
4395 */
4396void
4397xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
4398    xmlNodeSetPtr newset = NULL;
4399
4400    SKIP_BLANKS;
4401    xmlXPathEvalStep(ctxt);
4402    SKIP_BLANKS;
4403    while (CUR == '/') {
4404	if ((CUR == '/') && (NXT(1) == '/')) {
4405	    SKIP(2);
4406	    SKIP_BLANKS;
4407	    if (ctxt->context->nodelist == NULL) {
4408		STRANGE
4409		xmlXPathRoot(ctxt);
4410	    }
4411	    newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
4412			     NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4413	    if (ctxt->context->nodelist != NULL)
4414		xmlXPathFreeNodeSet(ctxt->context->nodelist);
4415	    ctxt->context->nodelist = newset;
4416	    ctxt->context->node = NULL;
4417	    xmlXPathEvalStep(ctxt);
4418	} else if (CUR == '/') {
4419	    NEXT;
4420	    SKIP_BLANKS;
4421	    xmlXPathEvalStep(ctxt);
4422	}
4423	SKIP_BLANKS;
4424    }
4425}
4426
4427/**
4428 * xmlXPathEvalLocationPath:
4429 * @ctxt:  the XPath Parser context
4430 *
4431 *  [1]   LocationPath ::=   RelativeLocationPath
4432 *                     | AbsoluteLocationPath
4433 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
4434 *                     | AbbreviatedAbsoluteLocationPath
4435 *  [10]   AbbreviatedAbsoluteLocationPath ::=
4436 *                           '//' RelativeLocationPath
4437 *
4438 * // is short for /descendant-or-self::node()/. For example,
4439 * //para is short for /descendant-or-self::node()/child::para and
4440 * so will select any para element in the document (even a para element
4441 * that is a document element will be selected by //para since the
4442 * document element node is a child of the root node); div//para is
4443 * short for div/descendant-or-self::node()/child::para and so will
4444 * select all para descendants of div children.
4445 */
4446void
4447xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
4448    xmlNodeSetPtr newset = NULL;
4449
4450    SKIP_BLANKS;
4451    if (CUR != '/') {
4452        xmlXPathEvalRelativeLocationPath(ctxt);
4453    } else {
4454	while (CUR == '/') {
4455	    if ((CUR == '/') && (NXT(1) == '/')) {
4456		SKIP(2);
4457		SKIP_BLANKS;
4458		if (ctxt->context->nodelist == NULL)
4459		    xmlXPathRoot(ctxt);
4460		newset = xmlXPathNodeCollectAndTest(ctxt,
4461		                 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
4462				 XML_ELEMENT_NODE, NULL, NULL);
4463		if (ctxt->context->nodelist != NULL)
4464		    xmlXPathFreeNodeSet(ctxt->context->nodelist);
4465		ctxt->context->nodelist = newset;
4466		ctxt->context->node = NULL;
4467		xmlXPathEvalRelativeLocationPath(ctxt);
4468	    } else if (CUR == '/') {
4469		NEXT;
4470		SKIP_BLANKS;
4471		xmlXPathRoot(ctxt);
4472		if (CUR != 0)
4473		    xmlXPathEvalRelativeLocationPath(ctxt);
4474	    } else {
4475		xmlXPathEvalRelativeLocationPath(ctxt);
4476	    }
4477	}
4478    }
4479}
4480
4481/**
4482 * xmlXPathEval:
4483 * @str:  the XPath expression
4484 * @ctxt:  the XPath context
4485 *
4486 * Evaluate the XPath Location Path in the given context.
4487 *
4488 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
4489 *         the caller has to free the object.
4490 */
4491xmlXPathObjectPtr
4492xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctxt) {
4493    xmlXPathParserContextPtr pctxt;
4494    xmlXPathObjectPtr res = NULL, tmp;
4495    int stack = 0;
4496
4497    xmlXPathInit();
4498
4499    CHECK_CONTEXT
4500
4501    if (xmlXPathDebug == NULL)
4502        xmlXPathDebug = stderr;
4503    pctxt = xmlXPathNewParserContext(str, ctxt);
4504    if (str[0] == '/')
4505        xmlXPathRoot(pctxt);
4506    xmlXPathEvalLocationPath(pctxt);
4507
4508    /* TODO: cleanup nodelist, res = valuePop(pctxt); */
4509    do {
4510        tmp = valuePop(pctxt);
4511	if (tmp != NULL) {
4512	    xmlXPathFreeObject(tmp);
4513	    stack++;
4514        }
4515    } while (tmp != NULL);
4516    if (stack != 0) {
4517	fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
4518	        stack);
4519    }
4520    if (pctxt->error == XPATH_EXPRESSION_OK)
4521	res = xmlXPathNewNodeSetList(pctxt->context->nodelist);
4522    else
4523        res = NULL;
4524    xmlXPathFreeParserContext(pctxt);
4525    return(res);
4526}
4527
4528/**
4529 * xmlXPathEvalExpression:
4530 * @str:  the XPath expression
4531 * @ctxt:  the XPath context
4532 *
4533 * Evaluate the XPath expression in the given context.
4534 *
4535 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
4536 *         the caller has to free the object.
4537 */
4538xmlXPathObjectPtr
4539xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
4540    xmlXPathParserContextPtr pctxt;
4541    xmlXPathObjectPtr res, tmp;
4542    int stack = 0;
4543
4544    xmlXPathInit();
4545
4546    CHECK_CONTEXT
4547
4548    if (xmlXPathDebug == NULL)
4549        xmlXPathDebug = stderr;
4550    pctxt = xmlXPathNewParserContext(str, ctxt);
4551    xmlXPathEvalExpr(pctxt);
4552
4553    res = valuePop(pctxt);
4554    do {
4555        tmp = valuePop(pctxt);
4556	if (tmp != NULL) {
4557	    xmlXPathFreeObject(tmp);
4558	    stack++;
4559	}
4560    } while (tmp != NULL);
4561    if (stack != 0) {
4562	fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
4563	        stack);
4564    }
4565    xmlXPathFreeParserContext(pctxt);
4566    return(res);
4567}
4568
4569