resetting manifest requested domain to floor
[platform/upstream/libxml2.git] / xpath.c
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  *f
6  * Reference: W3C Recommendation 16 November 1999
7  *     http://www.w3.org/TR/1999/REC-xpath-19991116
8  * Public reference:
9  *     http://www.w3.org/TR/xpath
10  *
11  * See Copyright for the status of this software
12  *
13  * Author: daniel@veillard.com
14  *
15  */
16
17 #define IN_LIBXML
18 #include "libxml.h"
19
20 #include <string.h>
21
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
24 #endif
25 #ifdef HAVE_MATH_H
26 #include <math.h>
27 #endif
28 #ifdef HAVE_FLOAT_H
29 #include <float.h>
30 #endif
31 #ifdef HAVE_CTYPE_H
32 #include <ctype.h>
33 #endif
34 #ifdef HAVE_SIGNAL_H
35 #include <signal.h>
36 #endif
37
38 #include <libxml/xmlmemory.h>
39 #include <libxml/tree.h>
40 #include <libxml/valid.h>
41 #include <libxml/xpath.h>
42 #include <libxml/xpathInternals.h>
43 #include <libxml/parserInternals.h>
44 #include <libxml/hash.h>
45 #ifdef LIBXML_XPTR_ENABLED
46 #include <libxml/xpointer.h>
47 #endif
48 #ifdef LIBXML_DEBUG_ENABLED
49 #include <libxml/debugXML.h>
50 #endif
51 #include <libxml/xmlerror.h>
52 #include <libxml/threads.h>
53 #include <libxml/globals.h>
54 #ifdef LIBXML_PATTERN_ENABLED
55 #include <libxml/pattern.h>
56 #endif
57
58 #include "buf.h"
59
60 #ifdef LIBXML_PATTERN_ENABLED
61 #define XPATH_STREAMING
62 #endif
63
64 #define TODO                                                            \
65     xmlGenericError(xmlGenericErrorContext,                             \
66             "Unimplemented block at %s:%d\n",                           \
67             __FILE__, __LINE__);
68
69 /**
70  * WITH_TIM_SORT:
71  *
72  * Use the Timsort algorithm provided in timsort.h to sort
73  * nodeset as this is a great improvement over the old Shell sort
74  * used in xmlXPathNodeSetSort()
75  */
76 #define WITH_TIM_SORT
77
78 /*
79 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
80 * If defined, this will use xmlXPathCmpNodesExt() instead of
81 * xmlXPathCmpNodes(). The new function is optimized comparison of
82 * non-element nodes; actually it will speed up comparison only if
83 * xmlXPathOrderDocElems() was called in order to index the elements of
84 * a tree in document order; Libxslt does such an indexing, thus it will
85 * benefit from this optimization.
86 */
87 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
88
89 /*
90 * XP_OPTIMIZED_FILTER_FIRST:
91 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
92 * in a way, that it stop evaluation at the first node.
93 */
94 #define XP_OPTIMIZED_FILTER_FIRST
95
96 /*
97 * XP_DEBUG_OBJ_USAGE:
98 * Internal flag to enable tracking of how much XPath objects have been
99 * created.
100 */
101 /* #define XP_DEBUG_OBJ_USAGE */
102
103 /*
104  * XPATH_MAX_STEPS:
105  * when compiling an XPath expression we arbitrary limit the maximum
106  * number of step operation in the compiled expression. 1000000 is
107  * an insanely large value which should never be reached under normal
108  * circumstances
109  */
110 #define XPATH_MAX_STEPS 1000000
111
112 /*
113  * XPATH_MAX_STACK_DEPTH:
114  * when evaluating an XPath expression we arbitrary limit the maximum
115  * number of object allowed to be pushed on the stack. 1000000 is
116  * an insanely large value which should never be reached under normal
117  * circumstances
118  */
119 #define XPATH_MAX_STACK_DEPTH 1000000
120
121 /*
122  * XPATH_MAX_NODESET_LENGTH:
123  * when evaluating an XPath expression nodesets are created and we
124  * arbitrary limit the maximum length of those node set. 10000000 is
125  * an insanely large value which should never be reached under normal
126  * circumstances, one would first need to construct an in memory tree
127  * with more than 10 millions nodes.
128  */
129 #define XPATH_MAX_NODESET_LENGTH 10000000
130
131 /*
132  * TODO:
133  * There are a few spots where some tests are done which depend upon ascii
134  * data.  These should be enhanced for full UTF8 support (see particularly
135  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
136  */
137
138 /*
139  * Wrapper for the Timsort argorithm from timsort.h
140  */
141 #ifdef WITH_TIM_SORT
142 #define SORT_NAME libxml_domnode
143 #define SORT_TYPE xmlNodePtr
144 /**
145  * wrap_cmp:
146  * @x: a node
147  * @y: another node
148  *
149  * Comparison function for the Timsort implementation
150  *
151  * Returns -2 in case of error -1 if first point < second point, 0 if
152  *         it's the same node, +1 otherwise
153  */
154 static
155 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
156 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
157     static int xmlXPathCmpNodesExt(xmlNodePtr, xmlNodePtr);
158     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
159     {
160         int res = xmlXPathCmpNodesExt(x, y);
161         return res == -2 ? res : -res;
162     }
163 #else
164     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
165     {
166         int res = xmlXPathCmpNodes(x, y);
167         return res == -2 ? res : -res;
168     }
169 #endif
170 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
171 #include "timsort.h"
172 #endif /* WITH_TIM_SORT */
173
174 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
175
176 /************************************************************************
177  *                                                                      *
178  *                      Floating point stuff                            *
179  *                                                                      *
180  ************************************************************************/
181
182 #ifndef TRIO_REPLACE_STDIO
183 #define TRIO_PUBLIC static
184 #endif
185 #include "trionan.c"
186
187 /*
188  * The lack of portability of this section of the libc is annoying !
189  */
190 double xmlXPathNAN = 0;
191 double xmlXPathPINF = 1;
192 double xmlXPathNINF = -1;
193 static double xmlXPathNZERO = 0; /* not exported from headers */
194 static int xmlXPathInitialized = 0;
195
196 /**
197  * xmlXPathInit:
198  *
199  * Initialize the XPath environment
200  */
201 void
202 xmlXPathInit(void) {
203     if (xmlXPathInitialized) return;
204
205     xmlXPathPINF = trio_pinf();
206     xmlXPathNINF = trio_ninf();
207     xmlXPathNAN = trio_nan();
208     xmlXPathNZERO = trio_nzero();
209
210     xmlXPathInitialized = 1;
211 }
212
213 /**
214  * xmlXPathIsNaN:
215  * @val:  a double value
216  *
217  * Provides a portable isnan() function to detect whether a double
218  * is a NotaNumber. Based on trio code
219  * http://sourceforge.net/projects/ctrio/
220  *
221  * Returns 1 if the value is a NaN, 0 otherwise
222  */
223 int
224 xmlXPathIsNaN(double val) {
225     return(trio_isnan(val));
226 }
227
228 /**
229  * xmlXPathIsInf:
230  * @val:  a double value
231  *
232  * Provides a portable isinf() function to detect whether a double
233  * is a +Infinite or -Infinite. Based on trio code
234  * http://sourceforge.net/projects/ctrio/
235  *
236  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
237  */
238 int
239 xmlXPathIsInf(double val) {
240     return(trio_isinf(val));
241 }
242
243 #endif /* SCHEMAS or XPATH */
244 #ifdef LIBXML_XPATH_ENABLED
245 /**
246  * xmlXPathGetSign:
247  * @val:  a double value
248  *
249  * Provides a portable function to detect the sign of a double
250  * Modified from trio code
251  * http://sourceforge.net/projects/ctrio/
252  *
253  * Returns 1 if the value is Negative, 0 if positive
254  */
255 static int
256 xmlXPathGetSign(double val) {
257     return(trio_signbit(val));
258 }
259
260
261 /*
262  * TODO: when compatibility allows remove all "fake node libxslt" strings
263  *       the test should just be name[0] = ' '
264  */
265 #ifdef DEBUG_XPATH_EXPRESSION
266 #define DEBUG_STEP
267 #define DEBUG_EXPR
268 #define DEBUG_EVAL_COUNTS
269 #endif
270
271 static xmlNs xmlXPathXMLNamespaceStruct = {
272     NULL,
273     XML_NAMESPACE_DECL,
274     XML_XML_NAMESPACE,
275     BAD_CAST "xml",
276     NULL,
277     NULL
278 };
279 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
280 #ifndef LIBXML_THREAD_ENABLED
281 /*
282  * Optimizer is disabled only when threaded apps are detected while
283  * the library ain't compiled for thread safety.
284  */
285 static int xmlXPathDisableOptimizer = 0;
286 #endif
287
288 /************************************************************************
289  *                                                                      *
290  *                      Error handling routines                         *
291  *                                                                      *
292  ************************************************************************/
293
294 /**
295  * XP_ERRORNULL:
296  * @X:  the error code
297  *
298  * Macro to raise an XPath error and return NULL.
299  */
300 #define XP_ERRORNULL(X)                                                 \
301     { xmlXPathErr(ctxt, X); return(NULL); }
302
303 /*
304  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
305  */
306 static const char *xmlXPathErrorMessages[] = {
307     "Ok\n",
308     "Number encoding\n",
309     "Unfinished literal\n",
310     "Start of literal\n",
311     "Expected $ for variable reference\n",
312     "Undefined variable\n",
313     "Invalid predicate\n",
314     "Invalid expression\n",
315     "Missing closing curly brace\n",
316     "Unregistered function\n",
317     "Invalid operand\n",
318     "Invalid type\n",
319     "Invalid number of arguments\n",
320     "Invalid context size\n",
321     "Invalid context position\n",
322     "Memory allocation error\n",
323     "Syntax error\n",
324     "Resource error\n",
325     "Sub resource error\n",
326     "Undefined namespace prefix\n",
327     "Encoding error\n",
328     "Char out of XML range\n",
329     "Invalid or incomplete context\n",
330     "Stack usage errror\n",
331     "Forbidden variable\n",
332     "?? Unknown error ??\n"     /* Must be last in the list! */
333 };
334 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
335                    sizeof(xmlXPathErrorMessages[0])) - 1)
336 /**
337  * xmlXPathErrMemory:
338  * @ctxt:  an XPath context
339  * @extra:  extra informations
340  *
341  * Handle a redefinition of attribute error
342  */
343 static void
344 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
345 {
346     if (ctxt != NULL) {
347         if (extra) {
348             xmlChar buf[200];
349
350             xmlStrPrintf(buf, 200,
351                          BAD_CAST "Memory allocation failed : %s\n",
352                          extra);
353             ctxt->lastError.message = (char *) xmlStrdup(buf);
354         } else {
355             ctxt->lastError.message = (char *)
356                xmlStrdup(BAD_CAST "Memory allocation failed\n");
357         }
358         ctxt->lastError.domain = XML_FROM_XPATH;
359         ctxt->lastError.code = XML_ERR_NO_MEMORY;
360         if (ctxt->error != NULL)
361             ctxt->error(ctxt->userData, &ctxt->lastError);
362     } else {
363         if (extra)
364             __xmlRaiseError(NULL, NULL, NULL,
365                             NULL, NULL, XML_FROM_XPATH,
366                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
367                             extra, NULL, NULL, 0, 0,
368                             "Memory allocation failed : %s\n", extra);
369         else
370             __xmlRaiseError(NULL, NULL, NULL,
371                             NULL, NULL, XML_FROM_XPATH,
372                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
373                             NULL, NULL, NULL, 0, 0,
374                             "Memory allocation failed\n");
375     }
376 }
377
378 /**
379  * xmlXPathPErrMemory:
380  * @ctxt:  an XPath parser context
381  * @extra:  extra informations
382  *
383  * Handle a redefinition of attribute error
384  */
385 static void
386 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
387 {
388     if (ctxt == NULL)
389         xmlXPathErrMemory(NULL, extra);
390     else {
391         ctxt->error = XPATH_MEMORY_ERROR;
392         xmlXPathErrMemory(ctxt->context, extra);
393     }
394 }
395
396 /**
397  * xmlXPathErr:
398  * @ctxt:  a XPath parser context
399  * @error:  the error code
400  *
401  * Handle an XPath error
402  */
403 void
404 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
405 {
406     if ((error < 0) || (error > MAXERRNO))
407         error = MAXERRNO;
408     if (ctxt == NULL) {
409         __xmlRaiseError(NULL, NULL, NULL,
410                         NULL, NULL, XML_FROM_XPATH,
411                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
412                         XML_ERR_ERROR, NULL, 0,
413                         NULL, NULL, NULL, 0, 0,
414                         "%s", xmlXPathErrorMessages[error]);
415         return;
416     }
417     ctxt->error = error;
418     if (ctxt->context == NULL) {
419         __xmlRaiseError(NULL, NULL, NULL,
420                         NULL, NULL, XML_FROM_XPATH,
421                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
422                         XML_ERR_ERROR, NULL, 0,
423                         (const char *) ctxt->base, NULL, NULL,
424                         ctxt->cur - ctxt->base, 0,
425                         "%s", xmlXPathErrorMessages[error]);
426         return;
427     }
428
429     /* cleanup current last error */
430     xmlResetError(&ctxt->context->lastError);
431
432     ctxt->context->lastError.domain = XML_FROM_XPATH;
433     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
434                            XPATH_EXPRESSION_OK;
435     ctxt->context->lastError.level = XML_ERR_ERROR;
436     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
437     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
438     ctxt->context->lastError.node = ctxt->context->debugNode;
439     if (ctxt->context->error != NULL) {
440         ctxt->context->error(ctxt->context->userData,
441                              &ctxt->context->lastError);
442     } else {
443         __xmlRaiseError(NULL, NULL, NULL,
444                         NULL, ctxt->context->debugNode, XML_FROM_XPATH,
445                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
446                         XML_ERR_ERROR, NULL, 0,
447                         (const char *) ctxt->base, NULL, NULL,
448                         ctxt->cur - ctxt->base, 0,
449                         "%s", xmlXPathErrorMessages[error]);
450     }
451
452 }
453
454 /**
455  * xmlXPatherror:
456  * @ctxt:  the XPath Parser context
457  * @file:  the file name
458  * @line:  the line number
459  * @no:  the error number
460  *
461  * Formats an error message.
462  */
463 void
464 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
465               int line ATTRIBUTE_UNUSED, int no) {
466     xmlXPathErr(ctxt, no);
467 }
468
469 /************************************************************************
470  *                                                                      *
471  *                      Utilities                                       *
472  *                                                                      *
473  ************************************************************************/
474
475 /**
476  * xsltPointerList:
477  *
478  * Pointer-list for various purposes.
479  */
480 typedef struct _xmlPointerList xmlPointerList;
481 typedef xmlPointerList *xmlPointerListPtr;
482 struct _xmlPointerList {
483     void **items;
484     int number;
485     int size;
486 };
487 /*
488 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
489 * and here, we should make the functions public.
490 */
491 static int
492 xmlPointerListAddSize(xmlPointerListPtr list,
493                        void *item,
494                        int initialSize)
495 {
496     if (list->items == NULL) {
497         if (initialSize <= 0)
498             initialSize = 1;
499         list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
500         if (list->items == NULL) {
501             xmlXPathErrMemory(NULL,
502                 "xmlPointerListCreate: allocating item\n");
503             return(-1);
504         }
505         list->number = 0;
506         list->size = initialSize;
507     } else if (list->size <= list->number) {
508         if (list->size > 50000000) {
509             xmlXPathErrMemory(NULL,
510                 "xmlPointerListAddSize: re-allocating item\n");
511             return(-1);
512         }
513         list->size *= 2;
514         list->items = (void **) xmlRealloc(list->items,
515             list->size * sizeof(void *));
516         if (list->items == NULL) {
517             xmlXPathErrMemory(NULL,
518                 "xmlPointerListAddSize: re-allocating item\n");
519             list->size = 0;
520             return(-1);
521         }
522     }
523     list->items[list->number++] = item;
524     return(0);
525 }
526
527 /**
528  * xsltPointerListCreate:
529  *
530  * Creates an xsltPointerList structure.
531  *
532  * Returns a xsltPointerList structure or NULL in case of an error.
533  */
534 static xmlPointerListPtr
535 xmlPointerListCreate(int initialSize)
536 {
537     xmlPointerListPtr ret;
538
539     ret = xmlMalloc(sizeof(xmlPointerList));
540     if (ret == NULL) {
541         xmlXPathErrMemory(NULL,
542             "xmlPointerListCreate: allocating item\n");
543         return (NULL);
544     }
545     memset(ret, 0, sizeof(xmlPointerList));
546     if (initialSize > 0) {
547         xmlPointerListAddSize(ret, NULL, initialSize);
548         ret->number = 0;
549     }
550     return (ret);
551 }
552
553 /**
554  * xsltPointerListFree:
555  *
556  * Frees the xsltPointerList structure. This does not free
557  * the content of the list.
558  */
559 static void
560 xmlPointerListFree(xmlPointerListPtr list)
561 {
562     if (list == NULL)
563         return;
564     if (list->items != NULL)
565         xmlFree(list->items);
566     xmlFree(list);
567 }
568
569 /************************************************************************
570  *                                                                      *
571  *                      Parser Types                                    *
572  *                                                                      *
573  ************************************************************************/
574
575 /*
576  * Types are private:
577  */
578
579 typedef enum {
580     XPATH_OP_END=0,
581     XPATH_OP_AND,
582     XPATH_OP_OR,
583     XPATH_OP_EQUAL,
584     XPATH_OP_CMP,
585     XPATH_OP_PLUS,
586     XPATH_OP_MULT,
587     XPATH_OP_UNION,
588     XPATH_OP_ROOT,
589     XPATH_OP_NODE,
590     XPATH_OP_RESET, /* 10 */
591     XPATH_OP_COLLECT,
592     XPATH_OP_VALUE, /* 12 */
593     XPATH_OP_VARIABLE,
594     XPATH_OP_FUNCTION,
595     XPATH_OP_ARG,
596     XPATH_OP_PREDICATE,
597     XPATH_OP_FILTER, /* 17 */
598     XPATH_OP_SORT /* 18 */
599 #ifdef LIBXML_XPTR_ENABLED
600     ,XPATH_OP_RANGETO
601 #endif
602 } xmlXPathOp;
603
604 typedef enum {
605     AXIS_ANCESTOR = 1,
606     AXIS_ANCESTOR_OR_SELF,
607     AXIS_ATTRIBUTE,
608     AXIS_CHILD,
609     AXIS_DESCENDANT,
610     AXIS_DESCENDANT_OR_SELF,
611     AXIS_FOLLOWING,
612     AXIS_FOLLOWING_SIBLING,
613     AXIS_NAMESPACE,
614     AXIS_PARENT,
615     AXIS_PRECEDING,
616     AXIS_PRECEDING_SIBLING,
617     AXIS_SELF
618 } xmlXPathAxisVal;
619
620 typedef enum {
621     NODE_TEST_NONE = 0,
622     NODE_TEST_TYPE = 1,
623     NODE_TEST_PI = 2,
624     NODE_TEST_ALL = 3,
625     NODE_TEST_NS = 4,
626     NODE_TEST_NAME = 5
627 } xmlXPathTestVal;
628
629 typedef enum {
630     NODE_TYPE_NODE = 0,
631     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
632     NODE_TYPE_TEXT = XML_TEXT_NODE,
633     NODE_TYPE_PI = XML_PI_NODE
634 } xmlXPathTypeVal;
635
636 typedef struct _xmlXPathStepOp xmlXPathStepOp;
637 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
638 struct _xmlXPathStepOp {
639     xmlXPathOp op;              /* The identifier of the operation */
640     int ch1;                    /* First child */
641     int ch2;                    /* Second child */
642     int value;
643     int value2;
644     int value3;
645     void *value4;
646     void *value5;
647     void *cache;
648     void *cacheURI;
649 };
650
651 struct _xmlXPathCompExpr {
652     int nbStep;                 /* Number of steps in this expression */
653     int maxStep;                /* Maximum number of steps allocated */
654     xmlXPathStepOp *steps;      /* ops for computation of this expression */
655     int last;                   /* index of last step in expression */
656     xmlChar *expr;              /* the expression being computed */
657     xmlDictPtr dict;            /* the dictionnary to use if any */
658 #ifdef DEBUG_EVAL_COUNTS
659     int nb;
660     xmlChar *string;
661 #endif
662 #ifdef XPATH_STREAMING
663     xmlPatternPtr stream;
664 #endif
665 };
666
667 /************************************************************************
668  *                                                                      *
669  *                      Forward declarations                            *
670  *                                                                      *
671  ************************************************************************/
672 static void
673 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
674 static void
675 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
676 static int
677 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
678                         xmlXPathStepOpPtr op, xmlNodePtr *first);
679 static int
680 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
681                             xmlXPathStepOpPtr op,
682                             int isPredicate);
683
684 /************************************************************************
685  *                                                                      *
686  *                      Parser Type functions                           *
687  *                                                                      *
688  ************************************************************************/
689
690 /**
691  * xmlXPathNewCompExpr:
692  *
693  * Create a new Xpath component
694  *
695  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
696  */
697 static xmlXPathCompExprPtr
698 xmlXPathNewCompExpr(void) {
699     xmlXPathCompExprPtr cur;
700
701     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
702     if (cur == NULL) {
703         xmlXPathErrMemory(NULL, "allocating component\n");
704         return(NULL);
705     }
706     memset(cur, 0, sizeof(xmlXPathCompExpr));
707     cur->maxStep = 10;
708     cur->nbStep = 0;
709     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
710                                            sizeof(xmlXPathStepOp));
711     if (cur->steps == NULL) {
712         xmlXPathErrMemory(NULL, "allocating steps\n");
713         xmlFree(cur);
714         return(NULL);
715     }
716     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
717     cur->last = -1;
718 #ifdef DEBUG_EVAL_COUNTS
719     cur->nb = 0;
720 #endif
721     return(cur);
722 }
723
724 /**
725  * xmlXPathFreeCompExpr:
726  * @comp:  an XPATH comp
727  *
728  * Free up the memory allocated by @comp
729  */
730 void
731 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
732 {
733     xmlXPathStepOpPtr op;
734     int i;
735
736     if (comp == NULL)
737         return;
738     if (comp->dict == NULL) {
739         for (i = 0; i < comp->nbStep; i++) {
740             op = &comp->steps[i];
741             if (op->value4 != NULL) {
742                 if (op->op == XPATH_OP_VALUE)
743                     xmlXPathFreeObject(op->value4);
744                 else
745                     xmlFree(op->value4);
746             }
747             if (op->value5 != NULL)
748                 xmlFree(op->value5);
749         }
750     } else {
751         for (i = 0; i < comp->nbStep; i++) {
752             op = &comp->steps[i];
753             if (op->value4 != NULL) {
754                 if (op->op == XPATH_OP_VALUE)
755                     xmlXPathFreeObject(op->value4);
756             }
757         }
758         xmlDictFree(comp->dict);
759     }
760     if (comp->steps != NULL) {
761         xmlFree(comp->steps);
762     }
763 #ifdef DEBUG_EVAL_COUNTS
764     if (comp->string != NULL) {
765         xmlFree(comp->string);
766     }
767 #endif
768 #ifdef XPATH_STREAMING
769     if (comp->stream != NULL) {
770         xmlFreePatternList(comp->stream);
771     }
772 #endif
773     if (comp->expr != NULL) {
774         xmlFree(comp->expr);
775     }
776
777     xmlFree(comp);
778 }
779
780 /**
781  * xmlXPathCompExprAdd:
782  * @comp:  the compiled expression
783  * @ch1: first child index
784  * @ch2: second child index
785  * @op:  an op
786  * @value:  the first int value
787  * @value2:  the second int value
788  * @value3:  the third int value
789  * @value4:  the first string value
790  * @value5:  the second string value
791  *
792  * Add a step to an XPath Compiled Expression
793  *
794  * Returns -1 in case of failure, the index otherwise
795  */
796 static int
797 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
798    xmlXPathOp op, int value,
799    int value2, int value3, void *value4, void *value5) {
800     if (comp->nbStep >= comp->maxStep) {
801         xmlXPathStepOp *real;
802
803         if (comp->maxStep >= XPATH_MAX_STEPS) {
804             xmlXPathErrMemory(NULL, "adding step\n");
805             return(-1);
806         }
807         comp->maxStep *= 2;
808         real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
809                                       comp->maxStep * sizeof(xmlXPathStepOp));
810         if (real == NULL) {
811             comp->maxStep /= 2;
812             xmlXPathErrMemory(NULL, "adding step\n");
813             return(-1);
814         }
815         comp->steps = real;
816     }
817     comp->last = comp->nbStep;
818     comp->steps[comp->nbStep].ch1 = ch1;
819     comp->steps[comp->nbStep].ch2 = ch2;
820     comp->steps[comp->nbStep].op = op;
821     comp->steps[comp->nbStep].value = value;
822     comp->steps[comp->nbStep].value2 = value2;
823     comp->steps[comp->nbStep].value3 = value3;
824     if ((comp->dict != NULL) &&
825         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
826          (op == XPATH_OP_COLLECT))) {
827         if (value4 != NULL) {
828             comp->steps[comp->nbStep].value4 = (xmlChar *)
829                 (void *)xmlDictLookup(comp->dict, value4, -1);
830             xmlFree(value4);
831         } else
832             comp->steps[comp->nbStep].value4 = NULL;
833         if (value5 != NULL) {
834             comp->steps[comp->nbStep].value5 = (xmlChar *)
835                 (void *)xmlDictLookup(comp->dict, value5, -1);
836             xmlFree(value5);
837         } else
838             comp->steps[comp->nbStep].value5 = NULL;
839     } else {
840         comp->steps[comp->nbStep].value4 = value4;
841         comp->steps[comp->nbStep].value5 = value5;
842     }
843     comp->steps[comp->nbStep].cache = NULL;
844     return(comp->nbStep++);
845 }
846
847 /**
848  * xmlXPathCompSwap:
849  * @comp:  the compiled expression
850  * @op: operation index
851  *
852  * Swaps 2 operations in the compiled expression
853  */
854 static void
855 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
856     int tmp;
857
858 #ifndef LIBXML_THREAD_ENABLED
859     /*
860      * Since this manipulates possibly shared variables, this is
861      * disabled if one detects that the library is used in a multithreaded
862      * application
863      */
864     if (xmlXPathDisableOptimizer)
865         return;
866 #endif
867
868     tmp = op->ch1;
869     op->ch1 = op->ch2;
870     op->ch2 = tmp;
871 }
872
873 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)       \
874     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),                       \
875                         (op), (val), (val2), (val3), (val4), (val5))
876 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)                 \
877     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,               \
878                         (op), (val), (val2), (val3), (val4), (val5))
879
880 #define PUSH_LEAVE_EXPR(op, val, val2)                                  \
881 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
882
883 #define PUSH_UNARY_EXPR(op, ch, val, val2)                              \
884 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
885
886 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)                       \
887 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),                     \
888                         (val), (val2), 0 ,NULL ,NULL)
889
890 /************************************************************************
891  *                                                                      *
892  *              XPath object cache structures                           *
893  *                                                                      *
894  ************************************************************************/
895
896 /* #define XP_DEFAULT_CACHE_ON */
897
898 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
899
900 typedef struct _xmlXPathContextCache xmlXPathContextCache;
901 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
902 struct _xmlXPathContextCache {
903     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
904     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
905     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
906     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
907     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
908     int maxNodeset;
909     int maxString;
910     int maxBoolean;
911     int maxNumber;
912     int maxMisc;
913 #ifdef XP_DEBUG_OBJ_USAGE
914     int dbgCachedAll;
915     int dbgCachedNodeset;
916     int dbgCachedString;
917     int dbgCachedBool;
918     int dbgCachedNumber;
919     int dbgCachedPoint;
920     int dbgCachedRange;
921     int dbgCachedLocset;
922     int dbgCachedUsers;
923     int dbgCachedXSLTTree;
924     int dbgCachedUndefined;
925
926
927     int dbgReusedAll;
928     int dbgReusedNodeset;
929     int dbgReusedString;
930     int dbgReusedBool;
931     int dbgReusedNumber;
932     int dbgReusedPoint;
933     int dbgReusedRange;
934     int dbgReusedLocset;
935     int dbgReusedUsers;
936     int dbgReusedXSLTTree;
937     int dbgReusedUndefined;
938
939 #endif
940 };
941
942 /************************************************************************
943  *                                                                      *
944  *              Debugging related functions                             *
945  *                                                                      *
946  ************************************************************************/
947
948 #define STRANGE                                                 \
949     xmlGenericError(xmlGenericErrorContext,                             \
950             "Internal error at %s:%d\n",                                \
951             __FILE__, __LINE__);
952
953 #ifdef LIBXML_DEBUG_ENABLED
954 static void
955 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
956     int i;
957     char shift[100];
958
959     for (i = 0;((i < depth) && (i < 25));i++)
960         shift[2 * i] = shift[2 * i + 1] = ' ';
961     shift[2 * i] = shift[2 * i + 1] = 0;
962     if (cur == NULL) {
963         fprintf(output, "%s", shift);
964         fprintf(output, "Node is NULL !\n");
965         return;
966
967     }
968
969     if ((cur->type == XML_DOCUMENT_NODE) ||
970              (cur->type == XML_HTML_DOCUMENT_NODE)) {
971         fprintf(output, "%s", shift);
972         fprintf(output, " /\n");
973     } else if (cur->type == XML_ATTRIBUTE_NODE)
974         xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
975     else
976         xmlDebugDumpOneNode(output, cur, depth);
977 }
978 static void
979 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
980     xmlNodePtr tmp;
981     int i;
982     char shift[100];
983
984     for (i = 0;((i < depth) && (i < 25));i++)
985         shift[2 * i] = shift[2 * i + 1] = ' ';
986     shift[2 * i] = shift[2 * i + 1] = 0;
987     if (cur == NULL) {
988         fprintf(output, "%s", shift);
989         fprintf(output, "Node is NULL !\n");
990         return;
991
992     }
993
994     while (cur != NULL) {
995         tmp = cur;
996         cur = cur->next;
997         xmlDebugDumpOneNode(output, tmp, depth);
998     }
999 }
1000
1001 static void
1002 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1003     int i;
1004     char shift[100];
1005
1006     for (i = 0;((i < depth) && (i < 25));i++)
1007         shift[2 * i] = shift[2 * i + 1] = ' ';
1008     shift[2 * i] = shift[2 * i + 1] = 0;
1009
1010     if (cur == NULL) {
1011         fprintf(output, "%s", shift);
1012         fprintf(output, "NodeSet is NULL !\n");
1013         return;
1014
1015     }
1016
1017     if (cur != NULL) {
1018         fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1019         for (i = 0;i < cur->nodeNr;i++) {
1020             fprintf(output, "%s", shift);
1021             fprintf(output, "%d", i + 1);
1022             xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1023         }
1024     }
1025 }
1026
1027 static void
1028 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1029     int i;
1030     char shift[100];
1031
1032     for (i = 0;((i < depth) && (i < 25));i++)
1033         shift[2 * i] = shift[2 * i + 1] = ' ';
1034     shift[2 * i] = shift[2 * i + 1] = 0;
1035
1036     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1037         fprintf(output, "%s", shift);
1038         fprintf(output, "Value Tree is NULL !\n");
1039         return;
1040
1041     }
1042
1043     fprintf(output, "%s", shift);
1044     fprintf(output, "%d", i + 1);
1045     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1046 }
1047 #if defined(LIBXML_XPTR_ENABLED)
1048 static void
1049 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1050     int i;
1051     char shift[100];
1052
1053     for (i = 0;((i < depth) && (i < 25));i++)
1054         shift[2 * i] = shift[2 * i + 1] = ' ';
1055     shift[2 * i] = shift[2 * i + 1] = 0;
1056
1057     if (cur == NULL) {
1058         fprintf(output, "%s", shift);
1059         fprintf(output, "LocationSet is NULL !\n");
1060         return;
1061
1062     }
1063
1064     for (i = 0;i < cur->locNr;i++) {
1065         fprintf(output, "%s", shift);
1066         fprintf(output, "%d : ", i + 1);
1067         xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1068     }
1069 }
1070 #endif /* LIBXML_XPTR_ENABLED */
1071
1072 /**
1073  * xmlXPathDebugDumpObject:
1074  * @output:  the FILE * to dump the output
1075  * @cur:  the object to inspect
1076  * @depth:  indentation level
1077  *
1078  * Dump the content of the object for debugging purposes
1079  */
1080 void
1081 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1082     int i;
1083     char shift[100];
1084
1085     if (output == NULL) return;
1086
1087     for (i = 0;((i < depth) && (i < 25));i++)
1088         shift[2 * i] = shift[2 * i + 1] = ' ';
1089     shift[2 * i] = shift[2 * i + 1] = 0;
1090
1091
1092     fprintf(output, "%s", shift);
1093
1094     if (cur == NULL) {
1095         fprintf(output, "Object is empty (NULL)\n");
1096         return;
1097     }
1098     switch(cur->type) {
1099         case XPATH_UNDEFINED:
1100             fprintf(output, "Object is uninitialized\n");
1101             break;
1102         case XPATH_NODESET:
1103             fprintf(output, "Object is a Node Set :\n");
1104             xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1105             break;
1106         case XPATH_XSLT_TREE:
1107             fprintf(output, "Object is an XSLT value tree :\n");
1108             xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1109             break;
1110         case XPATH_BOOLEAN:
1111             fprintf(output, "Object is a Boolean : ");
1112             if (cur->boolval) fprintf(output, "true\n");
1113             else fprintf(output, "false\n");
1114             break;
1115         case XPATH_NUMBER:
1116             switch (xmlXPathIsInf(cur->floatval)) {
1117             case 1:
1118                 fprintf(output, "Object is a number : Infinity\n");
1119                 break;
1120             case -1:
1121                 fprintf(output, "Object is a number : -Infinity\n");
1122                 break;
1123             default:
1124                 if (xmlXPathIsNaN(cur->floatval)) {
1125                     fprintf(output, "Object is a number : NaN\n");
1126                 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1127                     fprintf(output, "Object is a number : 0\n");
1128                 } else {
1129                     fprintf(output, "Object is a number : %0g\n", cur->floatval);
1130                 }
1131             }
1132             break;
1133         case XPATH_STRING:
1134             fprintf(output, "Object is a string : ");
1135             xmlDebugDumpString(output, cur->stringval);
1136             fprintf(output, "\n");
1137             break;
1138         case XPATH_POINT:
1139             fprintf(output, "Object is a point : index %d in node", cur->index);
1140             xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1141             fprintf(output, "\n");
1142             break;
1143         case XPATH_RANGE:
1144             if ((cur->user2 == NULL) ||
1145                 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1146                 fprintf(output, "Object is a collapsed range :\n");
1147                 fprintf(output, "%s", shift);
1148                 if (cur->index >= 0)
1149                     fprintf(output, "index %d in ", cur->index);
1150                 fprintf(output, "node\n");
1151                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1152                                       depth + 1);
1153             } else  {
1154                 fprintf(output, "Object is a range :\n");
1155                 fprintf(output, "%s", shift);
1156                 fprintf(output, "From ");
1157                 if (cur->index >= 0)
1158                     fprintf(output, "index %d in ", cur->index);
1159                 fprintf(output, "node\n");
1160                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1161                                       depth + 1);
1162                 fprintf(output, "%s", shift);
1163                 fprintf(output, "To ");
1164                 if (cur->index2 >= 0)
1165                     fprintf(output, "index %d in ", cur->index2);
1166                 fprintf(output, "node\n");
1167                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1168                                       depth + 1);
1169                 fprintf(output, "\n");
1170             }
1171             break;
1172         case XPATH_LOCATIONSET:
1173 #if defined(LIBXML_XPTR_ENABLED)
1174             fprintf(output, "Object is a Location Set:\n");
1175             xmlXPathDebugDumpLocationSet(output,
1176                     (xmlLocationSetPtr) cur->user, depth);
1177 #endif
1178             break;
1179         case XPATH_USERS:
1180             fprintf(output, "Object is user defined\n");
1181             break;
1182     }
1183 }
1184
1185 static void
1186 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1187                              xmlXPathStepOpPtr op, int depth) {
1188     int i;
1189     char shift[100];
1190
1191     for (i = 0;((i < depth) && (i < 25));i++)
1192         shift[2 * i] = shift[2 * i + 1] = ' ';
1193     shift[2 * i] = shift[2 * i + 1] = 0;
1194
1195     fprintf(output, "%s", shift);
1196     if (op == NULL) {
1197         fprintf(output, "Step is NULL\n");
1198         return;
1199     }
1200     switch (op->op) {
1201         case XPATH_OP_END:
1202             fprintf(output, "END"); break;
1203         case XPATH_OP_AND:
1204             fprintf(output, "AND"); break;
1205         case XPATH_OP_OR:
1206             fprintf(output, "OR"); break;
1207         case XPATH_OP_EQUAL:
1208              if (op->value)
1209                  fprintf(output, "EQUAL =");
1210              else
1211                  fprintf(output, "EQUAL !=");
1212              break;
1213         case XPATH_OP_CMP:
1214              if (op->value)
1215                  fprintf(output, "CMP <");
1216              else
1217                  fprintf(output, "CMP >");
1218              if (!op->value2)
1219                  fprintf(output, "=");
1220              break;
1221         case XPATH_OP_PLUS:
1222              if (op->value == 0)
1223                  fprintf(output, "PLUS -");
1224              else if (op->value == 1)
1225                  fprintf(output, "PLUS +");
1226              else if (op->value == 2)
1227                  fprintf(output, "PLUS unary -");
1228              else if (op->value == 3)
1229                  fprintf(output, "PLUS unary - -");
1230              break;
1231         case XPATH_OP_MULT:
1232              if (op->value == 0)
1233                  fprintf(output, "MULT *");
1234              else if (op->value == 1)
1235                  fprintf(output, "MULT div");
1236              else
1237                  fprintf(output, "MULT mod");
1238              break;
1239         case XPATH_OP_UNION:
1240              fprintf(output, "UNION"); break;
1241         case XPATH_OP_ROOT:
1242              fprintf(output, "ROOT"); break;
1243         case XPATH_OP_NODE:
1244              fprintf(output, "NODE"); break;
1245         case XPATH_OP_RESET:
1246              fprintf(output, "RESET"); break;
1247         case XPATH_OP_SORT:
1248              fprintf(output, "SORT"); break;
1249         case XPATH_OP_COLLECT: {
1250             xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1251             xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1252             xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1253             const xmlChar *prefix = op->value4;
1254             const xmlChar *name = op->value5;
1255
1256             fprintf(output, "COLLECT ");
1257             switch (axis) {
1258                 case AXIS_ANCESTOR:
1259                     fprintf(output, " 'ancestors' "); break;
1260                 case AXIS_ANCESTOR_OR_SELF:
1261                     fprintf(output, " 'ancestors-or-self' "); break;
1262                 case AXIS_ATTRIBUTE:
1263                     fprintf(output, " 'attributes' "); break;
1264                 case AXIS_CHILD:
1265                     fprintf(output, " 'child' "); break;
1266                 case AXIS_DESCENDANT:
1267                     fprintf(output, " 'descendant' "); break;
1268                 case AXIS_DESCENDANT_OR_SELF:
1269                     fprintf(output, " 'descendant-or-self' "); break;
1270                 case AXIS_FOLLOWING:
1271                     fprintf(output, " 'following' "); break;
1272                 case AXIS_FOLLOWING_SIBLING:
1273                     fprintf(output, " 'following-siblings' "); break;
1274                 case AXIS_NAMESPACE:
1275                     fprintf(output, " 'namespace' "); break;
1276                 case AXIS_PARENT:
1277                     fprintf(output, " 'parent' "); break;
1278                 case AXIS_PRECEDING:
1279                     fprintf(output, " 'preceding' "); break;
1280                 case AXIS_PRECEDING_SIBLING:
1281                     fprintf(output, " 'preceding-sibling' "); break;
1282                 case AXIS_SELF:
1283                     fprintf(output, " 'self' "); break;
1284             }
1285             switch (test) {
1286                 case NODE_TEST_NONE:
1287                     fprintf(output, "'none' "); break;
1288                 case NODE_TEST_TYPE:
1289                     fprintf(output, "'type' "); break;
1290                 case NODE_TEST_PI:
1291                     fprintf(output, "'PI' "); break;
1292                 case NODE_TEST_ALL:
1293                     fprintf(output, "'all' "); break;
1294                 case NODE_TEST_NS:
1295                     fprintf(output, "'namespace' "); break;
1296                 case NODE_TEST_NAME:
1297                     fprintf(output, "'name' "); break;
1298             }
1299             switch (type) {
1300                 case NODE_TYPE_NODE:
1301                     fprintf(output, "'node' "); break;
1302                 case NODE_TYPE_COMMENT:
1303                     fprintf(output, "'comment' "); break;
1304                 case NODE_TYPE_TEXT:
1305                     fprintf(output, "'text' "); break;
1306                 case NODE_TYPE_PI:
1307                     fprintf(output, "'PI' "); break;
1308             }
1309             if (prefix != NULL)
1310                 fprintf(output, "%s:", prefix);
1311             if (name != NULL)
1312                 fprintf(output, "%s", (const char *) name);
1313             break;
1314
1315         }
1316         case XPATH_OP_VALUE: {
1317             xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1318
1319             fprintf(output, "ELEM ");
1320             xmlXPathDebugDumpObject(output, object, 0);
1321             goto finish;
1322         }
1323         case XPATH_OP_VARIABLE: {
1324             const xmlChar *prefix = op->value5;
1325             const xmlChar *name = op->value4;
1326
1327             if (prefix != NULL)
1328                 fprintf(output, "VARIABLE %s:%s", prefix, name);
1329             else
1330                 fprintf(output, "VARIABLE %s", name);
1331             break;
1332         }
1333         case XPATH_OP_FUNCTION: {
1334             int nbargs = op->value;
1335             const xmlChar *prefix = op->value5;
1336             const xmlChar *name = op->value4;
1337
1338             if (prefix != NULL)
1339                 fprintf(output, "FUNCTION %s:%s(%d args)",
1340                         prefix, name, nbargs);
1341             else
1342                 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1343             break;
1344         }
1345         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1346         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1347         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1348 #ifdef LIBXML_XPTR_ENABLED
1349         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1350 #endif
1351         default:
1352         fprintf(output, "UNKNOWN %d\n", op->op); return;
1353     }
1354     fprintf(output, "\n");
1355 finish:
1356     if (op->ch1 >= 0)
1357         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1358     if (op->ch2 >= 0)
1359         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1360 }
1361
1362 /**
1363  * xmlXPathDebugDumpCompExpr:
1364  * @output:  the FILE * for the output
1365  * @comp:  the precompiled XPath expression
1366  * @depth:  the indentation level.
1367  *
1368  * Dumps the tree of the compiled XPath expression.
1369  */
1370 void
1371 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1372                           int depth) {
1373     int i;
1374     char shift[100];
1375
1376     if ((output == NULL) || (comp == NULL)) return;
1377
1378     for (i = 0;((i < depth) && (i < 25));i++)
1379         shift[2 * i] = shift[2 * i + 1] = ' ';
1380     shift[2 * i] = shift[2 * i + 1] = 0;
1381
1382     fprintf(output, "%s", shift);
1383
1384     fprintf(output, "Compiled Expression : %d elements\n",
1385             comp->nbStep);
1386     i = comp->last;
1387     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1388 }
1389
1390 #ifdef XP_DEBUG_OBJ_USAGE
1391
1392 /*
1393 * XPath object usage related debugging variables.
1394 */
1395 static int xmlXPathDebugObjCounterUndefined = 0;
1396 static int xmlXPathDebugObjCounterNodeset = 0;
1397 static int xmlXPathDebugObjCounterBool = 0;
1398 static int xmlXPathDebugObjCounterNumber = 0;
1399 static int xmlXPathDebugObjCounterString = 0;
1400 static int xmlXPathDebugObjCounterPoint = 0;
1401 static int xmlXPathDebugObjCounterRange = 0;
1402 static int xmlXPathDebugObjCounterLocset = 0;
1403 static int xmlXPathDebugObjCounterUsers = 0;
1404 static int xmlXPathDebugObjCounterXSLTTree = 0;
1405 static int xmlXPathDebugObjCounterAll = 0;
1406
1407 static int xmlXPathDebugObjTotalUndefined = 0;
1408 static int xmlXPathDebugObjTotalNodeset = 0;
1409 static int xmlXPathDebugObjTotalBool = 0;
1410 static int xmlXPathDebugObjTotalNumber = 0;
1411 static int xmlXPathDebugObjTotalString = 0;
1412 static int xmlXPathDebugObjTotalPoint = 0;
1413 static int xmlXPathDebugObjTotalRange = 0;
1414 static int xmlXPathDebugObjTotalLocset = 0;
1415 static int xmlXPathDebugObjTotalUsers = 0;
1416 static int xmlXPathDebugObjTotalXSLTTree = 0;
1417 static int xmlXPathDebugObjTotalAll = 0;
1418
1419 static int xmlXPathDebugObjMaxUndefined = 0;
1420 static int xmlXPathDebugObjMaxNodeset = 0;
1421 static int xmlXPathDebugObjMaxBool = 0;
1422 static int xmlXPathDebugObjMaxNumber = 0;
1423 static int xmlXPathDebugObjMaxString = 0;
1424 static int xmlXPathDebugObjMaxPoint = 0;
1425 static int xmlXPathDebugObjMaxRange = 0;
1426 static int xmlXPathDebugObjMaxLocset = 0;
1427 static int xmlXPathDebugObjMaxUsers = 0;
1428 static int xmlXPathDebugObjMaxXSLTTree = 0;
1429 static int xmlXPathDebugObjMaxAll = 0;
1430
1431 /* REVISIT TODO: Make this static when committing */
1432 static void
1433 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1434 {
1435     if (ctxt != NULL) {
1436         if (ctxt->cache != NULL) {
1437             xmlXPathContextCachePtr cache =
1438                 (xmlXPathContextCachePtr) ctxt->cache;
1439
1440             cache->dbgCachedAll = 0;
1441             cache->dbgCachedNodeset = 0;
1442             cache->dbgCachedString = 0;
1443             cache->dbgCachedBool = 0;
1444             cache->dbgCachedNumber = 0;
1445             cache->dbgCachedPoint = 0;
1446             cache->dbgCachedRange = 0;
1447             cache->dbgCachedLocset = 0;
1448             cache->dbgCachedUsers = 0;
1449             cache->dbgCachedXSLTTree = 0;
1450             cache->dbgCachedUndefined = 0;
1451
1452             cache->dbgReusedAll = 0;
1453             cache->dbgReusedNodeset = 0;
1454             cache->dbgReusedString = 0;
1455             cache->dbgReusedBool = 0;
1456             cache->dbgReusedNumber = 0;
1457             cache->dbgReusedPoint = 0;
1458             cache->dbgReusedRange = 0;
1459             cache->dbgReusedLocset = 0;
1460             cache->dbgReusedUsers = 0;
1461             cache->dbgReusedXSLTTree = 0;
1462             cache->dbgReusedUndefined = 0;
1463         }
1464     }
1465
1466     xmlXPathDebugObjCounterUndefined = 0;
1467     xmlXPathDebugObjCounterNodeset = 0;
1468     xmlXPathDebugObjCounterBool = 0;
1469     xmlXPathDebugObjCounterNumber = 0;
1470     xmlXPathDebugObjCounterString = 0;
1471     xmlXPathDebugObjCounterPoint = 0;
1472     xmlXPathDebugObjCounterRange = 0;
1473     xmlXPathDebugObjCounterLocset = 0;
1474     xmlXPathDebugObjCounterUsers = 0;
1475     xmlXPathDebugObjCounterXSLTTree = 0;
1476     xmlXPathDebugObjCounterAll = 0;
1477
1478     xmlXPathDebugObjTotalUndefined = 0;
1479     xmlXPathDebugObjTotalNodeset = 0;
1480     xmlXPathDebugObjTotalBool = 0;
1481     xmlXPathDebugObjTotalNumber = 0;
1482     xmlXPathDebugObjTotalString = 0;
1483     xmlXPathDebugObjTotalPoint = 0;
1484     xmlXPathDebugObjTotalRange = 0;
1485     xmlXPathDebugObjTotalLocset = 0;
1486     xmlXPathDebugObjTotalUsers = 0;
1487     xmlXPathDebugObjTotalXSLTTree = 0;
1488     xmlXPathDebugObjTotalAll = 0;
1489
1490     xmlXPathDebugObjMaxUndefined = 0;
1491     xmlXPathDebugObjMaxNodeset = 0;
1492     xmlXPathDebugObjMaxBool = 0;
1493     xmlXPathDebugObjMaxNumber = 0;
1494     xmlXPathDebugObjMaxString = 0;
1495     xmlXPathDebugObjMaxPoint = 0;
1496     xmlXPathDebugObjMaxRange = 0;
1497     xmlXPathDebugObjMaxLocset = 0;
1498     xmlXPathDebugObjMaxUsers = 0;
1499     xmlXPathDebugObjMaxXSLTTree = 0;
1500     xmlXPathDebugObjMaxAll = 0;
1501
1502 }
1503
1504 static void
1505 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1506                               xmlXPathObjectType objType)
1507 {
1508     int isCached = 0;
1509
1510     if (ctxt != NULL) {
1511         if (ctxt->cache != NULL) {
1512             xmlXPathContextCachePtr cache =
1513                 (xmlXPathContextCachePtr) ctxt->cache;
1514
1515             isCached = 1;
1516
1517             cache->dbgReusedAll++;
1518             switch (objType) {
1519                 case XPATH_UNDEFINED:
1520                     cache->dbgReusedUndefined++;
1521                     break;
1522                 case XPATH_NODESET:
1523                     cache->dbgReusedNodeset++;
1524                     break;
1525                 case XPATH_BOOLEAN:
1526                     cache->dbgReusedBool++;
1527                     break;
1528                 case XPATH_NUMBER:
1529                     cache->dbgReusedNumber++;
1530                     break;
1531                 case XPATH_STRING:
1532                     cache->dbgReusedString++;
1533                     break;
1534                 case XPATH_POINT:
1535                     cache->dbgReusedPoint++;
1536                     break;
1537                 case XPATH_RANGE:
1538                     cache->dbgReusedRange++;
1539                     break;
1540                 case XPATH_LOCATIONSET:
1541                     cache->dbgReusedLocset++;
1542                     break;
1543                 case XPATH_USERS:
1544                     cache->dbgReusedUsers++;
1545                     break;
1546                 case XPATH_XSLT_TREE:
1547                     cache->dbgReusedXSLTTree++;
1548                     break;
1549                 default:
1550                     break;
1551             }
1552         }
1553     }
1554
1555     switch (objType) {
1556         case XPATH_UNDEFINED:
1557             if (! isCached)
1558                 xmlXPathDebugObjTotalUndefined++;
1559             xmlXPathDebugObjCounterUndefined++;
1560             if (xmlXPathDebugObjCounterUndefined >
1561                 xmlXPathDebugObjMaxUndefined)
1562                 xmlXPathDebugObjMaxUndefined =
1563                     xmlXPathDebugObjCounterUndefined;
1564             break;
1565         case XPATH_NODESET:
1566             if (! isCached)
1567                 xmlXPathDebugObjTotalNodeset++;
1568             xmlXPathDebugObjCounterNodeset++;
1569             if (xmlXPathDebugObjCounterNodeset >
1570                 xmlXPathDebugObjMaxNodeset)
1571                 xmlXPathDebugObjMaxNodeset =
1572                     xmlXPathDebugObjCounterNodeset;
1573             break;
1574         case XPATH_BOOLEAN:
1575             if (! isCached)
1576                 xmlXPathDebugObjTotalBool++;
1577             xmlXPathDebugObjCounterBool++;
1578             if (xmlXPathDebugObjCounterBool >
1579                 xmlXPathDebugObjMaxBool)
1580                 xmlXPathDebugObjMaxBool =
1581                     xmlXPathDebugObjCounterBool;
1582             break;
1583         case XPATH_NUMBER:
1584             if (! isCached)
1585                 xmlXPathDebugObjTotalNumber++;
1586             xmlXPathDebugObjCounterNumber++;
1587             if (xmlXPathDebugObjCounterNumber >
1588                 xmlXPathDebugObjMaxNumber)
1589                 xmlXPathDebugObjMaxNumber =
1590                     xmlXPathDebugObjCounterNumber;
1591             break;
1592         case XPATH_STRING:
1593             if (! isCached)
1594                 xmlXPathDebugObjTotalString++;
1595             xmlXPathDebugObjCounterString++;
1596             if (xmlXPathDebugObjCounterString >
1597                 xmlXPathDebugObjMaxString)
1598                 xmlXPathDebugObjMaxString =
1599                     xmlXPathDebugObjCounterString;
1600             break;
1601         case XPATH_POINT:
1602             if (! isCached)
1603                 xmlXPathDebugObjTotalPoint++;
1604             xmlXPathDebugObjCounterPoint++;
1605             if (xmlXPathDebugObjCounterPoint >
1606                 xmlXPathDebugObjMaxPoint)
1607                 xmlXPathDebugObjMaxPoint =
1608                     xmlXPathDebugObjCounterPoint;
1609             break;
1610         case XPATH_RANGE:
1611             if (! isCached)
1612                 xmlXPathDebugObjTotalRange++;
1613             xmlXPathDebugObjCounterRange++;
1614             if (xmlXPathDebugObjCounterRange >
1615                 xmlXPathDebugObjMaxRange)
1616                 xmlXPathDebugObjMaxRange =
1617                     xmlXPathDebugObjCounterRange;
1618             break;
1619         case XPATH_LOCATIONSET:
1620             if (! isCached)
1621                 xmlXPathDebugObjTotalLocset++;
1622             xmlXPathDebugObjCounterLocset++;
1623             if (xmlXPathDebugObjCounterLocset >
1624                 xmlXPathDebugObjMaxLocset)
1625                 xmlXPathDebugObjMaxLocset =
1626                     xmlXPathDebugObjCounterLocset;
1627             break;
1628         case XPATH_USERS:
1629             if (! isCached)
1630                 xmlXPathDebugObjTotalUsers++;
1631             xmlXPathDebugObjCounterUsers++;
1632             if (xmlXPathDebugObjCounterUsers >
1633                 xmlXPathDebugObjMaxUsers)
1634                 xmlXPathDebugObjMaxUsers =
1635                     xmlXPathDebugObjCounterUsers;
1636             break;
1637         case XPATH_XSLT_TREE:
1638             if (! isCached)
1639                 xmlXPathDebugObjTotalXSLTTree++;
1640             xmlXPathDebugObjCounterXSLTTree++;
1641             if (xmlXPathDebugObjCounterXSLTTree >
1642                 xmlXPathDebugObjMaxXSLTTree)
1643                 xmlXPathDebugObjMaxXSLTTree =
1644                     xmlXPathDebugObjCounterXSLTTree;
1645             break;
1646         default:
1647             break;
1648     }
1649     if (! isCached)
1650         xmlXPathDebugObjTotalAll++;
1651     xmlXPathDebugObjCounterAll++;
1652     if (xmlXPathDebugObjCounterAll >
1653         xmlXPathDebugObjMaxAll)
1654         xmlXPathDebugObjMaxAll =
1655             xmlXPathDebugObjCounterAll;
1656 }
1657
1658 static void
1659 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1660                               xmlXPathObjectType objType)
1661 {
1662     int isCached = 0;
1663
1664     if (ctxt != NULL) {
1665         if (ctxt->cache != NULL) {
1666             xmlXPathContextCachePtr cache =
1667                 (xmlXPathContextCachePtr) ctxt->cache;
1668
1669             isCached = 1;
1670
1671             cache->dbgCachedAll++;
1672             switch (objType) {
1673                 case XPATH_UNDEFINED:
1674                     cache->dbgCachedUndefined++;
1675                     break;
1676                 case XPATH_NODESET:
1677                     cache->dbgCachedNodeset++;
1678                     break;
1679                 case XPATH_BOOLEAN:
1680                     cache->dbgCachedBool++;
1681                     break;
1682                 case XPATH_NUMBER:
1683                     cache->dbgCachedNumber++;
1684                     break;
1685                 case XPATH_STRING:
1686                     cache->dbgCachedString++;
1687                     break;
1688                 case XPATH_POINT:
1689                     cache->dbgCachedPoint++;
1690                     break;
1691                 case XPATH_RANGE:
1692                     cache->dbgCachedRange++;
1693                     break;
1694                 case XPATH_LOCATIONSET:
1695                     cache->dbgCachedLocset++;
1696                     break;
1697                 case XPATH_USERS:
1698                     cache->dbgCachedUsers++;
1699                     break;
1700                 case XPATH_XSLT_TREE:
1701                     cache->dbgCachedXSLTTree++;
1702                     break;
1703                 default:
1704                     break;
1705             }
1706
1707         }
1708     }
1709     switch (objType) {
1710         case XPATH_UNDEFINED:
1711             xmlXPathDebugObjCounterUndefined--;
1712             break;
1713         case XPATH_NODESET:
1714             xmlXPathDebugObjCounterNodeset--;
1715             break;
1716         case XPATH_BOOLEAN:
1717             xmlXPathDebugObjCounterBool--;
1718             break;
1719         case XPATH_NUMBER:
1720             xmlXPathDebugObjCounterNumber--;
1721             break;
1722         case XPATH_STRING:
1723             xmlXPathDebugObjCounterString--;
1724             break;
1725         case XPATH_POINT:
1726             xmlXPathDebugObjCounterPoint--;
1727             break;
1728         case XPATH_RANGE:
1729             xmlXPathDebugObjCounterRange--;
1730             break;
1731         case XPATH_LOCATIONSET:
1732             xmlXPathDebugObjCounterLocset--;
1733             break;
1734         case XPATH_USERS:
1735             xmlXPathDebugObjCounterUsers--;
1736             break;
1737         case XPATH_XSLT_TREE:
1738             xmlXPathDebugObjCounterXSLTTree--;
1739             break;
1740         default:
1741             break;
1742     }
1743     xmlXPathDebugObjCounterAll--;
1744 }
1745
1746 /* REVISIT TODO: Make this static when committing */
1747 static void
1748 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1749 {
1750     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1751         reqXSLTTree, reqUndefined;
1752     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1753         caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1754     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1755         reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1756     int leftObjs = xmlXPathDebugObjCounterAll;
1757
1758     reqAll = xmlXPathDebugObjTotalAll;
1759     reqNodeset = xmlXPathDebugObjTotalNodeset;
1760     reqString = xmlXPathDebugObjTotalString;
1761     reqBool = xmlXPathDebugObjTotalBool;
1762     reqNumber = xmlXPathDebugObjTotalNumber;
1763     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1764     reqUndefined = xmlXPathDebugObjTotalUndefined;
1765
1766     printf("# XPath object usage:\n");
1767
1768     if (ctxt != NULL) {
1769         if (ctxt->cache != NULL) {
1770             xmlXPathContextCachePtr cache =
1771                 (xmlXPathContextCachePtr) ctxt->cache;
1772
1773             reAll = cache->dbgReusedAll;
1774             reqAll += reAll;
1775             reNodeset = cache->dbgReusedNodeset;
1776             reqNodeset += reNodeset;
1777             reString = cache->dbgReusedString;
1778             reqString += reString;
1779             reBool = cache->dbgReusedBool;
1780             reqBool += reBool;
1781             reNumber = cache->dbgReusedNumber;
1782             reqNumber += reNumber;
1783             reXSLTTree = cache->dbgReusedXSLTTree;
1784             reqXSLTTree += reXSLTTree;
1785             reUndefined = cache->dbgReusedUndefined;
1786             reqUndefined += reUndefined;
1787
1788             caAll = cache->dbgCachedAll;
1789             caBool = cache->dbgCachedBool;
1790             caNodeset = cache->dbgCachedNodeset;
1791             caString = cache->dbgCachedString;
1792             caNumber = cache->dbgCachedNumber;
1793             caXSLTTree = cache->dbgCachedXSLTTree;
1794             caUndefined = cache->dbgCachedUndefined;
1795
1796             if (cache->nodesetObjs)
1797                 leftObjs -= cache->nodesetObjs->number;
1798             if (cache->stringObjs)
1799                 leftObjs -= cache->stringObjs->number;
1800             if (cache->booleanObjs)
1801                 leftObjs -= cache->booleanObjs->number;
1802             if (cache->numberObjs)
1803                 leftObjs -= cache->numberObjs->number;
1804             if (cache->miscObjs)
1805                 leftObjs -= cache->miscObjs->number;
1806         }
1807     }
1808
1809     printf("# all\n");
1810     printf("#   total  : %d\n", reqAll);
1811     printf("#   left  : %d\n", leftObjs);
1812     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
1813     printf("#   reused : %d\n", reAll);
1814     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
1815
1816     printf("# node-sets\n");
1817     printf("#   total  : %d\n", reqNodeset);
1818     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
1819     printf("#   reused : %d\n", reNodeset);
1820     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
1821
1822     printf("# strings\n");
1823     printf("#   total  : %d\n", reqString);
1824     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
1825     printf("#   reused : %d\n", reString);
1826     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
1827
1828     printf("# booleans\n");
1829     printf("#   total  : %d\n", reqBool);
1830     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
1831     printf("#   reused : %d\n", reBool);
1832     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
1833
1834     printf("# numbers\n");
1835     printf("#   total  : %d\n", reqNumber);
1836     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
1837     printf("#   reused : %d\n", reNumber);
1838     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
1839
1840     printf("# XSLT result tree fragments\n");
1841     printf("#   total  : %d\n", reqXSLTTree);
1842     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1843     printf("#   reused : %d\n", reXSLTTree);
1844     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
1845
1846     printf("# undefined\n");
1847     printf("#   total  : %d\n", reqUndefined);
1848     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
1849     printf("#   reused : %d\n", reUndefined);
1850     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
1851
1852 }
1853
1854 #endif /* XP_DEBUG_OBJ_USAGE */
1855
1856 #endif /* LIBXML_DEBUG_ENABLED */
1857
1858 /************************************************************************
1859  *                                                                      *
1860  *                      XPath object caching                            *
1861  *                                                                      *
1862  ************************************************************************/
1863
1864 /**
1865  * xmlXPathNewCache:
1866  *
1867  * Create a new object cache
1868  *
1869  * Returns the xmlXPathCache just allocated.
1870  */
1871 static xmlXPathContextCachePtr
1872 xmlXPathNewCache(void)
1873 {
1874     xmlXPathContextCachePtr ret;
1875
1876     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1877     if (ret == NULL) {
1878         xmlXPathErrMemory(NULL, "creating object cache\n");
1879         return(NULL);
1880     }
1881     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1882     ret->maxNodeset = 100;
1883     ret->maxString = 100;
1884     ret->maxBoolean = 100;
1885     ret->maxNumber = 100;
1886     ret->maxMisc = 100;
1887     return(ret);
1888 }
1889
1890 static void
1891 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1892 {
1893     int i;
1894     xmlXPathObjectPtr obj;
1895
1896     if (list == NULL)
1897         return;
1898
1899     for (i = 0; i < list->number; i++) {
1900         obj = list->items[i];
1901         /*
1902         * Note that it is already assured that we don't need to
1903         * look out for namespace nodes in the node-set.
1904         */
1905         if (obj->nodesetval != NULL) {
1906             if (obj->nodesetval->nodeTab != NULL)
1907                 xmlFree(obj->nodesetval->nodeTab);
1908             xmlFree(obj->nodesetval);
1909         }
1910         xmlFree(obj);
1911 #ifdef XP_DEBUG_OBJ_USAGE
1912         xmlXPathDebugObjCounterAll--;
1913 #endif
1914     }
1915     xmlPointerListFree(list);
1916 }
1917
1918 static void
1919 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1920 {
1921     if (cache == NULL)
1922         return;
1923     if (cache->nodesetObjs)
1924         xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1925     if (cache->stringObjs)
1926         xmlXPathCacheFreeObjectList(cache->stringObjs);
1927     if (cache->booleanObjs)
1928         xmlXPathCacheFreeObjectList(cache->booleanObjs);
1929     if (cache->numberObjs)
1930         xmlXPathCacheFreeObjectList(cache->numberObjs);
1931     if (cache->miscObjs)
1932         xmlXPathCacheFreeObjectList(cache->miscObjs);
1933     xmlFree(cache);
1934 }
1935
1936 /**
1937  * xmlXPathContextSetCache:
1938  *
1939  * @ctxt:  the XPath context
1940  * @active: enables/disables (creates/frees) the cache
1941  * @value: a value with semantics dependant on @options
1942  * @options: options (currently only the value 0 is used)
1943  *
1944  * Creates/frees an object cache on the XPath context.
1945  * If activates XPath objects (xmlXPathObject) will be cached internally
1946  * to be reused.
1947  * @options:
1948  *   0: This will set the XPath object caching:
1949  *      @value:
1950  *        This will set the maximum number of XPath objects
1951  *        to be cached per slot
1952  *        There are 5 slots for: node-set, string, number, boolean, and
1953  *        misc objects. Use <0 for the default number (100).
1954  *   Other values for @options have currently no effect.
1955  *
1956  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1957  */
1958 int
1959 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1960                         int active,
1961                         int value,
1962                         int options)
1963 {
1964     if (ctxt == NULL)
1965         return(-1);
1966     if (active) {
1967         xmlXPathContextCachePtr cache;
1968
1969         if (ctxt->cache == NULL) {
1970             ctxt->cache = xmlXPathNewCache();
1971             if (ctxt->cache == NULL)
1972                 return(-1);
1973         }
1974         cache = (xmlXPathContextCachePtr) ctxt->cache;
1975         if (options == 0) {
1976             if (value < 0)
1977                 value = 100;
1978             cache->maxNodeset = value;
1979             cache->maxString = value;
1980             cache->maxNumber = value;
1981             cache->maxBoolean = value;
1982             cache->maxMisc = value;
1983         }
1984     } else if (ctxt->cache != NULL) {
1985         xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1986         ctxt->cache = NULL;
1987     }
1988     return(0);
1989 }
1990
1991 /**
1992  * xmlXPathCacheWrapNodeSet:
1993  * @ctxt: the XPath context
1994  * @val:  the NodePtr value
1995  *
1996  * This is the cached version of xmlXPathWrapNodeSet().
1997  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1998  *
1999  * Returns the created or reused object.
2000  */
2001 static xmlXPathObjectPtr
2002 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2003 {
2004     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2005         xmlXPathContextCachePtr cache =
2006             (xmlXPathContextCachePtr) ctxt->cache;
2007
2008         if ((cache->miscObjs != NULL) &&
2009             (cache->miscObjs->number != 0))
2010         {
2011             xmlXPathObjectPtr ret;
2012
2013             ret = (xmlXPathObjectPtr)
2014                 cache->miscObjs->items[--cache->miscObjs->number];
2015             ret->type = XPATH_NODESET;
2016             ret->nodesetval = val;
2017 #ifdef XP_DEBUG_OBJ_USAGE
2018             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2019 #endif
2020             return(ret);
2021         }
2022     }
2023
2024     return(xmlXPathWrapNodeSet(val));
2025
2026 }
2027
2028 /**
2029  * xmlXPathCacheWrapString:
2030  * @ctxt: the XPath context
2031  * @val:  the xmlChar * value
2032  *
2033  * This is the cached version of xmlXPathWrapString().
2034  * Wraps the @val string into an XPath object.
2035  *
2036  * Returns the created or reused object.
2037  */
2038 static xmlXPathObjectPtr
2039 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2040 {
2041     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2042         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2043
2044         if ((cache->stringObjs != NULL) &&
2045             (cache->stringObjs->number != 0))
2046         {
2047
2048             xmlXPathObjectPtr ret;
2049
2050             ret = (xmlXPathObjectPtr)
2051                 cache->stringObjs->items[--cache->stringObjs->number];
2052             ret->type = XPATH_STRING;
2053             ret->stringval = val;
2054 #ifdef XP_DEBUG_OBJ_USAGE
2055             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2056 #endif
2057             return(ret);
2058         } else if ((cache->miscObjs != NULL) &&
2059             (cache->miscObjs->number != 0))
2060         {
2061             xmlXPathObjectPtr ret;
2062             /*
2063             * Fallback to misc-cache.
2064             */
2065             ret = (xmlXPathObjectPtr)
2066                 cache->miscObjs->items[--cache->miscObjs->number];
2067
2068             ret->type = XPATH_STRING;
2069             ret->stringval = val;
2070 #ifdef XP_DEBUG_OBJ_USAGE
2071             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2072 #endif
2073             return(ret);
2074         }
2075     }
2076     return(xmlXPathWrapString(val));
2077 }
2078
2079 /**
2080  * xmlXPathCacheNewNodeSet:
2081  * @ctxt: the XPath context
2082  * @val:  the NodePtr value
2083  *
2084  * This is the cached version of xmlXPathNewNodeSet().
2085  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2086  * it with the single Node @val
2087  *
2088  * Returns the created or reused object.
2089  */
2090 static xmlXPathObjectPtr
2091 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2092 {
2093     if ((ctxt != NULL) && (ctxt->cache)) {
2094         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2095
2096         if ((cache->nodesetObjs != NULL) &&
2097             (cache->nodesetObjs->number != 0))
2098         {
2099             xmlXPathObjectPtr ret;
2100             /*
2101             * Use the nodset-cache.
2102             */
2103             ret = (xmlXPathObjectPtr)
2104                 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2105             ret->type = XPATH_NODESET;
2106             ret->boolval = 0;
2107             if (val) {
2108                 if ((ret->nodesetval->nodeMax == 0) ||
2109                     (val->type == XML_NAMESPACE_DECL))
2110                 {
2111                     xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2112                 } else {
2113                     ret->nodesetval->nodeTab[0] = val;
2114                     ret->nodesetval->nodeNr = 1;
2115                 }
2116             }
2117 #ifdef XP_DEBUG_OBJ_USAGE
2118             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2119 #endif
2120             return(ret);
2121         } else if ((cache->miscObjs != NULL) &&
2122             (cache->miscObjs->number != 0))
2123         {
2124             xmlXPathObjectPtr ret;
2125             /*
2126             * Fallback to misc-cache.
2127             */
2128
2129             ret = (xmlXPathObjectPtr)
2130                 cache->miscObjs->items[--cache->miscObjs->number];
2131
2132             ret->type = XPATH_NODESET;
2133             ret->boolval = 0;
2134             ret->nodesetval = xmlXPathNodeSetCreate(val);
2135             if (ret->nodesetval == NULL) {
2136                 ctxt->lastError.domain = XML_FROM_XPATH;
2137                 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2138                 return(NULL);
2139             }
2140 #ifdef XP_DEBUG_OBJ_USAGE
2141             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2142 #endif
2143             return(ret);
2144         }
2145     }
2146     return(xmlXPathNewNodeSet(val));
2147 }
2148
2149 /**
2150  * xmlXPathCacheNewCString:
2151  * @ctxt: the XPath context
2152  * @val:  the char * value
2153  *
2154  * This is the cached version of xmlXPathNewCString().
2155  * Acquire an xmlXPathObjectPtr of type string and of value @val
2156  *
2157  * Returns the created or reused object.
2158  */
2159 static xmlXPathObjectPtr
2160 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2161 {
2162     if ((ctxt != NULL) && (ctxt->cache)) {
2163         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2164
2165         if ((cache->stringObjs != NULL) &&
2166             (cache->stringObjs->number != 0))
2167         {
2168             xmlXPathObjectPtr ret;
2169
2170             ret = (xmlXPathObjectPtr)
2171                 cache->stringObjs->items[--cache->stringObjs->number];
2172
2173             ret->type = XPATH_STRING;
2174             ret->stringval = xmlStrdup(BAD_CAST val);
2175 #ifdef XP_DEBUG_OBJ_USAGE
2176             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2177 #endif
2178             return(ret);
2179         } else if ((cache->miscObjs != NULL) &&
2180             (cache->miscObjs->number != 0))
2181         {
2182             xmlXPathObjectPtr ret;
2183
2184             ret = (xmlXPathObjectPtr)
2185                 cache->miscObjs->items[--cache->miscObjs->number];
2186
2187             ret->type = XPATH_STRING;
2188             ret->stringval = xmlStrdup(BAD_CAST val);
2189 #ifdef XP_DEBUG_OBJ_USAGE
2190             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2191 #endif
2192             return(ret);
2193         }
2194     }
2195     return(xmlXPathNewCString(val));
2196 }
2197
2198 /**
2199  * xmlXPathCacheNewString:
2200  * @ctxt: the XPath context
2201  * @val:  the xmlChar * value
2202  *
2203  * This is the cached version of xmlXPathNewString().
2204  * Acquire an xmlXPathObjectPtr of type string and of value @val
2205  *
2206  * Returns the created or reused object.
2207  */
2208 static xmlXPathObjectPtr
2209 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2210 {
2211     if ((ctxt != NULL) && (ctxt->cache)) {
2212         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2213
2214         if ((cache->stringObjs != NULL) &&
2215             (cache->stringObjs->number != 0))
2216         {
2217             xmlXPathObjectPtr ret;
2218
2219             ret = (xmlXPathObjectPtr)
2220                 cache->stringObjs->items[--cache->stringObjs->number];
2221             ret->type = XPATH_STRING;
2222             if (val != NULL)
2223                 ret->stringval = xmlStrdup(val);
2224             else
2225                 ret->stringval = xmlStrdup((const xmlChar *)"");
2226 #ifdef XP_DEBUG_OBJ_USAGE
2227             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2228 #endif
2229             return(ret);
2230         } else if ((cache->miscObjs != NULL) &&
2231             (cache->miscObjs->number != 0))
2232         {
2233             xmlXPathObjectPtr ret;
2234
2235             ret = (xmlXPathObjectPtr)
2236                 cache->miscObjs->items[--cache->miscObjs->number];
2237
2238             ret->type = XPATH_STRING;
2239             if (val != NULL)
2240                 ret->stringval = xmlStrdup(val);
2241             else
2242                 ret->stringval = xmlStrdup((const xmlChar *)"");
2243 #ifdef XP_DEBUG_OBJ_USAGE
2244             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2245 #endif
2246             return(ret);
2247         }
2248     }
2249     return(xmlXPathNewString(val));
2250 }
2251
2252 /**
2253  * xmlXPathCacheNewBoolean:
2254  * @ctxt: the XPath context
2255  * @val:  the boolean value
2256  *
2257  * This is the cached version of xmlXPathNewBoolean().
2258  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2259  *
2260  * Returns the created or reused object.
2261  */
2262 static xmlXPathObjectPtr
2263 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2264 {
2265     if ((ctxt != NULL) && (ctxt->cache)) {
2266         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2267
2268         if ((cache->booleanObjs != NULL) &&
2269             (cache->booleanObjs->number != 0))
2270         {
2271             xmlXPathObjectPtr ret;
2272
2273             ret = (xmlXPathObjectPtr)
2274                 cache->booleanObjs->items[--cache->booleanObjs->number];
2275             ret->type = XPATH_BOOLEAN;
2276             ret->boolval = (val != 0);
2277 #ifdef XP_DEBUG_OBJ_USAGE
2278             xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2279 #endif
2280             return(ret);
2281         } else if ((cache->miscObjs != NULL) &&
2282             (cache->miscObjs->number != 0))
2283         {
2284             xmlXPathObjectPtr ret;
2285
2286             ret = (xmlXPathObjectPtr)
2287                 cache->miscObjs->items[--cache->miscObjs->number];
2288
2289             ret->type = XPATH_BOOLEAN;
2290             ret->boolval = (val != 0);
2291 #ifdef XP_DEBUG_OBJ_USAGE
2292             xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2293 #endif
2294             return(ret);
2295         }
2296     }
2297     return(xmlXPathNewBoolean(val));
2298 }
2299
2300 /**
2301  * xmlXPathCacheNewFloat:
2302  * @ctxt: the XPath context
2303  * @val:  the double value
2304  *
2305  * This is the cached version of xmlXPathNewFloat().
2306  * Acquires an xmlXPathObjectPtr of type double and of value @val
2307  *
2308  * Returns the created or reused object.
2309  */
2310 static xmlXPathObjectPtr
2311 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2312 {
2313      if ((ctxt != NULL) && (ctxt->cache)) {
2314         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2315
2316         if ((cache->numberObjs != NULL) &&
2317             (cache->numberObjs->number != 0))
2318         {
2319             xmlXPathObjectPtr ret;
2320
2321             ret = (xmlXPathObjectPtr)
2322                 cache->numberObjs->items[--cache->numberObjs->number];
2323             ret->type = XPATH_NUMBER;
2324             ret->floatval = val;
2325 #ifdef XP_DEBUG_OBJ_USAGE
2326             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2327 #endif
2328             return(ret);
2329         } else if ((cache->miscObjs != NULL) &&
2330             (cache->miscObjs->number != 0))
2331         {
2332             xmlXPathObjectPtr ret;
2333
2334             ret = (xmlXPathObjectPtr)
2335                 cache->miscObjs->items[--cache->miscObjs->number];
2336
2337             ret->type = XPATH_NUMBER;
2338             ret->floatval = val;
2339 #ifdef XP_DEBUG_OBJ_USAGE
2340             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2341 #endif
2342             return(ret);
2343         }
2344     }
2345     return(xmlXPathNewFloat(val));
2346 }
2347
2348 /**
2349  * xmlXPathCacheConvertString:
2350  * @ctxt: the XPath context
2351  * @val:  an XPath object
2352  *
2353  * This is the cached version of xmlXPathConvertString().
2354  * Converts an existing object to its string() equivalent
2355  *
2356  * Returns a created or reused object, the old one is freed (cached)
2357  *         (or the operation is done directly on @val)
2358  */
2359
2360 static xmlXPathObjectPtr
2361 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2362     xmlChar *res = NULL;
2363
2364     if (val == NULL)
2365         return(xmlXPathCacheNewCString(ctxt, ""));
2366
2367     switch (val->type) {
2368     case XPATH_UNDEFINED:
2369 #ifdef DEBUG_EXPR
2370         xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2371 #endif
2372         break;
2373     case XPATH_NODESET:
2374     case XPATH_XSLT_TREE:
2375         res = xmlXPathCastNodeSetToString(val->nodesetval);
2376         break;
2377     case XPATH_STRING:
2378         return(val);
2379     case XPATH_BOOLEAN:
2380         res = xmlXPathCastBooleanToString(val->boolval);
2381         break;
2382     case XPATH_NUMBER:
2383         res = xmlXPathCastNumberToString(val->floatval);
2384         break;
2385     case XPATH_USERS:
2386     case XPATH_POINT:
2387     case XPATH_RANGE:
2388     case XPATH_LOCATIONSET:
2389         TODO;
2390         break;
2391     }
2392     xmlXPathReleaseObject(ctxt, val);
2393     if (res == NULL)
2394         return(xmlXPathCacheNewCString(ctxt, ""));
2395     return(xmlXPathCacheWrapString(ctxt, res));
2396 }
2397
2398 /**
2399  * xmlXPathCacheObjectCopy:
2400  * @ctxt: the XPath context
2401  * @val:  the original object
2402  *
2403  * This is the cached version of xmlXPathObjectCopy().
2404  * Acquire a copy of a given object
2405  *
2406  * Returns a created or reused created object.
2407  */
2408 static xmlXPathObjectPtr
2409 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2410 {
2411     if (val == NULL)
2412         return(NULL);
2413
2414     if (XP_HAS_CACHE(ctxt)) {
2415         switch (val->type) {
2416             case XPATH_NODESET:
2417                 return(xmlXPathCacheWrapNodeSet(ctxt,
2418                     xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2419             case XPATH_STRING:
2420                 return(xmlXPathCacheNewString(ctxt, val->stringval));
2421             case XPATH_BOOLEAN:
2422                 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2423             case XPATH_NUMBER:
2424                 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2425             default:
2426                 break;
2427         }
2428     }
2429     return(xmlXPathObjectCopy(val));
2430 }
2431
2432 /**
2433  * xmlXPathCacheConvertBoolean:
2434  * @ctxt: the XPath context
2435  * @val:  an XPath object
2436  *
2437  * This is the cached version of xmlXPathConvertBoolean().
2438  * Converts an existing object to its boolean() equivalent
2439  *
2440  * Returns a created or reused object, the old one is freed (or the operation
2441  *         is done directly on @val)
2442  */
2443 static xmlXPathObjectPtr
2444 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2445     xmlXPathObjectPtr ret;
2446
2447     if (val == NULL)
2448         return(xmlXPathCacheNewBoolean(ctxt, 0));
2449     if (val->type == XPATH_BOOLEAN)
2450         return(val);
2451     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2452     xmlXPathReleaseObject(ctxt, val);
2453     return(ret);
2454 }
2455
2456 /**
2457  * xmlXPathCacheConvertNumber:
2458  * @ctxt: the XPath context
2459  * @val:  an XPath object
2460  *
2461  * This is the cached version of xmlXPathConvertNumber().
2462  * Converts an existing object to its number() equivalent
2463  *
2464  * Returns a created or reused object, the old one is freed (or the operation
2465  *         is done directly on @val)
2466  */
2467 static xmlXPathObjectPtr
2468 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2469     xmlXPathObjectPtr ret;
2470
2471     if (val == NULL)
2472         return(xmlXPathCacheNewFloat(ctxt, 0.0));
2473     if (val->type == XPATH_NUMBER)
2474         return(val);
2475     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2476     xmlXPathReleaseObject(ctxt, val);
2477     return(ret);
2478 }
2479
2480 /************************************************************************
2481  *                                                                      *
2482  *              Parser stacks related functions and macros              *
2483  *                                                                      *
2484  ************************************************************************/
2485
2486 /**
2487  * xmlXPathSetFrame:
2488  * @ctxt: an XPath parser context
2489  *
2490  * Set the callee evaluation frame
2491  *
2492  * Returns the previous frame value to be restored once done
2493  */
2494 static int
2495 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2496     int ret;
2497
2498     if (ctxt == NULL)
2499         return(0);
2500     ret = ctxt->valueFrame;
2501     ctxt->valueFrame = ctxt->valueNr;
2502     return(ret);
2503 }
2504
2505 /**
2506  * xmlXPathPopFrame:
2507  * @ctxt: an XPath parser context
2508  * @frame: the previous frame value
2509  *
2510  * Remove the callee evaluation frame
2511  */
2512 static void
2513 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2514     if (ctxt == NULL)
2515         return;
2516     if (ctxt->valueNr < ctxt->valueFrame) {
2517         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2518     }
2519     ctxt->valueFrame = frame;
2520 }
2521
2522 /**
2523  * valuePop:
2524  * @ctxt: an XPath evaluation context
2525  *
2526  * Pops the top XPath object from the value stack
2527  *
2528  * Returns the XPath object just removed
2529  */
2530 xmlXPathObjectPtr
2531 valuePop(xmlXPathParserContextPtr ctxt)
2532 {
2533     xmlXPathObjectPtr ret;
2534
2535     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2536         return (NULL);
2537
2538     if (ctxt->valueNr <= ctxt->valueFrame) {
2539         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2540         return (NULL);
2541     }
2542
2543     ctxt->valueNr--;
2544     if (ctxt->valueNr > 0)
2545         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2546     else
2547         ctxt->value = NULL;
2548     ret = ctxt->valueTab[ctxt->valueNr];
2549     ctxt->valueTab[ctxt->valueNr] = NULL;
2550     return (ret);
2551 }
2552 /**
2553  * valuePush:
2554  * @ctxt:  an XPath evaluation context
2555  * @value:  the XPath object
2556  *
2557  * Pushes a new XPath object on top of the value stack
2558  *
2559  * returns the number of items on the value stack
2560  */
2561 int
2562 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2563 {
2564     if ((ctxt == NULL) || (value == NULL)) return(-1);
2565     if (ctxt->valueNr >= ctxt->valueMax) {
2566         xmlXPathObjectPtr *tmp;
2567
2568         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2569             xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2570             ctxt->error = XPATH_MEMORY_ERROR;
2571             return (0);
2572         }
2573         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2574                                              2 * ctxt->valueMax *
2575                                              sizeof(ctxt->valueTab[0]));
2576         if (tmp == NULL) {
2577             xmlXPathErrMemory(NULL, "pushing value\n");
2578             ctxt->error = XPATH_MEMORY_ERROR;
2579             return (0);
2580         }
2581         ctxt->valueMax *= 2;
2582         ctxt->valueTab = tmp;
2583     }
2584     ctxt->valueTab[ctxt->valueNr] = value;
2585     ctxt->value = value;
2586     return (ctxt->valueNr++);
2587 }
2588
2589 /**
2590  * xmlXPathPopBoolean:
2591  * @ctxt:  an XPath parser context
2592  *
2593  * Pops a boolean from the stack, handling conversion if needed.
2594  * Check error with #xmlXPathCheckError.
2595  *
2596  * Returns the boolean
2597  */
2598 int
2599 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2600     xmlXPathObjectPtr obj;
2601     int ret;
2602
2603     obj = valuePop(ctxt);
2604     if (obj == NULL) {
2605         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2606         return(0);
2607     }
2608     if (obj->type != XPATH_BOOLEAN)
2609         ret = xmlXPathCastToBoolean(obj);
2610     else
2611         ret = obj->boolval;
2612     xmlXPathReleaseObject(ctxt->context, obj);
2613     return(ret);
2614 }
2615
2616 /**
2617  * xmlXPathPopNumber:
2618  * @ctxt:  an XPath parser context
2619  *
2620  * Pops a number from the stack, handling conversion if needed.
2621  * Check error with #xmlXPathCheckError.
2622  *
2623  * Returns the number
2624  */
2625 double
2626 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2627     xmlXPathObjectPtr obj;
2628     double ret;
2629
2630     obj = valuePop(ctxt);
2631     if (obj == NULL) {
2632         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2633         return(0);
2634     }
2635     if (obj->type != XPATH_NUMBER)
2636         ret = xmlXPathCastToNumber(obj);
2637     else
2638         ret = obj->floatval;
2639     xmlXPathReleaseObject(ctxt->context, obj);
2640     return(ret);
2641 }
2642
2643 /**
2644  * xmlXPathPopString:
2645  * @ctxt:  an XPath parser context
2646  *
2647  * Pops a string from the stack, handling conversion if needed.
2648  * Check error with #xmlXPathCheckError.
2649  *
2650  * Returns the string
2651  */
2652 xmlChar *
2653 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2654     xmlXPathObjectPtr obj;
2655     xmlChar * ret;
2656
2657     obj = valuePop(ctxt);
2658     if (obj == NULL) {
2659         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2660         return(NULL);
2661     }
2662     ret = xmlXPathCastToString(obj);    /* this does required strdup */
2663     /* TODO: needs refactoring somewhere else */
2664     if (obj->stringval == ret)
2665         obj->stringval = NULL;
2666     xmlXPathReleaseObject(ctxt->context, obj);
2667     return(ret);
2668 }
2669
2670 /**
2671  * xmlXPathPopNodeSet:
2672  * @ctxt:  an XPath parser context
2673  *
2674  * Pops a node-set from the stack, handling conversion if needed.
2675  * Check error with #xmlXPathCheckError.
2676  *
2677  * Returns the node-set
2678  */
2679 xmlNodeSetPtr
2680 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2681     xmlXPathObjectPtr obj;
2682     xmlNodeSetPtr ret;
2683
2684     if (ctxt == NULL) return(NULL);
2685     if (ctxt->value == NULL) {
2686         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2687         return(NULL);
2688     }
2689     if (!xmlXPathStackIsNodeSet(ctxt)) {
2690         xmlXPathSetTypeError(ctxt);
2691         return(NULL);
2692     }
2693     obj = valuePop(ctxt);
2694     ret = obj->nodesetval;
2695 #if 0
2696     /* to fix memory leak of not clearing obj->user */
2697     if (obj->boolval && obj->user != NULL)
2698         xmlFreeNodeList((xmlNodePtr) obj->user);
2699 #endif
2700     obj->nodesetval = NULL;
2701     xmlXPathReleaseObject(ctxt->context, obj);
2702     return(ret);
2703 }
2704
2705 /**
2706  * xmlXPathPopExternal:
2707  * @ctxt:  an XPath parser context
2708  *
2709  * Pops an external object from the stack, handling conversion if needed.
2710  * Check error with #xmlXPathCheckError.
2711  *
2712  * Returns the object
2713  */
2714 void *
2715 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2716     xmlXPathObjectPtr obj;
2717     void * ret;
2718
2719     if ((ctxt == NULL) || (ctxt->value == NULL)) {
2720         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2721         return(NULL);
2722     }
2723     if (ctxt->value->type != XPATH_USERS) {
2724         xmlXPathSetTypeError(ctxt);
2725         return(NULL);
2726     }
2727     obj = valuePop(ctxt);
2728     ret = obj->user;
2729     obj->user = NULL;
2730     xmlXPathReleaseObject(ctxt->context, obj);
2731     return(ret);
2732 }
2733
2734 /*
2735  * Macros for accessing the content. Those should be used only by the parser,
2736  * and not exported.
2737  *
2738  * Dirty macros, i.e. one need to make assumption on the context to use them
2739  *
2740  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2741  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2742  *           in ISO-Latin or UTF-8.
2743  *           This should be used internally by the parser
2744  *           only to compare to ASCII values otherwise it would break when
2745  *           running with UTF-8 encoding.
2746  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2747  *           to compare on ASCII based substring.
2748  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2749  *           strings within the parser.
2750  *   CURRENT Returns the current char value, with the full decoding of
2751  *           UTF-8 if we are using this mode. It returns an int.
2752  *   NEXT    Skip to the next character, this does the proper decoding
2753  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2754  *           It returns the pointer to the current xmlChar.
2755  */
2756
2757 #define CUR (*ctxt->cur)
2758 #define SKIP(val) ctxt->cur += (val)
2759 #define NXT(val) ctxt->cur[(val)]
2760 #define CUR_PTR ctxt->cur
2761 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2762
2763 #define COPY_BUF(l,b,i,v)                                              \
2764     if (l == 1) b[i++] = (xmlChar) v;                                  \
2765     else i += xmlCopyChar(l,&b[i],v)
2766
2767 #define NEXTL(l)  ctxt->cur += l
2768
2769 #define SKIP_BLANKS                                                     \
2770     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2771
2772 #define CURRENT (*ctxt->cur)
2773 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2774
2775
2776 #ifndef DBL_DIG
2777 #define DBL_DIG 16
2778 #endif
2779 #ifndef DBL_EPSILON
2780 #define DBL_EPSILON 1E-9
2781 #endif
2782
2783 #define UPPER_DOUBLE 1E9
2784 #define LOWER_DOUBLE 1E-5
2785 #define LOWER_DOUBLE_EXP 5
2786
2787 #define INTEGER_DIGITS DBL_DIG
2788 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2789 #define EXPONENT_DIGITS (3 + 2)
2790
2791 /**
2792  * xmlXPathFormatNumber:
2793  * @number:     number to format
2794  * @buffer:     output buffer
2795  * @buffersize: size of output buffer
2796  *
2797  * Convert the number into a string representation.
2798  */
2799 static void
2800 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2801 {
2802     switch (xmlXPathIsInf(number)) {
2803     case 1:
2804         if (buffersize > (int)sizeof("Infinity"))
2805             snprintf(buffer, buffersize, "Infinity");
2806         break;
2807     case -1:
2808         if (buffersize > (int)sizeof("-Infinity"))
2809             snprintf(buffer, buffersize, "-Infinity");
2810         break;
2811     default:
2812         if (xmlXPathIsNaN(number)) {
2813             if (buffersize > (int)sizeof("NaN"))
2814                 snprintf(buffer, buffersize, "NaN");
2815         } else if (number == 0 && xmlXPathGetSign(number) != 0) {
2816             snprintf(buffer, buffersize, "0");
2817         } else if (number == ((int) number)) {
2818             char work[30];
2819             char *ptr, *cur;
2820             int value = (int) number;
2821
2822             ptr = &buffer[0];
2823             if (value == 0) {
2824                 *ptr++ = '0';
2825             } else {
2826                 snprintf(work, 29, "%d", value);
2827                 cur = &work[0];
2828                 while ((*cur) && (ptr - buffer < buffersize)) {
2829                     *ptr++ = *cur++;
2830                 }
2831             }
2832             if (ptr - buffer < buffersize) {
2833                 *ptr = 0;
2834             } else if (buffersize > 0) {
2835                 ptr--;
2836                 *ptr = 0;
2837             }
2838         } else {
2839             /*
2840               For the dimension of work,
2841                   DBL_DIG is number of significant digits
2842                   EXPONENT is only needed for "scientific notation"
2843                   3 is sign, decimal point, and terminating zero
2844                   LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2845               Note that this dimension is slightly (a few characters)
2846               larger than actually necessary.
2847             */
2848             char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2849             int integer_place, fraction_place;
2850             char *ptr;
2851             char *after_fraction;
2852             double absolute_value;
2853             int size;
2854
2855             absolute_value = fabs(number);
2856
2857             /*
2858              * First choose format - scientific or regular floating point.
2859              * In either case, result is in work, and after_fraction points
2860              * just past the fractional part.
2861             */
2862             if ( ((absolute_value > UPPER_DOUBLE) ||
2863                   (absolute_value < LOWER_DOUBLE)) &&
2864                  (absolute_value != 0.0) ) {
2865                 /* Use scientific notation */
2866                 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2867                 fraction_place = DBL_DIG - 1;
2868                 size = snprintf(work, sizeof(work),"%*.*e",
2869                          integer_place, fraction_place, number);
2870                 while ((size > 0) && (work[size] != 'e')) size--;
2871
2872             }
2873             else {
2874                 /* Use regular notation */
2875                 if (absolute_value > 0.0) {
2876                     integer_place = (int)log10(absolute_value);
2877                     if (integer_place > 0)
2878                         fraction_place = DBL_DIG - integer_place - 1;
2879                     else
2880                         fraction_place = DBL_DIG - integer_place;
2881                 } else {
2882                     fraction_place = 1;
2883                 }
2884                 size = snprintf(work, sizeof(work), "%0.*f",
2885                                 fraction_place, number);
2886             }
2887
2888             /* Remove fractional trailing zeroes */
2889             after_fraction = work + size;
2890             ptr = after_fraction;
2891             while (*(--ptr) == '0')
2892                 ;
2893             if (*ptr != '.')
2894                 ptr++;
2895             while ((*ptr++ = *after_fraction++) != 0);
2896
2897             /* Finally copy result back to caller */
2898             size = strlen(work) + 1;
2899             if (size > buffersize) {
2900                 work[buffersize - 1] = 0;
2901                 size = buffersize;
2902             }
2903             memmove(buffer, work, size);
2904         }
2905         break;
2906     }
2907 }
2908
2909
2910 /************************************************************************
2911  *                                                                      *
2912  *                      Routines to handle NodeSets                     *
2913  *                                                                      *
2914  ************************************************************************/
2915
2916 /**
2917  * xmlXPathOrderDocElems:
2918  * @doc:  an input document
2919  *
2920  * Call this routine to speed up XPath computation on static documents.
2921  * This stamps all the element nodes with the document order
2922  * Like for line information, the order is kept in the element->content
2923  * field, the value stored is actually - the node number (starting at -1)
2924  * to be able to differentiate from line numbers.
2925  *
2926  * Returns the number of elements found in the document or -1 in case
2927  *    of error.
2928  */
2929 long
2930 xmlXPathOrderDocElems(xmlDocPtr doc) {
2931     long count = 0;
2932     xmlNodePtr cur;
2933
2934     if (doc == NULL)
2935         return(-1);
2936     cur = doc->children;
2937     while (cur != NULL) {
2938         if (cur->type == XML_ELEMENT_NODE) {
2939             cur->content = (void *) (-(++count));
2940             if (cur->children != NULL) {
2941                 cur = cur->children;
2942                 continue;
2943             }
2944         }
2945         if (cur->next != NULL) {
2946             cur = cur->next;
2947             continue;
2948         }
2949         do {
2950             cur = cur->parent;
2951             if (cur == NULL)
2952                 break;
2953             if (cur == (xmlNodePtr) doc) {
2954                 cur = NULL;
2955                 break;
2956             }
2957             if (cur->next != NULL) {
2958                 cur = cur->next;
2959                 break;
2960             }
2961         } while (cur != NULL);
2962     }
2963     return(count);
2964 }
2965
2966 /**
2967  * xmlXPathCmpNodes:
2968  * @node1:  the first node
2969  * @node2:  the second node
2970  *
2971  * Compare two nodes w.r.t document order
2972  *
2973  * Returns -2 in case of error 1 if first point < second point, 0 if
2974  *         it's the same node, -1 otherwise
2975  */
2976 int
2977 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2978     int depth1, depth2;
2979     int attr1 = 0, attr2 = 0;
2980     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2981     xmlNodePtr cur, root;
2982
2983     if ((node1 == NULL) || (node2 == NULL))
2984         return(-2);
2985     /*
2986      * a couple of optimizations which will avoid computations in most cases
2987      */
2988     if (node1 == node2)         /* trivial case */
2989         return(0);
2990     if (node1->type == XML_ATTRIBUTE_NODE) {
2991         attr1 = 1;
2992         attrNode1 = node1;
2993         node1 = node1->parent;
2994     }
2995     if (node2->type == XML_ATTRIBUTE_NODE) {
2996         attr2 = 1;
2997         attrNode2 = node2;
2998         node2 = node2->parent;
2999     }
3000     if (node1 == node2) {
3001         if (attr1 == attr2) {
3002             /* not required, but we keep attributes in order */
3003             if (attr1 != 0) {
3004                 cur = attrNode2->prev;
3005                 while (cur != NULL) {
3006                     if (cur == attrNode1)
3007                         return (1);
3008                     cur = cur->prev;
3009                 }
3010                 return (-1);
3011             }
3012             return(0);
3013         }
3014         if (attr2 == 1)
3015             return(1);
3016         return(-1);
3017     }
3018     if ((node1->type == XML_NAMESPACE_DECL) ||
3019         (node2->type == XML_NAMESPACE_DECL))
3020         return(1);
3021     if (node1 == node2->prev)
3022         return(1);
3023     if (node1 == node2->next)
3024         return(-1);
3025
3026     /*
3027      * Speedup using document order if availble.
3028      */
3029     if ((node1->type == XML_ELEMENT_NODE) &&
3030         (node2->type == XML_ELEMENT_NODE) &&
3031         (0 > (long) node1->content) &&
3032         (0 > (long) node2->content) &&
3033         (node1->doc == node2->doc)) {
3034         long l1, l2;
3035
3036         l1 = -((long) node1->content);
3037         l2 = -((long) node2->content);
3038         if (l1 < l2)
3039             return(1);
3040         if (l1 > l2)
3041             return(-1);
3042     }
3043
3044     /*
3045      * compute depth to root
3046      */
3047     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3048         if (cur == node1)
3049             return(1);
3050         depth2++;
3051     }
3052     root = cur;
3053     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3054         if (cur == node2)
3055             return(-1);
3056         depth1++;
3057     }
3058     /*
3059      * Distinct document (or distinct entities :-( ) case.
3060      */
3061     if (root != cur) {
3062         return(-2);
3063     }
3064     /*
3065      * get the nearest common ancestor.
3066      */
3067     while (depth1 > depth2) {
3068         depth1--;
3069         node1 = node1->parent;
3070     }
3071     while (depth2 > depth1) {
3072         depth2--;
3073         node2 = node2->parent;
3074     }
3075     while (node1->parent != node2->parent) {
3076         node1 = node1->parent;
3077         node2 = node2->parent;
3078         /* should not happen but just in case ... */
3079         if ((node1 == NULL) || (node2 == NULL))
3080             return(-2);
3081     }
3082     /*
3083      * Find who's first.
3084      */
3085     if (node1 == node2->prev)
3086         return(1);
3087     if (node1 == node2->next)
3088         return(-1);
3089     /*
3090      * Speedup using document order if availble.
3091      */
3092     if ((node1->type == XML_ELEMENT_NODE) &&
3093         (node2->type == XML_ELEMENT_NODE) &&
3094         (0 > (long) node1->content) &&
3095         (0 > (long) node2->content) &&
3096         (node1->doc == node2->doc)) {
3097         long l1, l2;
3098
3099         l1 = -((long) node1->content);
3100         l2 = -((long) node2->content);
3101         if (l1 < l2)
3102             return(1);
3103         if (l1 > l2)
3104             return(-1);
3105     }
3106
3107     for (cur = node1->next;cur != NULL;cur = cur->next)
3108         if (cur == node2)
3109             return(1);
3110     return(-1); /* assume there is no sibling list corruption */
3111 }
3112
3113 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3114 /**
3115  * xmlXPathCmpNodesExt:
3116  * @node1:  the first node
3117  * @node2:  the second node
3118  *
3119  * Compare two nodes w.r.t document order.
3120  * This one is optimized for handling of non-element nodes.
3121  *
3122  * Returns -2 in case of error 1 if first point < second point, 0 if
3123  *         it's the same node, -1 otherwise
3124  */
3125 static int
3126 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
3127     int depth1, depth2;
3128     int misc = 0, precedence1 = 0, precedence2 = 0;
3129     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
3130     xmlNodePtr cur, root;
3131     long l1, l2;
3132
3133     if ((node1 == NULL) || (node2 == NULL))
3134         return(-2);
3135
3136     if (node1 == node2)
3137         return(0);
3138
3139     /*
3140      * a couple of optimizations which will avoid computations in most cases
3141      */
3142     switch (node1->type) {
3143         case XML_ELEMENT_NODE:
3144             if (node2->type == XML_ELEMENT_NODE) {
3145                 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3146                     (0 > (long) node2->content) &&
3147                     (node1->doc == node2->doc))
3148                 {
3149                     l1 = -((long) node1->content);
3150                     l2 = -((long) node2->content);
3151                     if (l1 < l2)
3152                         return(1);
3153                     if (l1 > l2)
3154                         return(-1);
3155                 } else
3156                     goto turtle_comparison;
3157             }
3158             break;
3159         case XML_ATTRIBUTE_NODE:
3160             precedence1 = 1; /* element is owner */
3161             miscNode1 = node1;
3162             node1 = node1->parent;
3163             misc = 1;
3164             break;
3165         case XML_TEXT_NODE:
3166         case XML_CDATA_SECTION_NODE:
3167         case XML_COMMENT_NODE:
3168         case XML_PI_NODE: {
3169             miscNode1 = node1;
3170             /*
3171             * Find nearest element node.
3172             */
3173             if (node1->prev != NULL) {
3174                 do {
3175                     node1 = node1->prev;
3176                     if (node1->type == XML_ELEMENT_NODE) {
3177                         precedence1 = 3; /* element in prev-sibl axis */
3178                         break;
3179                     }
3180                     if (node1->prev == NULL) {
3181                         precedence1 = 2; /* element is parent */
3182                         /*
3183                         * URGENT TODO: Are there any cases, where the
3184                         * parent of such a node is not an element node?
3185                         */
3186                         node1 = node1->parent;
3187                         break;
3188                     }
3189                 } while (1);
3190             } else {
3191                 precedence1 = 2; /* element is parent */
3192                 node1 = node1->parent;
3193             }
3194             if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3195                 (0 <= (long) node1->content)) {
3196                 /*
3197                 * Fallback for whatever case.
3198                 */
3199                 node1 = miscNode1;
3200                 precedence1 = 0;
3201             } else
3202                 misc = 1;
3203         }
3204             break;
3205         case XML_NAMESPACE_DECL:
3206             /*
3207             * TODO: why do we return 1 for namespace nodes?
3208             */
3209             return(1);
3210         default:
3211             break;
3212     }
3213     switch (node2->type) {
3214         case XML_ELEMENT_NODE:
3215             break;
3216         case XML_ATTRIBUTE_NODE:
3217             precedence2 = 1; /* element is owner */
3218             miscNode2 = node2;
3219             node2 = node2->parent;
3220             misc = 1;
3221             break;
3222         case XML_TEXT_NODE:
3223         case XML_CDATA_SECTION_NODE:
3224         case XML_COMMENT_NODE:
3225         case XML_PI_NODE: {
3226             miscNode2 = node2;
3227             if (node2->prev != NULL) {
3228                 do {
3229                     node2 = node2->prev;
3230                     if (node2->type == XML_ELEMENT_NODE) {
3231                         precedence2 = 3; /* element in prev-sibl axis */
3232                         break;
3233                     }
3234                     if (node2->prev == NULL) {
3235                         precedence2 = 2; /* element is parent */
3236                         node2 = node2->parent;
3237                         break;
3238                     }
3239                 } while (1);
3240             } else {
3241                 precedence2 = 2; /* element is parent */
3242                 node2 = node2->parent;
3243             }
3244             if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3245                 (0 <= (long) node1->content))
3246             {
3247                 node2 = miscNode2;
3248                 precedence2 = 0;
3249             } else
3250                 misc = 1;
3251         }
3252             break;
3253         case XML_NAMESPACE_DECL:
3254             return(1);
3255         default:
3256             break;
3257     }
3258     if (misc) {
3259         if (node1 == node2) {
3260             if (precedence1 == precedence2) {
3261                 /*
3262                 * The ugly case; but normally there aren't many
3263                 * adjacent non-element nodes around.
3264                 */
3265                 cur = miscNode2->prev;
3266                 while (cur != NULL) {
3267                     if (cur == miscNode1)
3268                         return(1);
3269                     if (cur->type == XML_ELEMENT_NODE)
3270                         return(-1);
3271                     cur = cur->prev;
3272                 }
3273                 return (-1);
3274             } else {
3275                 /*
3276                 * Evaluate based on higher precedence wrt to the element.
3277                 * TODO: This assumes attributes are sorted before content.
3278                 *   Is this 100% correct?
3279                 */
3280                 if (precedence1 < precedence2)
3281                     return(1);
3282                 else
3283                     return(-1);
3284             }
3285         }
3286         /*
3287         * Special case: One of the helper-elements is contained by the other.
3288         * <foo>
3289         *   <node2>
3290         *     <node1>Text-1(precedence1 == 2)</node1>
3291         *   </node2>
3292         *   Text-6(precedence2 == 3)
3293         * </foo>
3294         */
3295         if ((precedence2 == 3) && (precedence1 > 1)) {
3296             cur = node1->parent;
3297             while (cur) {
3298                 if (cur == node2)
3299                     return(1);
3300                 cur = cur->parent;
3301             }
3302         }
3303         if ((precedence1 == 3) && (precedence2 > 1)) {
3304             cur = node2->parent;
3305             while (cur) {
3306                 if (cur == node1)
3307                     return(-1);
3308                 cur = cur->parent;
3309             }
3310         }
3311     }
3312
3313     /*
3314      * Speedup using document order if availble.
3315      */
3316     if ((node1->type == XML_ELEMENT_NODE) &&
3317         (node2->type == XML_ELEMENT_NODE) &&
3318         (0 > (long) node1->content) &&
3319         (0 > (long) node2->content) &&
3320         (node1->doc == node2->doc)) {
3321
3322         l1 = -((long) node1->content);
3323         l2 = -((long) node2->content);
3324         if (l1 < l2)
3325             return(1);
3326         if (l1 > l2)
3327             return(-1);
3328     }
3329
3330 turtle_comparison:
3331
3332     if (node1 == node2->prev)
3333         return(1);
3334     if (node1 == node2->next)
3335         return(-1);
3336     /*
3337      * compute depth to root
3338      */
3339     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3340         if (cur == node1)
3341             return(1);
3342         depth2++;
3343     }
3344     root = cur;
3345     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3346         if (cur == node2)
3347             return(-1);
3348         depth1++;
3349     }
3350     /*
3351      * Distinct document (or distinct entities :-( ) case.
3352      */
3353     if (root != cur) {
3354         return(-2);
3355     }
3356     /*
3357      * get the nearest common ancestor.
3358      */
3359     while (depth1 > depth2) {
3360         depth1--;
3361         node1 = node1->parent;
3362     }
3363     while (depth2 > depth1) {
3364         depth2--;
3365         node2 = node2->parent;
3366     }
3367     while (node1->parent != node2->parent) {
3368         node1 = node1->parent;
3369         node2 = node2->parent;
3370         /* should not happen but just in case ... */
3371         if ((node1 == NULL) || (node2 == NULL))
3372             return(-2);
3373     }
3374     /*
3375      * Find who's first.
3376      */
3377     if (node1 == node2->prev)
3378         return(1);
3379     if (node1 == node2->next)
3380         return(-1);
3381     /*
3382      * Speedup using document order if availble.
3383      */
3384     if ((node1->type == XML_ELEMENT_NODE) &&
3385         (node2->type == XML_ELEMENT_NODE) &&
3386         (0 > (long) node1->content) &&
3387         (0 > (long) node2->content) &&
3388         (node1->doc == node2->doc)) {
3389
3390         l1 = -((long) node1->content);
3391         l2 = -((long) node2->content);
3392         if (l1 < l2)
3393             return(1);
3394         if (l1 > l2)
3395             return(-1);
3396     }
3397
3398     for (cur = node1->next;cur != NULL;cur = cur->next)
3399         if (cur == node2)
3400             return(1);
3401     return(-1); /* assume there is no sibling list corruption */
3402 }
3403 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3404
3405 /**
3406  * xmlXPathNodeSetSort:
3407  * @set:  the node set
3408  *
3409  * Sort the node set in document order
3410  */
3411 void
3412 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3413 #ifndef WITH_TIM_SORT
3414     int i, j, incr, len;
3415     xmlNodePtr tmp;
3416 #endif
3417
3418     if (set == NULL)
3419         return;
3420
3421 #ifndef WITH_TIM_SORT
3422     /*
3423      * Use the old Shell's sort implementation to sort the node-set
3424      * Timsort ought to be quite faster
3425      */
3426     len = set->nodeNr;
3427     for (incr = len / 2; incr > 0; incr /= 2) {
3428         for (i = incr; i < len; i++) {
3429             j = i - incr;
3430             while (j >= 0) {
3431 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3432                 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3433                         set->nodeTab[j + incr]) == -1)
3434 #else
3435                 if (xmlXPathCmpNodes(set->nodeTab[j],
3436                         set->nodeTab[j + incr]) == -1)
3437 #endif
3438                 {
3439                     tmp = set->nodeTab[j];
3440                     set->nodeTab[j] = set->nodeTab[j + incr];
3441                     set->nodeTab[j + incr] = tmp;
3442                     j -= incr;
3443                 } else
3444                     break;
3445             }
3446         }
3447     }
3448 #else /* WITH_TIM_SORT */
3449     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3450 #endif /* WITH_TIM_SORT */
3451 }
3452
3453 #define XML_NODESET_DEFAULT     10
3454 /**
3455  * xmlXPathNodeSetDupNs:
3456  * @node:  the parent node of the namespace XPath node
3457  * @ns:  the libxml namespace declaration node.
3458  *
3459  * Namespace node in libxml don't match the XPath semantic. In a node set
3460  * the namespace nodes are duplicated and the next pointer is set to the
3461  * parent node in the XPath semantic.
3462  *
3463  * Returns the newly created object.
3464  */
3465 static xmlNodePtr
3466 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3467     xmlNsPtr cur;
3468
3469     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3470         return(NULL);
3471     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3472         return((xmlNodePtr) ns);
3473
3474     /*
3475      * Allocate a new Namespace and fill the fields.
3476      */
3477     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3478     if (cur == NULL) {
3479         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3480         return(NULL);
3481     }
3482     memset(cur, 0, sizeof(xmlNs));
3483     cur->type = XML_NAMESPACE_DECL;
3484     if (ns->href != NULL)
3485         cur->href = xmlStrdup(ns->href);
3486     if (ns->prefix != NULL)
3487         cur->prefix = xmlStrdup(ns->prefix);
3488     cur->next = (xmlNsPtr) node;
3489     return((xmlNodePtr) cur);
3490 }
3491
3492 /**
3493  * xmlXPathNodeSetFreeNs:
3494  * @ns:  the XPath namespace node found in a nodeset.
3495  *
3496  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3497  * the namespace nodes are duplicated and the next pointer is set to the
3498  * parent node in the XPath semantic. Check if such a node needs to be freed
3499  */
3500 void
3501 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3502     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3503         return;
3504
3505     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3506         if (ns->href != NULL)
3507             xmlFree((xmlChar *)ns->href);
3508         if (ns->prefix != NULL)
3509             xmlFree((xmlChar *)ns->prefix);
3510         xmlFree(ns);
3511     }
3512 }
3513
3514 /**
3515  * xmlXPathNodeSetCreate:
3516  * @val:  an initial xmlNodePtr, or NULL
3517  *
3518  * Create a new xmlNodeSetPtr of type double and of value @val
3519  *
3520  * Returns the newly created object.
3521  */
3522 xmlNodeSetPtr
3523 xmlXPathNodeSetCreate(xmlNodePtr val) {
3524     xmlNodeSetPtr ret;
3525
3526     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3527     if (ret == NULL) {
3528         xmlXPathErrMemory(NULL, "creating nodeset\n");
3529         return(NULL);
3530     }
3531     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3532     if (val != NULL) {
3533         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3534                                              sizeof(xmlNodePtr));
3535         if (ret->nodeTab == NULL) {
3536             xmlXPathErrMemory(NULL, "creating nodeset\n");
3537             xmlFree(ret);
3538             return(NULL);
3539         }
3540         memset(ret->nodeTab, 0 ,
3541                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3542         ret->nodeMax = XML_NODESET_DEFAULT;
3543         if (val->type == XML_NAMESPACE_DECL) {
3544             xmlNsPtr ns = (xmlNsPtr) val;
3545
3546             ret->nodeTab[ret->nodeNr++] =
3547                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3548         } else
3549             ret->nodeTab[ret->nodeNr++] = val;
3550     }
3551     return(ret);
3552 }
3553
3554 /**
3555  * xmlXPathNodeSetCreateSize:
3556  * @size:  the initial size of the set
3557  *
3558  * Create a new xmlNodeSetPtr of type double and of value @val
3559  *
3560  * Returns the newly created object.
3561  */
3562 static xmlNodeSetPtr
3563 xmlXPathNodeSetCreateSize(int size) {
3564     xmlNodeSetPtr ret;
3565
3566     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3567     if (ret == NULL) {
3568         xmlXPathErrMemory(NULL, "creating nodeset\n");
3569         return(NULL);
3570     }
3571     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3572     if (size < XML_NODESET_DEFAULT)
3573         size = XML_NODESET_DEFAULT;
3574     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3575     if (ret->nodeTab == NULL) {
3576         xmlXPathErrMemory(NULL, "creating nodeset\n");
3577         xmlFree(ret);
3578         return(NULL);
3579     }
3580     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3581     ret->nodeMax = size;
3582     return(ret);
3583 }
3584
3585 /**
3586  * xmlXPathNodeSetContains:
3587  * @cur:  the node-set
3588  * @val:  the node
3589  *
3590  * checks whether @cur contains @val
3591  *
3592  * Returns true (1) if @cur contains @val, false (0) otherwise
3593  */
3594 int
3595 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3596     int i;
3597
3598     if ((cur == NULL) || (val == NULL)) return(0);
3599     if (val->type == XML_NAMESPACE_DECL) {
3600         for (i = 0; i < cur->nodeNr; i++) {
3601             if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3602                 xmlNsPtr ns1, ns2;
3603
3604                 ns1 = (xmlNsPtr) val;
3605                 ns2 = (xmlNsPtr) cur->nodeTab[i];
3606                 if (ns1 == ns2)
3607                     return(1);
3608                 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3609                     (xmlStrEqual(ns1->prefix, ns2->prefix)))
3610                     return(1);
3611             }
3612         }
3613     } else {
3614         for (i = 0; i < cur->nodeNr; i++) {
3615             if (cur->nodeTab[i] == val)
3616                 return(1);
3617         }
3618     }
3619     return(0);
3620 }
3621
3622 /**
3623  * xmlXPathNodeSetAddNs:
3624  * @cur:  the initial node set
3625  * @node:  the hosting node
3626  * @ns:  a the namespace node
3627  *
3628  * add a new namespace node to an existing NodeSet
3629  *
3630  * Returns 0 in case of success and -1 in case of error
3631  */
3632 int
3633 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3634     int i;
3635
3636
3637     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3638         (ns->type != XML_NAMESPACE_DECL) ||
3639         (node->type != XML_ELEMENT_NODE))
3640         return(-1);
3641
3642     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3643     /*
3644      * prevent duplicates
3645      */
3646     for (i = 0;i < cur->nodeNr;i++) {
3647         if ((cur->nodeTab[i] != NULL) &&
3648             (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3649             (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3650             (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3651             return(0);
3652     }
3653
3654     /*
3655      * grow the nodeTab if needed
3656      */
3657     if (cur->nodeMax == 0) {
3658         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3659                                              sizeof(xmlNodePtr));
3660         if (cur->nodeTab == NULL) {
3661             xmlXPathErrMemory(NULL, "growing nodeset\n");
3662             return(-1);
3663         }
3664         memset(cur->nodeTab, 0 ,
3665                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3666         cur->nodeMax = XML_NODESET_DEFAULT;
3667     } else if (cur->nodeNr == cur->nodeMax) {
3668         xmlNodePtr *temp;
3669
3670         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3671             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3672             return(-1);
3673         }
3674         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3675                                       sizeof(xmlNodePtr));
3676         if (temp == NULL) {
3677             xmlXPathErrMemory(NULL, "growing nodeset\n");
3678             return(-1);
3679         }
3680         cur->nodeMax *= 2;
3681         cur->nodeTab = temp;
3682     }
3683     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3684     return(0);
3685 }
3686
3687 /**
3688  * xmlXPathNodeSetAdd:
3689  * @cur:  the initial node set
3690  * @val:  a new xmlNodePtr
3691  *
3692  * add a new xmlNodePtr to an existing NodeSet
3693  *
3694  * Returns 0 in case of success, and -1 in case of error
3695  */
3696 int
3697 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3698     int i;
3699
3700     if ((cur == NULL) || (val == NULL)) return(-1);
3701
3702     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3703     /*
3704      * prevent duplcates
3705      */
3706     for (i = 0;i < cur->nodeNr;i++)
3707         if (cur->nodeTab[i] == val) return(0);
3708
3709     /*
3710      * grow the nodeTab if needed
3711      */
3712     if (cur->nodeMax == 0) {
3713         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3714                                              sizeof(xmlNodePtr));
3715         if (cur->nodeTab == NULL) {
3716             xmlXPathErrMemory(NULL, "growing nodeset\n");
3717             return(-1);
3718         }
3719         memset(cur->nodeTab, 0 ,
3720                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3721         cur->nodeMax = XML_NODESET_DEFAULT;
3722     } else if (cur->nodeNr == cur->nodeMax) {
3723         xmlNodePtr *temp;
3724
3725         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3726             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3727             return(-1);
3728         }
3729         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3730                                       sizeof(xmlNodePtr));
3731         if (temp == NULL) {
3732             xmlXPathErrMemory(NULL, "growing nodeset\n");
3733             return(-1);
3734         }
3735         cur->nodeMax *= 2;
3736         cur->nodeTab = temp;
3737     }
3738     if (val->type == XML_NAMESPACE_DECL) {
3739         xmlNsPtr ns = (xmlNsPtr) val;
3740
3741         cur->nodeTab[cur->nodeNr++] =
3742             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3743     } else
3744         cur->nodeTab[cur->nodeNr++] = val;
3745     return(0);
3746 }
3747
3748 /**
3749  * xmlXPathNodeSetAddUnique:
3750  * @cur:  the initial node set
3751  * @val:  a new xmlNodePtr
3752  *
3753  * add a new xmlNodePtr to an existing NodeSet, optimized version
3754  * when we are sure the node is not already in the set.
3755  *
3756  * Returns 0 in case of success and -1 in case of failure
3757  */
3758 int
3759 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3760     if ((cur == NULL) || (val == NULL)) return(-1);
3761
3762     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3763     /*
3764      * grow the nodeTab if needed
3765      */
3766     if (cur->nodeMax == 0) {
3767         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3768                                              sizeof(xmlNodePtr));
3769         if (cur->nodeTab == NULL) {
3770             xmlXPathErrMemory(NULL, "growing nodeset\n");
3771             return(-1);
3772         }
3773         memset(cur->nodeTab, 0 ,
3774                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3775         cur->nodeMax = XML_NODESET_DEFAULT;
3776     } else if (cur->nodeNr == cur->nodeMax) {
3777         xmlNodePtr *temp;
3778
3779         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3780             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3781             return(-1);
3782         }
3783         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3784                                       sizeof(xmlNodePtr));
3785         if (temp == NULL) {
3786             xmlXPathErrMemory(NULL, "growing nodeset\n");
3787             return(-1);
3788         }
3789         cur->nodeTab = temp;
3790         cur->nodeMax *= 2;
3791     }
3792     if (val->type == XML_NAMESPACE_DECL) {
3793         xmlNsPtr ns = (xmlNsPtr) val;
3794
3795         cur->nodeTab[cur->nodeNr++] =
3796             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3797     } else
3798         cur->nodeTab[cur->nodeNr++] = val;
3799     return(0);
3800 }
3801
3802 /**
3803  * xmlXPathNodeSetMerge:
3804  * @val1:  the first NodeSet or NULL
3805  * @val2:  the second NodeSet
3806  *
3807  * Merges two nodesets, all nodes from @val2 are added to @val1
3808  * if @val1 is NULL, a new set is created and copied from @val2
3809  *
3810  * Returns @val1 once extended or NULL in case of error.
3811  */
3812 xmlNodeSetPtr
3813 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3814     int i, j, initNr, skip;
3815     xmlNodePtr n1, n2;
3816
3817     if (val2 == NULL) return(val1);
3818     if (val1 == NULL) {
3819         val1 = xmlXPathNodeSetCreate(NULL);
3820     if (val1 == NULL)
3821         return (NULL);
3822 #if 0
3823         /*
3824         * TODO: The optimization won't work in every case, since
3825         *  those nasty namespace nodes need to be added with
3826         *  xmlXPathNodeSetDupNs() to the set; thus a pure
3827         *  memcpy is not possible.
3828         *  If there was a flag on the nodesetval, indicating that
3829         *  some temporary nodes are in, that would be helpfull.
3830         */
3831         /*
3832         * Optimization: Create an equally sized node-set
3833         * and memcpy the content.
3834         */
3835         val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3836         if (val1 == NULL)
3837             return(NULL);
3838         if (val2->nodeNr != 0) {
3839             if (val2->nodeNr == 1)
3840                 *(val1->nodeTab) = *(val2->nodeTab);
3841             else {
3842                 memcpy(val1->nodeTab, val2->nodeTab,
3843                     val2->nodeNr * sizeof(xmlNodePtr));
3844             }
3845             val1->nodeNr = val2->nodeNr;
3846         }
3847         return(val1);
3848 #endif
3849     }
3850
3851     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3852     initNr = val1->nodeNr;
3853
3854     for (i = 0;i < val2->nodeNr;i++) {
3855         n2 = val2->nodeTab[i];
3856         /*
3857          * check against duplicates
3858          */
3859         skip = 0;
3860         for (j = 0; j < initNr; j++) {
3861             n1 = val1->nodeTab[j];
3862             if (n1 == n2) {
3863                 skip = 1;
3864                 break;
3865             } else if ((n1->type == XML_NAMESPACE_DECL) &&
3866                        (n2->type == XML_NAMESPACE_DECL)) {
3867                 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3868                     (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3869                         ((xmlNsPtr) n2)->prefix)))
3870                 {
3871                     skip = 1;
3872                     break;
3873                 }
3874             }
3875         }
3876         if (skip)
3877             continue;
3878
3879         /*
3880          * grow the nodeTab if needed
3881          */
3882         if (val1->nodeMax == 0) {
3883             val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3884                                                     sizeof(xmlNodePtr));
3885             if (val1->nodeTab == NULL) {
3886                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3887                 return(NULL);
3888             }
3889             memset(val1->nodeTab, 0 ,
3890                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3891             val1->nodeMax = XML_NODESET_DEFAULT;
3892         } else if (val1->nodeNr == val1->nodeMax) {
3893             xmlNodePtr *temp;
3894
3895             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3896                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3897                 return(NULL);
3898             }
3899             temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3900                                              sizeof(xmlNodePtr));
3901             if (temp == NULL) {
3902                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3903                 return(NULL);
3904             }
3905             val1->nodeTab = temp;
3906             val1->nodeMax *= 2;
3907         }
3908         if (n2->type == XML_NAMESPACE_DECL) {
3909             xmlNsPtr ns = (xmlNsPtr) n2;
3910
3911             val1->nodeTab[val1->nodeNr++] =
3912                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3913         } else
3914             val1->nodeTab[val1->nodeNr++] = n2;
3915     }
3916
3917     return(val1);
3918 }
3919
3920
3921 /**
3922  * xmlXPathNodeSetMergeAndClear:
3923  * @set1:  the first NodeSet or NULL
3924  * @set2:  the second NodeSet
3925  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3926  *
3927  * Merges two nodesets, all nodes from @set2 are added to @set1
3928  * if @set1 is NULL, a new set is created and copied from @set2.
3929  * Checks for duplicate nodes. Clears set2.
3930  *
3931  * Returns @set1 once extended or NULL in case of error.
3932  */
3933 static xmlNodeSetPtr
3934 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3935                              int hasNullEntries)
3936 {
3937     if ((set1 == NULL) && (hasNullEntries == 0)) {
3938         /*
3939         * Note that doing a memcpy of the list, namespace nodes are
3940         * just assigned to set1, since set2 is cleared anyway.
3941         */
3942         set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3943         if (set1 == NULL)
3944             return(NULL);
3945         if (set2->nodeNr != 0) {
3946             memcpy(set1->nodeTab, set2->nodeTab,
3947                 set2->nodeNr * sizeof(xmlNodePtr));
3948             set1->nodeNr = set2->nodeNr;
3949         }
3950     } else {
3951         int i, j, initNbSet1;
3952         xmlNodePtr n1, n2;
3953
3954         if (set1 == NULL)
3955             set1 = xmlXPathNodeSetCreate(NULL);
3956         if (set1 == NULL)
3957             return (NULL);
3958
3959         initNbSet1 = set1->nodeNr;
3960         for (i = 0;i < set2->nodeNr;i++) {
3961             n2 = set2->nodeTab[i];
3962             /*
3963             * Skip NULLed entries.
3964             */
3965             if (n2 == NULL)
3966                 continue;
3967             /*
3968             * Skip duplicates.
3969             */
3970             for (j = 0; j < initNbSet1; j++) {
3971                 n1 = set1->nodeTab[j];
3972                 if (n1 == n2) {
3973                     goto skip_node;
3974                 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3975                     (n2->type == XML_NAMESPACE_DECL))
3976                 {
3977                     if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3978                         (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3979                         ((xmlNsPtr) n2)->prefix)))
3980                     {
3981                         /*
3982                         * Free the namespace node.
3983                         */
3984                         set2->nodeTab[i] = NULL;
3985                         xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3986                         goto skip_node;
3987                     }
3988                 }
3989             }
3990             /*
3991             * grow the nodeTab if needed
3992             */
3993             if (set1->nodeMax == 0) {
3994                 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3995                     XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3996                 if (set1->nodeTab == NULL) {
3997                     xmlXPathErrMemory(NULL, "merging nodeset\n");
3998                     return(NULL);
3999                 }
4000                 memset(set1->nodeTab, 0,
4001                     XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4002                 set1->nodeMax = XML_NODESET_DEFAULT;
4003             } else if (set1->nodeNr >= set1->nodeMax) {
4004                 xmlNodePtr *temp;
4005
4006                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4007                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4008                     return(NULL);
4009                 }
4010                 temp = (xmlNodePtr *) xmlRealloc(
4011                     set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4012                 if (temp == NULL) {
4013                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4014                     return(NULL);
4015                 }
4016                 set1->nodeTab = temp;
4017                 set1->nodeMax *= 2;
4018             }
4019             if (n2->type == XML_NAMESPACE_DECL) {
4020                 xmlNsPtr ns = (xmlNsPtr) n2;
4021
4022                 set1->nodeTab[set1->nodeNr++] =
4023                     xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
4024             } else
4025                 set1->nodeTab[set1->nodeNr++] = n2;
4026 skip_node:
4027             {}
4028         }
4029     }
4030     set2->nodeNr = 0;
4031     return(set1);
4032 }
4033
4034 /**
4035  * xmlXPathNodeSetMergeAndClearNoDupls:
4036  * @set1:  the first NodeSet or NULL
4037  * @set2:  the second NodeSet
4038  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4039  *
4040  * Merges two nodesets, all nodes from @set2 are added to @set1
4041  * if @set1 is NULL, a new set is created and copied from @set2.
4042  * Doesn't chack for duplicate nodes. Clears set2.
4043  *
4044  * Returns @set1 once extended or NULL in case of error.
4045  */
4046 static xmlNodeSetPtr
4047 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4048                                     int hasNullEntries)
4049 {
4050     if (set2 == NULL)
4051         return(set1);
4052     if ((set1 == NULL) && (hasNullEntries == 0)) {
4053         /*
4054         * Note that doing a memcpy of the list, namespace nodes are
4055         * just assigned to set1, since set2 is cleared anyway.
4056         */
4057         set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4058         if (set1 == NULL)
4059             return(NULL);
4060         if (set2->nodeNr != 0) {
4061             memcpy(set1->nodeTab, set2->nodeTab,
4062                 set2->nodeNr * sizeof(xmlNodePtr));
4063             set1->nodeNr = set2->nodeNr;
4064         }
4065     } else {
4066         int i;
4067         xmlNodePtr n2;
4068
4069         if (set1 == NULL)
4070             set1 = xmlXPathNodeSetCreate(NULL);
4071         if (set1 == NULL)
4072             return (NULL);
4073
4074         for (i = 0;i < set2->nodeNr;i++) {
4075             n2 = set2->nodeTab[i];
4076             /*
4077             * Skip NULLed entries.
4078             */
4079             if (n2 == NULL)
4080                 continue;
4081             if (set1->nodeMax == 0) {
4082                 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4083                     XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4084                 if (set1->nodeTab == NULL) {
4085                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4086                     return(NULL);
4087                 }
4088                 memset(set1->nodeTab, 0,
4089                     XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4090                 set1->nodeMax = XML_NODESET_DEFAULT;
4091             } else if (set1->nodeNr >= set1->nodeMax) {
4092                 xmlNodePtr *temp;
4093
4094                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4095                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4096                     return(NULL);
4097                 }
4098                 temp = (xmlNodePtr *) xmlRealloc(
4099                     set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4100                 if (temp == NULL) {
4101                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4102                     return(NULL);
4103                 }
4104                 set1->nodeTab = temp;
4105                 set1->nodeMax *= 2;
4106             }
4107             set1->nodeTab[set1->nodeNr++] = n2;
4108         }
4109     }
4110     set2->nodeNr = 0;
4111     return(set1);
4112 }
4113
4114 /**
4115  * xmlXPathNodeSetDel:
4116  * @cur:  the initial node set
4117  * @val:  an xmlNodePtr
4118  *
4119  * Removes an xmlNodePtr from an existing NodeSet
4120  */
4121 void
4122 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4123     int i;
4124
4125     if (cur == NULL) return;
4126     if (val == NULL) return;
4127
4128     /*
4129      * find node in nodeTab
4130      */
4131     for (i = 0;i < cur->nodeNr;i++)
4132         if (cur->nodeTab[i] == val) break;
4133
4134     if (i >= cur->nodeNr) {     /* not found */
4135 #ifdef DEBUG
4136         xmlGenericError(xmlGenericErrorContext,
4137                 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4138                 val->name);
4139 #endif
4140         return;
4141     }
4142     if ((cur->nodeTab[i] != NULL) &&
4143         (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4144         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4145     cur->nodeNr--;
4146     for (;i < cur->nodeNr;i++)
4147         cur->nodeTab[i] = cur->nodeTab[i + 1];
4148     cur->nodeTab[cur->nodeNr] = NULL;
4149 }
4150
4151 /**
4152  * xmlXPathNodeSetRemove:
4153  * @cur:  the initial node set
4154  * @val:  the index to remove
4155  *
4156  * Removes an entry from an existing NodeSet list.
4157  */
4158 void
4159 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4160     if (cur == NULL) return;
4161     if (val >= cur->nodeNr) return;
4162     if ((cur->nodeTab[val] != NULL) &&
4163         (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4164         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4165     cur->nodeNr--;
4166     for (;val < cur->nodeNr;val++)
4167         cur->nodeTab[val] = cur->nodeTab[val + 1];
4168     cur->nodeTab[cur->nodeNr] = NULL;
4169 }
4170
4171 /**
4172  * xmlXPathFreeNodeSet:
4173  * @obj:  the xmlNodeSetPtr to free
4174  *
4175  * Free the NodeSet compound (not the actual nodes !).
4176  */
4177 void
4178 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4179     if (obj == NULL) return;
4180     if (obj->nodeTab != NULL) {
4181         int i;
4182
4183         /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4184         for (i = 0;i < obj->nodeNr;i++)
4185             if ((obj->nodeTab[i] != NULL) &&
4186                 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4187                 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4188         xmlFree(obj->nodeTab);
4189     }
4190     xmlFree(obj);
4191 }
4192
4193 /**
4194  * xmlXPathNodeSetClear:
4195  * @set:  the node set to clear
4196  *
4197  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4198  * are feed), but does *not* free the list itself. Sets the length of the
4199  * list to 0.
4200  */
4201 static void
4202 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4203 {
4204     if ((set == NULL) || (set->nodeNr <= 0))
4205         return;
4206     else if (hasNsNodes) {
4207         int i;
4208         xmlNodePtr node;
4209
4210         for (i = 0; i < set->nodeNr; i++) {
4211             node = set->nodeTab[i];
4212             if ((node != NULL) &&
4213                 (node->type == XML_NAMESPACE_DECL))
4214                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4215         }
4216     }
4217     set->nodeNr = 0;
4218 }
4219
4220 /**
4221  * xmlXPathNodeSetClearFromPos:
4222  * @set: the node set to be cleared
4223  * @pos: the start position to clear from
4224  *
4225  * Clears the list from temporary XPath objects (e.g. namespace nodes
4226  * are feed) starting with the entry at @pos, but does *not* free the list
4227  * itself. Sets the length of the list to @pos.
4228  */
4229 static void
4230 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4231 {
4232     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4233         return;
4234     else if ((hasNsNodes)) {
4235         int i;
4236         xmlNodePtr node;
4237
4238         for (i = pos; i < set->nodeNr; i++) {
4239             node = set->nodeTab[i];
4240             if ((node != NULL) &&
4241                 (node->type == XML_NAMESPACE_DECL))
4242                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4243         }
4244     }
4245     set->nodeNr = pos;
4246 }
4247
4248 /**
4249  * xmlXPathFreeValueTree:
4250  * @obj:  the xmlNodeSetPtr to free
4251  *
4252  * Free the NodeSet compound and the actual tree, this is different
4253  * from xmlXPathFreeNodeSet()
4254  */
4255 static void
4256 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4257     int i;
4258
4259     if (obj == NULL) return;
4260
4261     if (obj->nodeTab != NULL) {
4262         for (i = 0;i < obj->nodeNr;i++) {
4263             if (obj->nodeTab[i] != NULL) {
4264                 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4265                     xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4266                 } else {
4267                     xmlFreeNodeList(obj->nodeTab[i]);
4268                 }
4269             }
4270         }
4271         xmlFree(obj->nodeTab);
4272     }
4273     xmlFree(obj);
4274 }
4275
4276 #if defined(DEBUG) || defined(DEBUG_STEP)
4277 /**
4278  * xmlGenericErrorContextNodeSet:
4279  * @output:  a FILE * for the output
4280  * @obj:  the xmlNodeSetPtr to display
4281  *
4282  * Quick display of a NodeSet
4283  */
4284 void
4285 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4286     int i;
4287
4288     if (output == NULL) output = xmlGenericErrorContext;
4289     if (obj == NULL)  {
4290         fprintf(output, "NodeSet == NULL !\n");
4291         return;
4292     }
4293     if (obj->nodeNr == 0) {
4294         fprintf(output, "NodeSet is empty\n");
4295         return;
4296     }
4297     if (obj->nodeTab == NULL) {
4298         fprintf(output, " nodeTab == NULL !\n");
4299         return;
4300     }
4301     for (i = 0; i < obj->nodeNr; i++) {
4302         if (obj->nodeTab[i] == NULL) {
4303             fprintf(output, " NULL !\n");
4304             return;
4305         }
4306         if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4307             (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4308             fprintf(output, " /");
4309         else if (obj->nodeTab[i]->name == NULL)
4310             fprintf(output, " noname!");
4311         else fprintf(output, " %s", obj->nodeTab[i]->name);
4312     }
4313     fprintf(output, "\n");
4314 }
4315 #endif
4316
4317 /**
4318  * xmlXPathNewNodeSet:
4319  * @val:  the NodePtr value
4320  *
4321  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4322  * it with the single Node @val
4323  *
4324  * Returns the newly created object.
4325  */
4326 xmlXPathObjectPtr
4327 xmlXPathNewNodeSet(xmlNodePtr val) {
4328     xmlXPathObjectPtr ret;
4329
4330     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4331     if (ret == NULL) {
4332         xmlXPathErrMemory(NULL, "creating nodeset\n");
4333         return(NULL);
4334     }
4335     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4336     ret->type = XPATH_NODESET;
4337     ret->boolval = 0;
4338     ret->nodesetval = xmlXPathNodeSetCreate(val);
4339     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4340 #ifdef XP_DEBUG_OBJ_USAGE
4341     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4342 #endif
4343     return(ret);
4344 }
4345
4346 /**
4347  * xmlXPathNewValueTree:
4348  * @val:  the NodePtr value
4349  *
4350  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4351  * it with the tree root @val
4352  *
4353  * Returns the newly created object.
4354  */
4355 xmlXPathObjectPtr
4356 xmlXPathNewValueTree(xmlNodePtr val) {
4357     xmlXPathObjectPtr ret;
4358
4359     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4360     if (ret == NULL) {
4361         xmlXPathErrMemory(NULL, "creating result value tree\n");
4362         return(NULL);
4363     }
4364     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4365     ret->type = XPATH_XSLT_TREE;
4366     ret->boolval = 1;
4367     ret->user = (void *) val;
4368     ret->nodesetval = xmlXPathNodeSetCreate(val);
4369 #ifdef XP_DEBUG_OBJ_USAGE
4370     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4371 #endif
4372     return(ret);
4373 }
4374
4375 /**
4376  * xmlXPathNewNodeSetList:
4377  * @val:  an existing NodeSet
4378  *
4379  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4380  * it with the Nodeset @val
4381  *
4382  * Returns the newly created object.
4383  */
4384 xmlXPathObjectPtr
4385 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4386 {
4387     xmlXPathObjectPtr ret;
4388     int i;
4389
4390     if (val == NULL)
4391         ret = NULL;
4392     else if (val->nodeTab == NULL)
4393         ret = xmlXPathNewNodeSet(NULL);
4394     else {
4395         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4396         if (ret) {
4397             for (i = 1; i < val->nodeNr; ++i) {
4398                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4399                     < 0) break;
4400             }
4401         }
4402     }
4403
4404     return (ret);
4405 }
4406
4407 /**
4408  * xmlXPathWrapNodeSet:
4409  * @val:  the NodePtr value
4410  *
4411  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4412  *
4413  * Returns the newly created object.
4414  */
4415 xmlXPathObjectPtr
4416 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4417     xmlXPathObjectPtr ret;
4418
4419     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4420     if (ret == NULL) {
4421         xmlXPathErrMemory(NULL, "creating node set object\n");
4422         return(NULL);
4423     }
4424     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4425     ret->type = XPATH_NODESET;
4426     ret->nodesetval = val;
4427 #ifdef XP_DEBUG_OBJ_USAGE
4428     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4429 #endif
4430     return(ret);
4431 }
4432
4433 /**
4434  * xmlXPathFreeNodeSetList:
4435  * @obj:  an existing NodeSetList object
4436  *
4437  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4438  * the list contrary to xmlXPathFreeObject().
4439  */
4440 void
4441 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4442     if (obj == NULL) return;
4443 #ifdef XP_DEBUG_OBJ_USAGE
4444     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4445 #endif
4446     xmlFree(obj);
4447 }
4448
4449 /**
4450  * xmlXPathDifference:
4451  * @nodes1:  a node-set
4452  * @nodes2:  a node-set
4453  *
4454  * Implements the EXSLT - Sets difference() function:
4455  *    node-set set:difference (node-set, node-set)
4456  *
4457  * Returns the difference between the two node sets, or nodes1 if
4458  *         nodes2 is empty
4459  */
4460 xmlNodeSetPtr
4461 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4462     xmlNodeSetPtr ret;
4463     int i, l1;
4464     xmlNodePtr cur;
4465
4466     if (xmlXPathNodeSetIsEmpty(nodes2))
4467         return(nodes1);
4468
4469     ret = xmlXPathNodeSetCreate(NULL);
4470     if (xmlXPathNodeSetIsEmpty(nodes1))
4471         return(ret);
4472
4473     l1 = xmlXPathNodeSetGetLength(nodes1);
4474
4475     for (i = 0; i < l1; i++) {
4476         cur = xmlXPathNodeSetItem(nodes1, i);
4477         if (!xmlXPathNodeSetContains(nodes2, cur)) {
4478             if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4479                 break;
4480         }
4481     }
4482     return(ret);
4483 }
4484
4485 /**
4486  * xmlXPathIntersection:
4487  * @nodes1:  a node-set
4488  * @nodes2:  a node-set
4489  *
4490  * Implements the EXSLT - Sets intersection() function:
4491  *    node-set set:intersection (node-set, node-set)
4492  *
4493  * Returns a node set comprising the nodes that are within both the
4494  *         node sets passed as arguments
4495  */
4496 xmlNodeSetPtr
4497 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4498     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4499     int i, l1;
4500     xmlNodePtr cur;
4501
4502     if (ret == NULL)
4503         return(ret);
4504     if (xmlXPathNodeSetIsEmpty(nodes1))
4505         return(ret);
4506     if (xmlXPathNodeSetIsEmpty(nodes2))
4507         return(ret);
4508
4509     l1 = xmlXPathNodeSetGetLength(nodes1);
4510
4511     for (i = 0; i < l1; i++) {
4512         cur = xmlXPathNodeSetItem(nodes1, i);
4513         if (xmlXPathNodeSetContains(nodes2, cur)) {
4514             if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4515                 break;
4516         }
4517     }
4518     return(ret);
4519 }
4520
4521 /**
4522  * xmlXPathDistinctSorted:
4523  * @nodes:  a node-set, sorted by document order
4524  *
4525  * Implements the EXSLT - Sets distinct() function:
4526  *    node-set set:distinct (node-set)
4527  *
4528  * Returns a subset of the nodes contained in @nodes, or @nodes if
4529  *         it is empty
4530  */
4531 xmlNodeSetPtr
4532 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4533     xmlNodeSetPtr ret;
4534     xmlHashTablePtr hash;
4535     int i, l;
4536     xmlChar * strval;
4537     xmlNodePtr cur;
4538
4539     if (xmlXPathNodeSetIsEmpty(nodes))
4540         return(nodes);
4541
4542     ret = xmlXPathNodeSetCreate(NULL);
4543     if (ret == NULL)
4544         return(ret);
4545     l = xmlXPathNodeSetGetLength(nodes);
4546     hash = xmlHashCreate (l);
4547     for (i = 0; i < l; i++) {
4548         cur = xmlXPathNodeSetItem(nodes, i);
4549         strval = xmlXPathCastNodeToString(cur);
4550         if (xmlHashLookup(hash, strval) == NULL) {
4551             xmlHashAddEntry(hash, strval, strval);
4552             if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4553                 break;
4554         } else {
4555             xmlFree(strval);
4556         }
4557     }
4558     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4559     return(ret);
4560 }
4561
4562 /**
4563  * xmlXPathDistinct:
4564  * @nodes:  a node-set
4565  *
4566  * Implements the EXSLT - Sets distinct() function:
4567  *    node-set set:distinct (node-set)
4568  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4569  * is called with the sorted node-set
4570  *
4571  * Returns a subset of the nodes contained in @nodes, or @nodes if
4572  *         it is empty
4573  */
4574 xmlNodeSetPtr
4575 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4576     if (xmlXPathNodeSetIsEmpty(nodes))
4577         return(nodes);
4578
4579     xmlXPathNodeSetSort(nodes);
4580     return(xmlXPathDistinctSorted(nodes));
4581 }
4582
4583 /**
4584  * xmlXPathHasSameNodes:
4585  * @nodes1:  a node-set
4586  * @nodes2:  a node-set
4587  *
4588  * Implements the EXSLT - Sets has-same-nodes function:
4589  *    boolean set:has-same-node(node-set, node-set)
4590  *
4591  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4592  *         otherwise
4593  */
4594 int
4595 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4596     int i, l;
4597     xmlNodePtr cur;
4598
4599     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4600         xmlXPathNodeSetIsEmpty(nodes2))
4601         return(0);
4602
4603     l = xmlXPathNodeSetGetLength(nodes1);
4604     for (i = 0; i < l; i++) {
4605         cur = xmlXPathNodeSetItem(nodes1, i);
4606         if (xmlXPathNodeSetContains(nodes2, cur))
4607             return(1);
4608     }
4609     return(0);
4610 }
4611
4612 /**
4613  * xmlXPathNodeLeadingSorted:
4614  * @nodes: a node-set, sorted by document order
4615  * @node: a node
4616  *
4617  * Implements the EXSLT - Sets leading() function:
4618  *    node-set set:leading (node-set, node-set)
4619  *
4620  * Returns the nodes in @nodes that precede @node in document order,
4621  *         @nodes if @node is NULL or an empty node-set if @nodes
4622  *         doesn't contain @node
4623  */
4624 xmlNodeSetPtr
4625 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4626     int i, l;
4627     xmlNodePtr cur;
4628     xmlNodeSetPtr ret;
4629
4630     if (node == NULL)
4631         return(nodes);
4632
4633     ret = xmlXPathNodeSetCreate(NULL);
4634     if (ret == NULL)
4635         return(ret);
4636     if (xmlXPathNodeSetIsEmpty(nodes) ||
4637         (!xmlXPathNodeSetContains(nodes, node)))
4638         return(ret);
4639
4640     l = xmlXPathNodeSetGetLength(nodes);
4641     for (i = 0; i < l; i++) {
4642         cur = xmlXPathNodeSetItem(nodes, i);
4643         if (cur == node)
4644             break;
4645         if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4646             break;
4647     }
4648     return(ret);
4649 }
4650
4651 /**
4652  * xmlXPathNodeLeading:
4653  * @nodes:  a node-set
4654  * @node:  a node
4655  *
4656  * Implements the EXSLT - Sets leading() function:
4657  *    node-set set:leading (node-set, node-set)
4658  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4659  * is called.
4660  *
4661  * Returns the nodes in @nodes that precede @node in document order,
4662  *         @nodes if @node is NULL or an empty node-set if @nodes
4663  *         doesn't contain @node
4664  */
4665 xmlNodeSetPtr
4666 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4667     xmlXPathNodeSetSort(nodes);
4668     return(xmlXPathNodeLeadingSorted(nodes, node));
4669 }
4670
4671 /**
4672  * xmlXPathLeadingSorted:
4673  * @nodes1:  a node-set, sorted by document order
4674  * @nodes2:  a node-set, sorted by document order
4675  *
4676  * Implements the EXSLT - Sets leading() function:
4677  *    node-set set:leading (node-set, node-set)
4678  *
4679  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4680  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4681  *         an empty node-set if @nodes1 doesn't contain @nodes2
4682  */
4683 xmlNodeSetPtr
4684 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4685     if (xmlXPathNodeSetIsEmpty(nodes2))
4686         return(nodes1);
4687     return(xmlXPathNodeLeadingSorted(nodes1,
4688                                      xmlXPathNodeSetItem(nodes2, 1)));
4689 }
4690
4691 /**
4692  * xmlXPathLeading:
4693  * @nodes1:  a node-set
4694  * @nodes2:  a node-set
4695  *
4696  * Implements the EXSLT - Sets leading() function:
4697  *    node-set set:leading (node-set, node-set)
4698  * @nodes1 and @nodes2 are sorted by document order, then
4699  * #exslSetsLeadingSorted is called.
4700  *
4701  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4702  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4703  *         an empty node-set if @nodes1 doesn't contain @nodes2
4704  */
4705 xmlNodeSetPtr
4706 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4707     if (xmlXPathNodeSetIsEmpty(nodes2))
4708         return(nodes1);
4709     if (xmlXPathNodeSetIsEmpty(nodes1))
4710         return(xmlXPathNodeSetCreate(NULL));
4711     xmlXPathNodeSetSort(nodes1);
4712     xmlXPathNodeSetSort(nodes2);
4713     return(xmlXPathNodeLeadingSorted(nodes1,
4714                                      xmlXPathNodeSetItem(nodes2, 1)));
4715 }
4716
4717 /**
4718  * xmlXPathNodeTrailingSorted:
4719  * @nodes: a node-set, sorted by document order
4720  * @node: a node
4721  *
4722  * Implements the EXSLT - Sets trailing() function:
4723  *    node-set set:trailing (node-set, node-set)
4724  *
4725  * Returns the nodes in @nodes that follow @node in document order,
4726  *         @nodes if @node is NULL or an empty node-set if @nodes
4727  *         doesn't contain @node
4728  */
4729 xmlNodeSetPtr
4730 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4731     int i, l;
4732     xmlNodePtr cur;
4733     xmlNodeSetPtr ret;
4734
4735     if (node == NULL)
4736         return(nodes);
4737
4738     ret = xmlXPathNodeSetCreate(NULL);
4739     if (ret == NULL)
4740         return(ret);
4741     if (xmlXPathNodeSetIsEmpty(nodes) ||
4742         (!xmlXPathNodeSetContains(nodes, node)))
4743         return(ret);
4744
4745     l = xmlXPathNodeSetGetLength(nodes);
4746     for (i = l - 1; i >= 0; i--) {
4747         cur = xmlXPathNodeSetItem(nodes, i);
4748         if (cur == node)
4749             break;
4750         if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4751             break;
4752     }
4753     xmlXPathNodeSetSort(ret);   /* bug 413451 */
4754     return(ret);
4755 }
4756
4757 /**
4758  * xmlXPathNodeTrailing:
4759  * @nodes:  a node-set
4760  * @node:  a node
4761  *
4762  * Implements the EXSLT - Sets trailing() function:
4763  *    node-set set:trailing (node-set, node-set)
4764  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4765  * is called.
4766  *
4767  * Returns the nodes in @nodes that follow @node in document order,
4768  *         @nodes if @node is NULL or an empty node-set if @nodes
4769  *         doesn't contain @node
4770  */
4771 xmlNodeSetPtr
4772 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4773     xmlXPathNodeSetSort(nodes);
4774     return(xmlXPathNodeTrailingSorted(nodes, node));
4775 }
4776
4777 /**
4778  * xmlXPathTrailingSorted:
4779  * @nodes1:  a node-set, sorted by document order
4780  * @nodes2:  a node-set, sorted by document order
4781  *
4782  * Implements the EXSLT - Sets trailing() function:
4783  *    node-set set:trailing (node-set, node-set)
4784  *
4785  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4786  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4787  *         an empty node-set if @nodes1 doesn't contain @nodes2
4788  */
4789 xmlNodeSetPtr
4790 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4791     if (xmlXPathNodeSetIsEmpty(nodes2))
4792         return(nodes1);
4793     return(xmlXPathNodeTrailingSorted(nodes1,
4794                                       xmlXPathNodeSetItem(nodes2, 0)));
4795 }
4796
4797 /**
4798  * xmlXPathTrailing:
4799  * @nodes1:  a node-set
4800  * @nodes2:  a node-set
4801  *
4802  * Implements the EXSLT - Sets trailing() function:
4803  *    node-set set:trailing (node-set, node-set)
4804  * @nodes1 and @nodes2 are sorted by document order, then
4805  * #xmlXPathTrailingSorted is called.
4806  *
4807  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4808  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4809  *         an empty node-set if @nodes1 doesn't contain @nodes2
4810  */
4811 xmlNodeSetPtr
4812 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4813     if (xmlXPathNodeSetIsEmpty(nodes2))
4814         return(nodes1);
4815     if (xmlXPathNodeSetIsEmpty(nodes1))
4816         return(xmlXPathNodeSetCreate(NULL));
4817     xmlXPathNodeSetSort(nodes1);
4818     xmlXPathNodeSetSort(nodes2);
4819     return(xmlXPathNodeTrailingSorted(nodes1,
4820                                       xmlXPathNodeSetItem(nodes2, 0)));
4821 }
4822
4823 /************************************************************************
4824  *                                                                      *
4825  *              Routines to handle extra functions                      *
4826  *                                                                      *
4827  ************************************************************************/
4828
4829 /**
4830  * xmlXPathRegisterFunc:
4831  * @ctxt:  the XPath context
4832  * @name:  the function name
4833  * @f:  the function implementation or NULL
4834  *
4835  * Register a new function. If @f is NULL it unregisters the function
4836  *
4837  * Returns 0 in case of success, -1 in case of error
4838  */
4839 int
4840 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4841                      xmlXPathFunction f) {
4842     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4843 }
4844
4845 /**
4846  * xmlXPathRegisterFuncNS:
4847  * @ctxt:  the XPath context
4848  * @name:  the function name
4849  * @ns_uri:  the function namespace URI
4850  * @f:  the function implementation or NULL
4851  *
4852  * Register a new function. If @f is NULL it unregisters the function
4853  *
4854  * Returns 0 in case of success, -1 in case of error
4855  */
4856 int
4857 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4858                        const xmlChar *ns_uri, xmlXPathFunction f) {
4859     if (ctxt == NULL)
4860         return(-1);
4861     if (name == NULL)
4862         return(-1);
4863
4864     if (ctxt->funcHash == NULL)
4865         ctxt->funcHash = xmlHashCreate(0);
4866     if (ctxt->funcHash == NULL)
4867         return(-1);
4868     if (f == NULL)
4869         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4870     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4871 }
4872
4873 /**
4874  * xmlXPathRegisterFuncLookup:
4875  * @ctxt:  the XPath context
4876  * @f:  the lookup function
4877  * @funcCtxt:  the lookup data
4878  *
4879  * Registers an external mechanism to do function lookup.
4880  */
4881 void
4882 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4883                             xmlXPathFuncLookupFunc f,
4884                             void *funcCtxt) {
4885     if (ctxt == NULL)
4886         return;
4887     ctxt->funcLookupFunc = f;
4888     ctxt->funcLookupData = funcCtxt;
4889 }
4890
4891 /**
4892  * xmlXPathFunctionLookup:
4893  * @ctxt:  the XPath context
4894  * @name:  the function name
4895  *
4896  * Search in the Function array of the context for the given
4897  * function.
4898  *
4899  * Returns the xmlXPathFunction or NULL if not found
4900  */
4901 xmlXPathFunction
4902 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4903     if (ctxt == NULL)
4904         return (NULL);
4905
4906     if (ctxt->funcLookupFunc != NULL) {
4907         xmlXPathFunction ret;
4908         xmlXPathFuncLookupFunc f;
4909
4910         f = ctxt->funcLookupFunc;
4911         ret = f(ctxt->funcLookupData, name, NULL);
4912         if (ret != NULL)
4913             return(ret);
4914     }
4915     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4916 }
4917
4918 /**
4919  * xmlXPathFunctionLookupNS:
4920  * @ctxt:  the XPath context
4921  * @name:  the function name
4922  * @ns_uri:  the function namespace URI
4923  *
4924  * Search in the Function array of the context for the given
4925  * function.
4926  *
4927  * Returns the xmlXPathFunction or NULL if not found
4928  */
4929 xmlXPathFunction
4930 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4931                          const xmlChar *ns_uri) {
4932     xmlXPathFunction ret;
4933
4934     if (ctxt == NULL)
4935         return(NULL);
4936     if (name == NULL)
4937         return(NULL);
4938
4939     if (ctxt->funcLookupFunc != NULL) {
4940         xmlXPathFuncLookupFunc f;
4941
4942         f = ctxt->funcLookupFunc;
4943         ret = f(ctxt->funcLookupData, name, ns_uri);
4944         if (ret != NULL)
4945             return(ret);
4946     }
4947
4948     if (ctxt->funcHash == NULL)
4949         return(NULL);
4950
4951     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4952     return(ret);
4953 }
4954
4955 /**
4956  * xmlXPathRegisteredFuncsCleanup:
4957  * @ctxt:  the XPath context
4958  *
4959  * Cleanup the XPath context data associated to registered functions
4960  */
4961 void
4962 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4963     if (ctxt == NULL)
4964         return;
4965
4966     xmlHashFree(ctxt->funcHash, NULL);
4967     ctxt->funcHash = NULL;
4968 }
4969
4970 /************************************************************************
4971  *                                                                      *
4972  *                      Routines to handle Variables                    *
4973  *                                                                      *
4974  ************************************************************************/
4975
4976 /**
4977  * xmlXPathRegisterVariable:
4978  * @ctxt:  the XPath context
4979  * @name:  the variable name
4980  * @value:  the variable value or NULL
4981  *
4982  * Register a new variable value. If @value is NULL it unregisters
4983  * the variable
4984  *
4985  * Returns 0 in case of success, -1 in case of error
4986  */
4987 int
4988 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4989                          xmlXPathObjectPtr value) {
4990     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4991 }
4992
4993 /**
4994  * xmlXPathRegisterVariableNS:
4995  * @ctxt:  the XPath context
4996  * @name:  the variable name
4997  * @ns_uri:  the variable namespace URI
4998  * @value:  the variable value or NULL
4999  *
5000  * Register a new variable value. If @value is NULL it unregisters
5001  * the variable
5002  *
5003  * Returns 0 in case of success, -1 in case of error
5004  */
5005 int
5006 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5007                            const xmlChar *ns_uri,
5008                            xmlXPathObjectPtr value) {
5009     if (ctxt == NULL)
5010         return(-1);
5011     if (name == NULL)
5012         return(-1);
5013
5014     if (ctxt->varHash == NULL)
5015         ctxt->varHash = xmlHashCreate(0);
5016     if (ctxt->varHash == NULL)
5017         return(-1);
5018     if (value == NULL)
5019         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5020                                    (xmlHashDeallocator)xmlXPathFreeObject));
5021     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5022                                (void *) value,
5023                                (xmlHashDeallocator)xmlXPathFreeObject));
5024 }
5025
5026 /**
5027  * xmlXPathRegisterVariableLookup:
5028  * @ctxt:  the XPath context
5029  * @f:  the lookup function
5030  * @data:  the lookup data
5031  *
5032  * register an external mechanism to do variable lookup
5033  */
5034 void
5035 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5036          xmlXPathVariableLookupFunc f, void *data) {
5037     if (ctxt == NULL)
5038         return;
5039     ctxt->varLookupFunc = f;
5040     ctxt->varLookupData = data;
5041 }
5042
5043 /**
5044  * xmlXPathVariableLookup:
5045  * @ctxt:  the XPath context
5046  * @name:  the variable name
5047  *
5048  * Search in the Variable array of the context for the given
5049  * variable value.
5050  *
5051  * Returns a copy of the value or NULL if not found
5052  */
5053 xmlXPathObjectPtr
5054 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5055     if (ctxt == NULL)
5056         return(NULL);
5057
5058     if (ctxt->varLookupFunc != NULL) {
5059         xmlXPathObjectPtr ret;
5060
5061         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5062                 (ctxt->varLookupData, name, NULL);
5063         return(ret);
5064     }
5065     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5066 }
5067
5068 /**
5069  * xmlXPathVariableLookupNS:
5070  * @ctxt:  the XPath context
5071  * @name:  the variable name
5072  * @ns_uri:  the variable namespace URI
5073  *
5074  * Search in the Variable array of the context for the given
5075  * variable value.
5076  *
5077  * Returns the a copy of the value or NULL if not found
5078  */
5079 xmlXPathObjectPtr
5080 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5081                          const xmlChar *ns_uri) {
5082     if (ctxt == NULL)
5083         return(NULL);
5084
5085     if (ctxt->varLookupFunc != NULL) {
5086         xmlXPathObjectPtr ret;
5087
5088         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5089                 (ctxt->varLookupData, name, ns_uri);
5090         if (ret != NULL) return(ret);
5091     }
5092
5093     if (ctxt->varHash == NULL)
5094         return(NULL);
5095     if (name == NULL)
5096         return(NULL);
5097
5098     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5099                 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5100 }
5101
5102 /**
5103  * xmlXPathRegisteredVariablesCleanup:
5104  * @ctxt:  the XPath context
5105  *
5106  * Cleanup the XPath context data associated to registered variables
5107  */
5108 void
5109 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5110     if (ctxt == NULL)
5111         return;
5112
5113     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5114     ctxt->varHash = NULL;
5115 }
5116
5117 /**
5118  * xmlXPathRegisterNs:
5119  * @ctxt:  the XPath context
5120  * @prefix:  the namespace prefix cannot be NULL or empty string
5121  * @ns_uri:  the namespace name
5122  *
5123  * Register a new namespace. If @ns_uri is NULL it unregisters
5124  * the namespace
5125  *
5126  * Returns 0 in case of success, -1 in case of error
5127  */
5128 int
5129 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5130                            const xmlChar *ns_uri) {
5131     if (ctxt == NULL)
5132         return(-1);
5133     if (prefix == NULL)
5134         return(-1);
5135     if (prefix[0] == 0)
5136         return(-1);
5137
5138     if (ctxt->nsHash == NULL)
5139         ctxt->nsHash = xmlHashCreate(10);
5140     if (ctxt->nsHash == NULL)
5141         return(-1);
5142     if (ns_uri == NULL)
5143         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5144                                   (xmlHashDeallocator)xmlFree));
5145     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5146                               (xmlHashDeallocator)xmlFree));
5147 }
5148
5149 /**
5150  * xmlXPathNsLookup:
5151  * @ctxt:  the XPath context
5152  * @prefix:  the namespace prefix value
5153  *
5154  * Search in the namespace declaration array of the context for the given
5155  * namespace name associated to the given prefix
5156  *
5157  * Returns the value or NULL if not found
5158  */
5159 const xmlChar *
5160 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5161     if (ctxt == NULL)
5162         return(NULL);
5163     if (prefix == NULL)
5164         return(NULL);
5165
5166 #ifdef XML_XML_NAMESPACE
5167     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5168         return(XML_XML_NAMESPACE);
5169 #endif
5170
5171     if (ctxt->namespaces != NULL) {
5172         int i;
5173
5174         for (i = 0;i < ctxt->nsNr;i++) {
5175             if ((ctxt->namespaces[i] != NULL) &&
5176                 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5177                 return(ctxt->namespaces[i]->href);
5178         }
5179     }
5180
5181     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5182 }
5183
5184 /**
5185  * xmlXPathRegisteredNsCleanup:
5186  * @ctxt:  the XPath context
5187  *
5188  * Cleanup the XPath context data associated to registered variables
5189  */
5190 void
5191 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5192     if (ctxt == NULL)
5193         return;
5194
5195     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5196     ctxt->nsHash = NULL;
5197 }
5198
5199 /************************************************************************
5200  *                                                                      *
5201  *                      Routines to handle Values                       *
5202  *                                                                      *
5203  ************************************************************************/
5204
5205 /* Allocations are terrible, one needs to optimize all this !!! */
5206
5207 /**
5208  * xmlXPathNewFloat:
5209  * @val:  the double value
5210  *
5211  * Create a new xmlXPathObjectPtr of type double and of value @val
5212  *
5213  * Returns the newly created object.
5214  */
5215 xmlXPathObjectPtr
5216 xmlXPathNewFloat(double val) {
5217     xmlXPathObjectPtr ret;
5218
5219     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5220     if (ret == NULL) {
5221         xmlXPathErrMemory(NULL, "creating float object\n");
5222         return(NULL);
5223     }
5224     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5225     ret->type = XPATH_NUMBER;
5226     ret->floatval = val;
5227 #ifdef XP_DEBUG_OBJ_USAGE
5228     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5229 #endif
5230     return(ret);
5231 }
5232
5233 /**
5234  * xmlXPathNewBoolean:
5235  * @val:  the boolean value
5236  *
5237  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5238  *
5239  * Returns the newly created object.
5240  */
5241 xmlXPathObjectPtr
5242 xmlXPathNewBoolean(int val) {
5243     xmlXPathObjectPtr ret;
5244
5245     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5246     if (ret == NULL) {
5247         xmlXPathErrMemory(NULL, "creating boolean object\n");
5248         return(NULL);
5249     }
5250     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5251     ret->type = XPATH_BOOLEAN;
5252     ret->boolval = (val != 0);
5253 #ifdef XP_DEBUG_OBJ_USAGE
5254     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5255 #endif
5256     return(ret);
5257 }
5258
5259 /**
5260  * xmlXPathNewString:
5261  * @val:  the xmlChar * value
5262  *
5263  * Create a new xmlXPathObjectPtr of type string and of value @val
5264  *
5265  * Returns the newly created object.
5266  */
5267 xmlXPathObjectPtr
5268 xmlXPathNewString(const xmlChar *val) {
5269     xmlXPathObjectPtr ret;
5270
5271     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5272     if (ret == NULL) {
5273         xmlXPathErrMemory(NULL, "creating string object\n");
5274         return(NULL);
5275     }
5276     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5277     ret->type = XPATH_STRING;
5278     if (val != NULL)
5279         ret->stringval = xmlStrdup(val);
5280     else
5281         ret->stringval = xmlStrdup((const xmlChar *)"");
5282 #ifdef XP_DEBUG_OBJ_USAGE
5283     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5284 #endif
5285     return(ret);
5286 }
5287
5288 /**
5289  * xmlXPathWrapString:
5290  * @val:  the xmlChar * value
5291  *
5292  * Wraps the @val string into an XPath object.
5293  *
5294  * Returns the newly created object.
5295  */
5296 xmlXPathObjectPtr
5297 xmlXPathWrapString (xmlChar *val) {
5298     xmlXPathObjectPtr ret;
5299
5300     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5301     if (ret == NULL) {
5302         xmlXPathErrMemory(NULL, "creating string object\n");
5303         return(NULL);
5304     }
5305     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5306     ret->type = XPATH_STRING;
5307     ret->stringval = val;
5308 #ifdef XP_DEBUG_OBJ_USAGE
5309     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5310 #endif
5311     return(ret);
5312 }
5313
5314 /**
5315  * xmlXPathNewCString:
5316  * @val:  the char * value
5317  *
5318  * Create a new xmlXPathObjectPtr of type string and of value @val
5319  *
5320  * Returns the newly created object.
5321  */
5322 xmlXPathObjectPtr
5323 xmlXPathNewCString(const char *val) {
5324     xmlXPathObjectPtr ret;
5325
5326     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5327     if (ret == NULL) {
5328         xmlXPathErrMemory(NULL, "creating string object\n");
5329         return(NULL);
5330     }
5331     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5332     ret->type = XPATH_STRING;
5333     ret->stringval = xmlStrdup(BAD_CAST val);
5334 #ifdef XP_DEBUG_OBJ_USAGE
5335     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5336 #endif
5337     return(ret);
5338 }
5339
5340 /**
5341  * xmlXPathWrapCString:
5342  * @val:  the char * value
5343  *
5344  * Wraps a string into an XPath object.
5345  *
5346  * Returns the newly created object.
5347  */
5348 xmlXPathObjectPtr
5349 xmlXPathWrapCString (char * val) {
5350     return(xmlXPathWrapString((xmlChar *)(val)));
5351 }
5352
5353 /**
5354  * xmlXPathWrapExternal:
5355  * @val:  the user data
5356  *
5357  * Wraps the @val data into an XPath object.
5358  *
5359  * Returns the newly created object.
5360  */
5361 xmlXPathObjectPtr
5362 xmlXPathWrapExternal (void *val) {
5363     xmlXPathObjectPtr ret;
5364
5365     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5366     if (ret == NULL) {
5367         xmlXPathErrMemory(NULL, "creating user object\n");
5368         return(NULL);
5369     }
5370     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5371     ret->type = XPATH_USERS;
5372     ret->user = val;
5373 #ifdef XP_DEBUG_OBJ_USAGE
5374     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5375 #endif
5376     return(ret);
5377 }
5378
5379 /**
5380  * xmlXPathObjectCopy:
5381  * @val:  the original object
5382  *
5383  * allocate a new copy of a given object
5384  *
5385  * Returns the newly created object.
5386  */
5387 xmlXPathObjectPtr
5388 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5389     xmlXPathObjectPtr ret;
5390
5391     if (val == NULL)
5392         return(NULL);
5393
5394     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5395     if (ret == NULL) {
5396         xmlXPathErrMemory(NULL, "copying object\n");
5397         return(NULL);
5398     }
5399     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5400 #ifdef XP_DEBUG_OBJ_USAGE
5401     xmlXPathDebugObjUsageRequested(NULL, val->type);
5402 #endif
5403     switch (val->type) {
5404         case XPATH_BOOLEAN:
5405         case XPATH_NUMBER:
5406         case XPATH_POINT:
5407         case XPATH_RANGE:
5408             break;
5409         case XPATH_STRING:
5410             ret->stringval = xmlStrdup(val->stringval);
5411             break;
5412         case XPATH_XSLT_TREE:
5413 #if 0
5414 /*
5415   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5416   this previous handling is no longer correct, and can cause some serious
5417   problems (ref. bug 145547)
5418 */
5419             if ((val->nodesetval != NULL) &&
5420                 (val->nodesetval->nodeTab != NULL)) {
5421                 xmlNodePtr cur, tmp;
5422                 xmlDocPtr top;
5423
5424                 ret->boolval = 1;
5425                 top =  xmlNewDoc(NULL);
5426                 top->name = (char *)
5427                     xmlStrdup(val->nodesetval->nodeTab[0]->name);
5428                 ret->user = top;
5429                 if (top != NULL) {
5430                     top->doc = top;
5431                     cur = val->nodesetval->nodeTab[0]->children;
5432                     while (cur != NULL) {
5433                         tmp = xmlDocCopyNode(cur, top, 1);
5434                         xmlAddChild((xmlNodePtr) top, tmp);
5435                         cur = cur->next;
5436                     }
5437                 }
5438
5439                 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5440             } else
5441                 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5442             /* Deallocate the copied tree value */
5443             break;
5444 #endif
5445         case XPATH_NODESET:
5446             ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5447             /* Do not deallocate the copied tree value */
5448             ret->boolval = 0;
5449             break;
5450         case XPATH_LOCATIONSET:
5451 #ifdef LIBXML_XPTR_ENABLED
5452         {
5453             xmlLocationSetPtr loc = val->user;
5454             ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5455             break;
5456         }
5457 #endif
5458         case XPATH_USERS:
5459             ret->user = val->user;
5460             break;
5461         case XPATH_UNDEFINED:
5462             xmlGenericError(xmlGenericErrorContext,
5463                     "xmlXPathObjectCopy: unsupported type %d\n",
5464                     val->type);
5465             break;
5466     }
5467     return(ret);
5468 }
5469
5470 /**
5471  * xmlXPathFreeObject:
5472  * @obj:  the object to free
5473  *
5474  * Free up an xmlXPathObjectPtr object.
5475  */
5476 void
5477 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5478     if (obj == NULL) return;
5479     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5480         if (obj->boolval) {
5481 #if 0
5482             if (obj->user != NULL) {
5483                 xmlXPathFreeNodeSet(obj->nodesetval);
5484                 xmlFreeNodeList((xmlNodePtr) obj->user);
5485             } else
5486 #endif
5487             obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5488             if (obj->nodesetval != NULL)
5489                 xmlXPathFreeValueTree(obj->nodesetval);
5490         } else {
5491             if (obj->nodesetval != NULL)
5492                 xmlXPathFreeNodeSet(obj->nodesetval);
5493         }
5494 #ifdef LIBXML_XPTR_ENABLED
5495     } else if (obj->type == XPATH_LOCATIONSET) {
5496         if (obj->user != NULL)
5497             xmlXPtrFreeLocationSet(obj->user);
5498 #endif
5499     } else if (obj->type == XPATH_STRING) {
5500         if (obj->stringval != NULL)
5501             xmlFree(obj->stringval);
5502     }
5503 #ifdef XP_DEBUG_OBJ_USAGE
5504     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5505 #endif
5506     xmlFree(obj);
5507 }
5508
5509 /**
5510  * xmlXPathReleaseObject:
5511  * @obj:  the xmlXPathObjectPtr to free or to cache
5512  *
5513  * Depending on the state of the cache this frees the given
5514  * XPath object or stores it in the cache.
5515  */
5516 static void
5517 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5518 {
5519 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5520         sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5521     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5522
5523 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5524
5525     if (obj == NULL)
5526         return;
5527     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5528          xmlXPathFreeObject(obj);
5529     } else {
5530         xmlXPathContextCachePtr cache =
5531             (xmlXPathContextCachePtr) ctxt->cache;
5532
5533         switch (obj->type) {
5534             case XPATH_NODESET:
5535             case XPATH_XSLT_TREE:
5536                 if (obj->nodesetval != NULL) {
5537                     if (obj->boolval) {
5538                         /*
5539                         * It looks like the @boolval is used for
5540                         * evaluation if this an XSLT Result Tree Fragment.
5541                         * TODO: Check if this assumption is correct.
5542                         */
5543                         obj->type = XPATH_XSLT_TREE; /* just for debugging */
5544                         xmlXPathFreeValueTree(obj->nodesetval);
5545                         obj->nodesetval = NULL;
5546                     } else if ((obj->nodesetval->nodeMax <= 40) &&
5547                         (XP_CACHE_WANTS(cache->nodesetObjs,
5548                                         cache->maxNodeset)))
5549                     {
5550                         XP_CACHE_ADD(cache->nodesetObjs, obj);
5551                         goto obj_cached;
5552                     } else {
5553                         xmlXPathFreeNodeSet(obj->nodesetval);
5554                         obj->nodesetval = NULL;
5555                     }
5556                 }
5557                 break;
5558             case XPATH_STRING:
5559                 if (obj->stringval != NULL)
5560                     xmlFree(obj->stringval);
5561
5562                 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5563                     XP_CACHE_ADD(cache->stringObjs, obj);
5564                     goto obj_cached;
5565                 }
5566                 break;
5567             case XPATH_BOOLEAN:
5568                 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5569                     XP_CACHE_ADD(cache->booleanObjs, obj);
5570                     goto obj_cached;
5571                 }
5572                 break;
5573             case XPATH_NUMBER:
5574                 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5575                     XP_CACHE_ADD(cache->numberObjs, obj);
5576                     goto obj_cached;
5577                 }
5578                 break;
5579 #ifdef LIBXML_XPTR_ENABLED
5580             case XPATH_LOCATIONSET:
5581                 if (obj->user != NULL) {
5582                     xmlXPtrFreeLocationSet(obj->user);
5583                 }
5584                 goto free_obj;
5585 #endif
5586             default:
5587                 goto free_obj;
5588         }
5589
5590         /*
5591         * Fallback to adding to the misc-objects slot.
5592         */
5593         if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5594             XP_CACHE_ADD(cache->miscObjs, obj);
5595         } else
5596             goto free_obj;
5597
5598 obj_cached:
5599
5600 #ifdef XP_DEBUG_OBJ_USAGE
5601         xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5602 #endif
5603
5604         if (obj->nodesetval != NULL) {
5605             xmlNodeSetPtr tmpset = obj->nodesetval;
5606
5607             /*
5608             * TODO: Due to those nasty ns-nodes, we need to traverse
5609             *  the list and free the ns-nodes.
5610             * URGENT TODO: Check if it's actually slowing things down.
5611             *  Maybe we shouldn't try to preserve the list.
5612             */
5613             if (tmpset->nodeNr > 1) {
5614                 int i;
5615                 xmlNodePtr node;
5616
5617                 for (i = 0; i < tmpset->nodeNr; i++) {
5618                     node = tmpset->nodeTab[i];
5619                     if ((node != NULL) &&
5620                         (node->type == XML_NAMESPACE_DECL))
5621                     {
5622                         xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5623                     }
5624                 }
5625             } else if (tmpset->nodeNr == 1) {
5626                 if ((tmpset->nodeTab[0] != NULL) &&
5627                     (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5628                     xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5629             }
5630             tmpset->nodeNr = 0;
5631             memset(obj, 0, sizeof(xmlXPathObject));
5632             obj->nodesetval = tmpset;
5633         } else
5634             memset(obj, 0, sizeof(xmlXPathObject));
5635
5636         return;
5637
5638 free_obj:
5639         /*
5640         * Cache is full; free the object.
5641         */
5642         if (obj->nodesetval != NULL)
5643             xmlXPathFreeNodeSet(obj->nodesetval);
5644 #ifdef XP_DEBUG_OBJ_USAGE
5645         xmlXPathDebugObjUsageReleased(NULL, obj->type);
5646 #endif
5647         xmlFree(obj);
5648     }
5649     return;
5650 }
5651
5652
5653 /************************************************************************
5654  *                                                                      *
5655  *                      Type Casting Routines                           *
5656  *                                                                      *
5657  ************************************************************************/
5658
5659 /**
5660  * xmlXPathCastBooleanToString:
5661  * @val:  a boolean
5662  *
5663  * Converts a boolean to its string value.
5664  *
5665  * Returns a newly allocated string.
5666  */
5667 xmlChar *
5668 xmlXPathCastBooleanToString (int val) {
5669     xmlChar *ret;
5670     if (val)
5671         ret = xmlStrdup((const xmlChar *) "true");
5672     else
5673         ret = xmlStrdup((const xmlChar *) "false");
5674     return(ret);
5675 }
5676
5677 /**
5678  * xmlXPathCastNumberToString:
5679  * @val:  a number
5680  *
5681  * Converts a number to its string value.
5682  *
5683  * Returns a newly allocated string.
5684  */
5685 xmlChar *
5686 xmlXPathCastNumberToString (double val) {
5687     xmlChar *ret;
5688     switch (xmlXPathIsInf(val)) {
5689     case 1:
5690         ret = xmlStrdup((const xmlChar *) "Infinity");
5691         break;
5692     case -1:
5693         ret = xmlStrdup((const xmlChar *) "-Infinity");
5694         break;
5695     default:
5696         if (xmlXPathIsNaN(val)) {
5697             ret = xmlStrdup((const xmlChar *) "NaN");
5698         } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5699             ret = xmlStrdup((const xmlChar *) "0");
5700         } else {
5701             /* could be improved */
5702             char buf[100];
5703             xmlXPathFormatNumber(val, buf, 99);
5704             buf[99] = 0;
5705             ret = xmlStrdup((const xmlChar *) buf);
5706         }
5707     }
5708     return(ret);
5709 }
5710
5711 /**
5712  * xmlXPathCastNodeToString:
5713  * @node:  a node
5714  *
5715  * Converts a node to its string value.
5716  *
5717  * Returns a newly allocated string.
5718  */
5719 xmlChar *
5720 xmlXPathCastNodeToString (xmlNodePtr node) {
5721 xmlChar *ret;
5722     if ((ret = xmlNodeGetContent(node)) == NULL)
5723         ret = xmlStrdup((const xmlChar *) "");
5724     return(ret);
5725 }
5726
5727 /**
5728  * xmlXPathCastNodeSetToString:
5729  * @ns:  a node-set
5730  *
5731  * Converts a node-set to its string value.
5732  *
5733  * Returns a newly allocated string.
5734  */
5735 xmlChar *
5736 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5737     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5738         return(xmlStrdup((const xmlChar *) ""));
5739
5740     if (ns->nodeNr > 1)
5741         xmlXPathNodeSetSort(ns);
5742     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5743 }
5744
5745 /**
5746  * xmlXPathCastToString:
5747  * @val:  an XPath object
5748  *
5749  * Converts an existing object to its string() equivalent
5750  *
5751  * Returns the allocated string value of the object, NULL in case of error.
5752  *         It's up to the caller to free the string memory with xmlFree().
5753  */
5754 xmlChar *
5755 xmlXPathCastToString(xmlXPathObjectPtr val) {
5756     xmlChar *ret = NULL;
5757
5758     if (val == NULL)
5759         return(xmlStrdup((const xmlChar *) ""));
5760     switch (val->type) {
5761         case XPATH_UNDEFINED:
5762 #ifdef DEBUG_EXPR
5763             xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5764 #endif
5765             ret = xmlStrdup((const xmlChar *) "");
5766             break;
5767         case XPATH_NODESET:
5768         case XPATH_XSLT_TREE:
5769             ret = xmlXPathCastNodeSetToString(val->nodesetval);
5770             break;
5771         case XPATH_STRING:
5772             return(xmlStrdup(val->stringval));
5773         case XPATH_BOOLEAN:
5774             ret = xmlXPathCastBooleanToString(val->boolval);
5775             break;
5776         case XPATH_NUMBER: {
5777             ret = xmlXPathCastNumberToString(val->floatval);
5778             break;
5779         }
5780         case XPATH_USERS:
5781         case XPATH_POINT:
5782         case XPATH_RANGE:
5783         case XPATH_LOCATIONSET:
5784             TODO
5785             ret = xmlStrdup((const xmlChar *) "");
5786             break;
5787     }
5788     return(ret);
5789 }
5790
5791 /**
5792  * xmlXPathConvertString:
5793  * @val:  an XPath object
5794  *
5795  * Converts an existing object to its string() equivalent
5796  *
5797  * Returns the new object, the old one is freed (or the operation
5798  *         is done directly on @val)
5799  */
5800 xmlXPathObjectPtr
5801 xmlXPathConvertString(xmlXPathObjectPtr val) {
5802     xmlChar *res = NULL;
5803
5804     if (val == NULL)
5805         return(xmlXPathNewCString(""));
5806
5807     switch (val->type) {
5808     case XPATH_UNDEFINED:
5809 #ifdef DEBUG_EXPR
5810         xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5811 #endif
5812         break;
5813     case XPATH_NODESET:
5814     case XPATH_XSLT_TREE:
5815         res = xmlXPathCastNodeSetToString(val->nodesetval);
5816         break;
5817     case XPATH_STRING:
5818         return(val);
5819     case XPATH_BOOLEAN:
5820         res = xmlXPathCastBooleanToString(val->boolval);
5821         break;
5822     case XPATH_NUMBER:
5823         res = xmlXPathCastNumberToString(val->floatval);
5824         break;
5825     case XPATH_USERS:
5826     case XPATH_POINT:
5827     case XPATH_RANGE:
5828     case XPATH_LOCATIONSET:
5829         TODO;
5830         break;
5831     }
5832     xmlXPathFreeObject(val);
5833     if (res == NULL)
5834         return(xmlXPathNewCString(""));
5835     return(xmlXPathWrapString(res));
5836 }
5837
5838 /**
5839  * xmlXPathCastBooleanToNumber:
5840  * @val:  a boolean
5841  *
5842  * Converts a boolean to its number value
5843  *
5844  * Returns the number value
5845  */
5846 double
5847 xmlXPathCastBooleanToNumber(int val) {
5848     if (val)
5849         return(1.0);
5850     return(0.0);
5851 }
5852
5853 /**
5854  * xmlXPathCastStringToNumber:
5855  * @val:  a string
5856  *
5857  * Converts a string to its number value
5858  *
5859  * Returns the number value
5860  */
5861 double
5862 xmlXPathCastStringToNumber(const xmlChar * val) {
5863     return(xmlXPathStringEvalNumber(val));
5864 }
5865
5866 /**
5867  * xmlXPathCastNodeToNumber:
5868  * @node:  a node
5869  *
5870  * Converts a node to its number value
5871  *
5872  * Returns the number value
5873  */
5874 double
5875 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5876     xmlChar *strval;
5877     double ret;
5878
5879     if (node == NULL)
5880         return(xmlXPathNAN);
5881     strval = xmlXPathCastNodeToString(node);
5882     if (strval == NULL)
5883         return(xmlXPathNAN);
5884     ret = xmlXPathCastStringToNumber(strval);
5885     xmlFree(strval);
5886
5887     return(ret);
5888 }
5889
5890 /**
5891  * xmlXPathCastNodeSetToNumber:
5892  * @ns:  a node-set
5893  *
5894  * Converts a node-set to its number value
5895  *
5896  * Returns the number value
5897  */
5898 double
5899 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5900     xmlChar *str;
5901     double ret;
5902
5903     if (ns == NULL)
5904         return(xmlXPathNAN);
5905     str = xmlXPathCastNodeSetToString(ns);
5906     ret = xmlXPathCastStringToNumber(str);
5907     xmlFree(str);
5908     return(ret);
5909 }
5910
5911 /**
5912  * xmlXPathCastToNumber:
5913  * @val:  an XPath object
5914  *
5915  * Converts an XPath object to its number value
5916  *
5917  * Returns the number value
5918  */
5919 double
5920 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5921     double ret = 0.0;
5922
5923     if (val == NULL)
5924         return(xmlXPathNAN);
5925     switch (val->type) {
5926     case XPATH_UNDEFINED:
5927 #ifdef DEGUB_EXPR
5928         xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5929 #endif
5930         ret = xmlXPathNAN;
5931         break;
5932     case XPATH_NODESET:
5933     case XPATH_XSLT_TREE:
5934         ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5935         break;
5936     case XPATH_STRING:
5937         ret = xmlXPathCastStringToNumber(val->stringval);
5938         break;
5939     case XPATH_NUMBER:
5940         ret = val->floatval;
5941         break;
5942     case XPATH_BOOLEAN:
5943         ret = xmlXPathCastBooleanToNumber(val->boolval);
5944         break;
5945     case XPATH_USERS:
5946     case XPATH_POINT:
5947     case XPATH_RANGE:
5948     case XPATH_LOCATIONSET:
5949         TODO;
5950         ret = xmlXPathNAN;
5951         break;
5952     }
5953     return(ret);
5954 }
5955
5956 /**
5957  * xmlXPathConvertNumber:
5958  * @val:  an XPath object
5959  *
5960  * Converts an existing object to its number() equivalent
5961  *
5962  * Returns the new object, the old one is freed (or the operation
5963  *         is done directly on @val)
5964  */
5965 xmlXPathObjectPtr
5966 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5967     xmlXPathObjectPtr ret;
5968
5969     if (val == NULL)
5970         return(xmlXPathNewFloat(0.0));
5971     if (val->type == XPATH_NUMBER)
5972         return(val);
5973     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5974     xmlXPathFreeObject(val);
5975     return(ret);
5976 }
5977
5978 /**
5979  * xmlXPathCastNumberToBoolean:
5980  * @val:  a number
5981  *
5982  * Converts a number to its boolean value
5983  *
5984  * Returns the boolean value
5985  */
5986 int
5987 xmlXPathCastNumberToBoolean (double val) {
5988      if (xmlXPathIsNaN(val) || (val == 0.0))
5989          return(0);
5990      return(1);
5991 }
5992
5993 /**
5994  * xmlXPathCastStringToBoolean:
5995  * @val:  a string
5996  *
5997  * Converts a string to its boolean value
5998  *
5999  * Returns the boolean value
6000  */
6001 int
6002 xmlXPathCastStringToBoolean (const xmlChar *val) {
6003     if ((val == NULL) || (xmlStrlen(val) == 0))
6004         return(0);
6005     return(1);
6006 }
6007
6008 /**
6009  * xmlXPathCastNodeSetToBoolean:
6010  * @ns:  a node-set
6011  *
6012  * Converts a node-set to its boolean value
6013  *
6014  * Returns the boolean value
6015  */
6016 int
6017 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6018     if ((ns == NULL) || (ns->nodeNr == 0))
6019         return(0);
6020     return(1);
6021 }
6022
6023 /**
6024  * xmlXPathCastToBoolean:
6025  * @val:  an XPath object
6026  *
6027  * Converts an XPath object to its boolean value
6028  *
6029  * Returns the boolean value
6030  */
6031 int
6032 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6033     int ret = 0;
6034
6035     if (val == NULL)
6036         return(0);
6037     switch (val->type) {
6038     case XPATH_UNDEFINED:
6039 #ifdef DEBUG_EXPR
6040         xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6041 #endif
6042         ret = 0;
6043         break;
6044     case XPATH_NODESET:
6045     case XPATH_XSLT_TREE:
6046         ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6047         break;
6048     case XPATH_STRING:
6049         ret = xmlXPathCastStringToBoolean(val->stringval);
6050         break;
6051     case XPATH_NUMBER:
6052         ret = xmlXPathCastNumberToBoolean(val->floatval);
6053         break;
6054     case XPATH_BOOLEAN:
6055         ret = val->boolval;
6056         break;
6057     case XPATH_USERS:
6058     case XPATH_POINT:
6059     case XPATH_RANGE:
6060     case XPATH_LOCATIONSET:
6061         TODO;
6062         ret = 0;
6063         break;
6064     }
6065     return(ret);
6066 }
6067
6068
6069 /**
6070  * xmlXPathConvertBoolean:
6071  * @val:  an XPath object
6072  *
6073  * Converts an existing object to its boolean() equivalent
6074  *
6075  * Returns the new object, the old one is freed (or the operation
6076  *         is done directly on @val)
6077  */
6078 xmlXPathObjectPtr
6079 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6080     xmlXPathObjectPtr ret;
6081
6082     if (val == NULL)
6083         return(xmlXPathNewBoolean(0));
6084     if (val->type == XPATH_BOOLEAN)
6085         return(val);
6086     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6087     xmlXPathFreeObject(val);
6088     return(ret);
6089 }
6090
6091 /************************************************************************
6092  *                                                                      *
6093  *              Routines to handle XPath contexts                       *
6094  *                                                                      *
6095  ************************************************************************/
6096
6097 /**
6098  * xmlXPathNewContext:
6099  * @doc:  the XML document
6100  *
6101  * Create a new xmlXPathContext
6102  *
6103  * Returns the xmlXPathContext just allocated. The caller will need to free it.
6104  */
6105 xmlXPathContextPtr
6106 xmlXPathNewContext(xmlDocPtr doc) {
6107     xmlXPathContextPtr ret;
6108
6109     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6110     if (ret == NULL) {
6111         xmlXPathErrMemory(NULL, "creating context\n");
6112         return(NULL);
6113     }
6114     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6115     ret->doc = doc;
6116     ret->node = NULL;
6117
6118     ret->varHash = NULL;
6119
6120     ret->nb_types = 0;
6121     ret->max_types = 0;
6122     ret->types = NULL;
6123
6124     ret->funcHash = xmlHashCreate(0);
6125
6126     ret->nb_axis = 0;
6127     ret->max_axis = 0;
6128     ret->axis = NULL;
6129
6130     ret->nsHash = NULL;
6131     ret->user = NULL;
6132
6133     ret->contextSize = -1;
6134     ret->proximityPosition = -1;
6135
6136 #ifdef XP_DEFAULT_CACHE_ON
6137     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6138         xmlXPathFreeContext(ret);
6139         return(NULL);
6140     }
6141 #endif
6142
6143     xmlXPathRegisterAllFunctions(ret);
6144
6145     return(ret);
6146 }
6147
6148 /**
6149  * xmlXPathFreeContext:
6150  * @ctxt:  the context to free
6151  *
6152  * Free up an xmlXPathContext
6153  */
6154 void
6155 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6156     if (ctxt == NULL) return;
6157
6158     if (ctxt->cache != NULL)
6159         xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6160     xmlXPathRegisteredNsCleanup(ctxt);
6161     xmlXPathRegisteredFuncsCleanup(ctxt);
6162     xmlXPathRegisteredVariablesCleanup(ctxt);
6163     xmlResetError(&ctxt->lastError);
6164     xmlFree(ctxt);
6165 }
6166
6167 /************************************************************************
6168  *                                                                      *
6169  *              Routines to handle XPath parser contexts                *
6170  *                                                                      *
6171  ************************************************************************/
6172
6173 #define CHECK_CTXT(ctxt)                                                \
6174     if (ctxt == NULL) {                                         \
6175         __xmlRaiseError(NULL, NULL, NULL,                               \
6176                 NULL, NULL, XML_FROM_XPATH,                             \
6177                 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6178                 __FILE__, __LINE__,                                     \
6179                 NULL, NULL, NULL, 0, 0,                                 \
6180                 "NULL context pointer\n");                              \
6181         return(NULL);                                                   \
6182     }                                                                   \
6183
6184 #define CHECK_CTXT_NEG(ctxt)                                            \
6185     if (ctxt == NULL) {                                         \
6186         __xmlRaiseError(NULL, NULL, NULL,                               \
6187                 NULL, NULL, XML_FROM_XPATH,                             \
6188                 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6189                 __FILE__, __LINE__,                                     \
6190                 NULL, NULL, NULL, 0, 0,                                 \
6191                 "NULL context pointer\n");                              \
6192         return(-1);                                                     \
6193     }                                                                   \
6194
6195
6196 #define CHECK_CONTEXT(ctxt)                                             \
6197     if ((ctxt == NULL) || (ctxt->doc == NULL) ||                        \
6198         (ctxt->doc->children == NULL)) {                                \
6199         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);    \
6200         return(NULL);                                                   \
6201     }
6202
6203
6204 /**
6205  * xmlXPathNewParserContext:
6206  * @str:  the XPath expression
6207  * @ctxt:  the XPath context
6208  *
6209  * Create a new xmlXPathParserContext
6210  *
6211  * Returns the xmlXPathParserContext just allocated.
6212  */
6213 xmlXPathParserContextPtr
6214 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6215     xmlXPathParserContextPtr ret;
6216
6217     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6218     if (ret == NULL) {
6219         xmlXPathErrMemory(ctxt, "creating parser context\n");
6220         return(NULL);
6221     }
6222     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6223     ret->cur = ret->base = str;
6224     ret->context = ctxt;
6225
6226     ret->comp = xmlXPathNewCompExpr();
6227     if (ret->comp == NULL) {
6228         xmlFree(ret->valueTab);
6229         xmlFree(ret);
6230         return(NULL);
6231     }
6232     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6233         ret->comp->dict = ctxt->dict;
6234         xmlDictReference(ret->comp->dict);
6235     }
6236
6237     return(ret);
6238 }
6239
6240 /**
6241  * xmlXPathCompParserContext:
6242  * @comp:  the XPath compiled expression
6243  * @ctxt:  the XPath context
6244  *
6245  * Create a new xmlXPathParserContext when processing a compiled expression
6246  *
6247  * Returns the xmlXPathParserContext just allocated.
6248  */
6249 static xmlXPathParserContextPtr
6250 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6251     xmlXPathParserContextPtr ret;
6252
6253     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6254     if (ret == NULL) {
6255         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6256         return(NULL);
6257     }
6258     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6259
6260     /* Allocate the value stack */
6261     ret->valueTab = (xmlXPathObjectPtr *)
6262                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6263     if (ret->valueTab == NULL) {
6264         xmlFree(ret);
6265         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6266         return(NULL);
6267     }
6268     ret->valueNr = 0;
6269     ret->valueMax = 10;
6270     ret->value = NULL;
6271     ret->valueFrame = 0;
6272
6273     ret->context = ctxt;
6274     ret->comp = comp;
6275
6276     return(ret);
6277 }
6278
6279 /**
6280  * xmlXPathFreeParserContext:
6281  * @ctxt:  the context to free
6282  *
6283  * Free up an xmlXPathParserContext
6284  */
6285 void
6286 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6287     if (ctxt->valueTab != NULL) {
6288         xmlFree(ctxt->valueTab);
6289     }
6290     if (ctxt->comp != NULL) {
6291 #ifdef XPATH_STREAMING
6292         if (ctxt->comp->stream != NULL) {
6293             xmlFreePatternList(ctxt->comp->stream);
6294             ctxt->comp->stream = NULL;
6295         }
6296 #endif
6297         xmlXPathFreeCompExpr(ctxt->comp);
6298     }
6299     xmlFree(ctxt);
6300 }
6301
6302 /************************************************************************
6303  *                                                                      *
6304  *              The implicit core function library                      *
6305  *                                                                      *
6306  ************************************************************************/
6307
6308 /**
6309  * xmlXPathNodeValHash:
6310  * @node:  a node pointer
6311  *
6312  * Function computing the beginning of the string value of the node,
6313  * used to speed up comparisons
6314  *
6315  * Returns an int usable as a hash
6316  */
6317 static unsigned int
6318 xmlXPathNodeValHash(xmlNodePtr node) {
6319     int len = 2;
6320     const xmlChar * string = NULL;
6321     xmlNodePtr tmp = NULL;
6322     unsigned int ret = 0;
6323
6324     if (node == NULL)
6325         return(0);
6326
6327     if (node->type == XML_DOCUMENT_NODE) {
6328         tmp = xmlDocGetRootElement((xmlDocPtr) node);
6329         if (tmp == NULL)
6330             node = node->children;
6331         else
6332             node = tmp;
6333
6334         if (node == NULL)
6335             return(0);
6336     }
6337
6338     switch (node->type) {
6339         case XML_COMMENT_NODE:
6340         case XML_PI_NODE:
6341         case XML_CDATA_SECTION_NODE:
6342         case XML_TEXT_NODE:
6343             string = node->content;
6344             if (string == NULL)
6345                 return(0);
6346             if (string[0] == 0)
6347                 return(0);
6348             return(((unsigned int) string[0]) +
6349                    (((unsigned int) string[1]) << 8));
6350         case XML_NAMESPACE_DECL:
6351             string = ((xmlNsPtr)node)->href;
6352             if (string == NULL)
6353                 return(0);
6354             if (string[0] == 0)
6355                 return(0);
6356             return(((unsigned int) string[0]) +
6357                    (((unsigned int) string[1]) << 8));
6358         case XML_ATTRIBUTE_NODE:
6359             tmp = ((xmlAttrPtr) node)->children;
6360             break;
6361         case XML_ELEMENT_NODE:
6362             tmp = node->children;
6363             break;
6364         default:
6365             return(0);
6366     }
6367     while (tmp != NULL) {
6368         switch (tmp->type) {
6369             case XML_COMMENT_NODE:
6370             case XML_PI_NODE:
6371             case XML_CDATA_SECTION_NODE:
6372             case XML_TEXT_NODE:
6373                 string = tmp->content;
6374                 break;
6375             case XML_NAMESPACE_DECL:
6376                 string = ((xmlNsPtr)tmp)->href;
6377                 break;
6378             default:
6379                 break;
6380         }
6381         if ((string != NULL) && (string[0] != 0)) {
6382             if (len == 1) {
6383                 return(ret + (((unsigned int) string[0]) << 8));
6384             }
6385             if (string[1] == 0) {
6386                 len = 1;
6387                 ret = (unsigned int) string[0];
6388             } else {
6389                 return(((unsigned int) string[0]) +
6390                        (((unsigned int) string[1]) << 8));
6391             }
6392         }
6393         /*
6394          * Skip to next node
6395          */
6396         if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6397             if (tmp->children->type != XML_ENTITY_DECL) {
6398                 tmp = tmp->children;
6399                 continue;
6400             }
6401         }
6402         if (tmp == node)
6403             break;
6404
6405         if (tmp->next != NULL) {
6406             tmp = tmp->next;
6407             continue;
6408         }
6409
6410         do {
6411             tmp = tmp->parent;
6412             if (tmp == NULL)
6413                 break;
6414             if (tmp == node) {
6415                 tmp = NULL;
6416                 break;
6417             }
6418             if (tmp->next != NULL) {
6419                 tmp = tmp->next;
6420                 break;
6421             }
6422         } while (tmp != NULL);
6423     }
6424     return(ret);
6425 }
6426
6427 /**
6428  * xmlXPathStringHash:
6429  * @string:  a string
6430  *
6431  * Function computing the beginning of the string value of the node,
6432  * used to speed up comparisons
6433  *
6434  * Returns an int usable as a hash
6435  */
6436 static unsigned int
6437 xmlXPathStringHash(const xmlChar * string) {
6438     if (string == NULL)
6439         return((unsigned int) 0);
6440     if (string[0] == 0)
6441         return(0);
6442     return(((unsigned int) string[0]) +
6443            (((unsigned int) string[1]) << 8));
6444 }
6445
6446 /**
6447  * xmlXPathCompareNodeSetFloat:
6448  * @ctxt:  the XPath Parser context
6449  * @inf:  less than (1) or greater than (0)
6450  * @strict:  is the comparison strict
6451  * @arg:  the node set
6452  * @f:  the value
6453  *
6454  * Implement the compare operation between a nodeset and a number
6455  *     @ns < @val    (1, 1, ...
6456  *     @ns <= @val   (1, 0, ...
6457  *     @ns > @val    (0, 1, ...
6458  *     @ns >= @val   (0, 0, ...
6459  *
6460  * If one object to be compared is a node-set and the other is a number,
6461  * then the comparison will be true if and only if there is a node in the
6462  * node-set such that the result of performing the comparison on the number
6463  * to be compared and on the result of converting the string-value of that
6464  * node to a number using the number function is true.
6465  *
6466  * Returns 0 or 1 depending on the results of the test.
6467  */
6468 static int
6469 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6470                             xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6471     int i, ret = 0;
6472     xmlNodeSetPtr ns;
6473     xmlChar *str2;
6474
6475     if ((f == NULL) || (arg == NULL) ||
6476         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6477         xmlXPathReleaseObject(ctxt->context, arg);
6478         xmlXPathReleaseObject(ctxt->context, f);
6479         return(0);
6480     }
6481     ns = arg->nodesetval;
6482     if (ns != NULL) {
6483         for (i = 0;i < ns->nodeNr;i++) {
6484              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6485              if (str2 != NULL) {
6486                  valuePush(ctxt,
6487                            xmlXPathCacheNewString(ctxt->context, str2));
6488                  xmlFree(str2);
6489                  xmlXPathNumberFunction(ctxt, 1);
6490                  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6491                  ret = xmlXPathCompareValues(ctxt, inf, strict);
6492                  if (ret)
6493                      break;
6494              }
6495         }
6496     }
6497     xmlXPathReleaseObject(ctxt->context, arg);
6498     xmlXPathReleaseObject(ctxt->context, f);
6499     return(ret);
6500 }
6501
6502 /**
6503  * xmlXPathCompareNodeSetString:
6504  * @ctxt:  the XPath Parser context
6505  * @inf:  less than (1) or greater than (0)
6506  * @strict:  is the comparison strict
6507  * @arg:  the node set
6508  * @s:  the value
6509  *
6510  * Implement the compare operation between a nodeset and a string
6511  *     @ns < @val    (1, 1, ...
6512  *     @ns <= @val   (1, 0, ...
6513  *     @ns > @val    (0, 1, ...
6514  *     @ns >= @val   (0, 0, ...
6515  *
6516  * If one object to be compared is a node-set and the other is a string,
6517  * then the comparison will be true if and only if there is a node in
6518  * the node-set such that the result of performing the comparison on the
6519  * string-value of the node and the other string is true.
6520  *
6521  * Returns 0 or 1 depending on the results of the test.
6522  */
6523 static int
6524 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6525                             xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6526     int i, ret = 0;
6527     xmlNodeSetPtr ns;
6528     xmlChar *str2;
6529
6530     if ((s == NULL) || (arg == NULL) ||
6531         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6532         xmlXPathReleaseObject(ctxt->context, arg);
6533         xmlXPathReleaseObject(ctxt->context, s);
6534         return(0);
6535     }
6536     ns = arg->nodesetval;
6537     if (ns != NULL) {
6538         for (i = 0;i < ns->nodeNr;i++) {
6539              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6540              if (str2 != NULL) {
6541                  valuePush(ctxt,
6542                            xmlXPathCacheNewString(ctxt->context, str2));
6543                  xmlFree(str2);
6544                  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6545                  ret = xmlXPathCompareValues(ctxt, inf, strict);
6546                  if (ret)
6547                      break;
6548              }
6549         }
6550     }
6551     xmlXPathReleaseObject(ctxt->context, arg);
6552     xmlXPathReleaseObject(ctxt->context, s);
6553     return(ret);
6554 }
6555
6556 /**
6557  * xmlXPathCompareNodeSets:
6558  * @inf:  less than (1) or greater than (0)
6559  * @strict:  is the comparison strict
6560  * @arg1:  the first node set object
6561  * @arg2:  the second node set object
6562  *
6563  * Implement the compare operation on nodesets:
6564  *
6565  * If both objects to be compared are node-sets, then the comparison
6566  * will be true if and only if there is a node in the first node-set
6567  * and a node in the second node-set such that the result of performing
6568  * the comparison on the string-values of the two nodes is true.
6569  * ....
6570  * When neither object to be compared is a node-set and the operator
6571  * is <=, <, >= or >, then the objects are compared by converting both
6572  * objects to numbers and comparing the numbers according to IEEE 754.
6573  * ....
6574  * The number function converts its argument to a number as follows:
6575  *  - a string that consists of optional whitespace followed by an
6576  *    optional minus sign followed by a Number followed by whitespace
6577  *    is converted to the IEEE 754 number that is nearest (according
6578  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6579  *    represented by the string; any other string is converted to NaN
6580  *
6581  * Conclusion all nodes need to be converted first to their string value
6582  * and then the comparison must be done when possible
6583  */
6584 static int
6585 xmlXPathCompareNodeSets(int inf, int strict,
6586                         xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6587     int i, j, init = 0;
6588     double val1;
6589     double *values2;
6590     int ret = 0;
6591     xmlNodeSetPtr ns1;
6592     xmlNodeSetPtr ns2;
6593
6594     if ((arg1 == NULL) ||
6595         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6596         xmlXPathFreeObject(arg2);
6597         return(0);
6598     }
6599     if ((arg2 == NULL) ||
6600         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6601         xmlXPathFreeObject(arg1);
6602         xmlXPathFreeObject(arg2);
6603         return(0);
6604     }
6605
6606     ns1 = arg1->nodesetval;
6607     ns2 = arg2->nodesetval;
6608
6609     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6610         xmlXPathFreeObject(arg1);
6611         xmlXPathFreeObject(arg2);
6612         return(0);
6613     }
6614     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6615         xmlXPathFreeObject(arg1);
6616         xmlXPathFreeObject(arg2);
6617         return(0);
6618     }
6619
6620     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6621     if (values2 == NULL) {
6622         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6623         xmlXPathFreeObject(arg1);
6624         xmlXPathFreeObject(arg2);
6625         return(0);
6626     }
6627     for (i = 0;i < ns1->nodeNr;i++) {
6628         val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6629         if (xmlXPathIsNaN(val1))
6630             continue;
6631         for (j = 0;j < ns2->nodeNr;j++) {
6632             if (init == 0) {
6633                 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6634             }
6635             if (xmlXPathIsNaN(values2[j]))
6636                 continue;
6637             if (inf && strict)
6638                 ret = (val1 < values2[j]);
6639             else if (inf && !strict)
6640                 ret = (val1 <= values2[j]);
6641             else if (!inf && strict)
6642                 ret = (val1 > values2[j]);
6643             else if (!inf && !strict)
6644                 ret = (val1 >= values2[j]);
6645             if (ret)
6646                 break;
6647         }
6648         if (ret)
6649             break;
6650         init = 1;
6651     }
6652     xmlFree(values2);
6653     xmlXPathFreeObject(arg1);
6654     xmlXPathFreeObject(arg2);
6655     return(ret);
6656 }
6657
6658 /**
6659  * xmlXPathCompareNodeSetValue:
6660  * @ctxt:  the XPath Parser context
6661  * @inf:  less than (1) or greater than (0)
6662  * @strict:  is the comparison strict
6663  * @arg:  the node set
6664  * @val:  the value
6665  *
6666  * Implement the compare operation between a nodeset and a value
6667  *     @ns < @val    (1, 1, ...
6668  *     @ns <= @val   (1, 0, ...
6669  *     @ns > @val    (0, 1, ...
6670  *     @ns >= @val   (0, 0, ...
6671  *
6672  * If one object to be compared is a node-set and the other is a boolean,
6673  * then the comparison will be true if and only if the result of performing
6674  * the comparison on the boolean and on the result of converting
6675  * the node-set to a boolean using the boolean function is true.
6676  *
6677  * Returns 0 or 1 depending on the results of the test.
6678  */
6679 static int
6680 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6681                             xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6682     if ((val == NULL) || (arg == NULL) ||
6683         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6684         return(0);
6685
6686     switch(val->type) {
6687         case XPATH_NUMBER:
6688             return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6689         case XPATH_NODESET:
6690         case XPATH_XSLT_TREE:
6691             return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6692         case XPATH_STRING:
6693             return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6694         case XPATH_BOOLEAN:
6695             valuePush(ctxt, arg);
6696             xmlXPathBooleanFunction(ctxt, 1);
6697             valuePush(ctxt, val);
6698             return(xmlXPathCompareValues(ctxt, inf, strict));
6699         default:
6700             TODO
6701     }
6702     return(0);
6703 }
6704
6705 /**
6706  * xmlXPathEqualNodeSetString:
6707  * @arg:  the nodeset object argument
6708  * @str:  the string to compare to.
6709  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6710  *
6711  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6712  * If one object to be compared is a node-set and the other is a string,
6713  * then the comparison will be true if and only if there is a node in
6714  * the node-set such that the result of performing the comparison on the
6715  * string-value of the node and the other string is true.
6716  *
6717  * Returns 0 or 1 depending on the results of the test.
6718  */
6719 static int
6720 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6721 {
6722     int i;
6723     xmlNodeSetPtr ns;
6724     xmlChar *str2;
6725     unsigned int hash;
6726
6727     if ((str == NULL) || (arg == NULL) ||
6728         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6729         return (0);
6730     ns = arg->nodesetval;
6731     /*
6732      * A NULL nodeset compared with a string is always false
6733      * (since there is no node equal, and no node not equal)
6734      */
6735     if ((ns == NULL) || (ns->nodeNr <= 0) )
6736         return (0);
6737     hash = xmlXPathStringHash(str);
6738     for (i = 0; i < ns->nodeNr; i++) {
6739         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6740             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6741             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6742                 xmlFree(str2);
6743                 if (neq)
6744                     continue;
6745                 return (1);
6746             } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6747                 if (neq)
6748                     continue;
6749                 return (1);
6750             } else if (neq) {
6751                 if (str2 != NULL)
6752                     xmlFree(str2);
6753                 return (1);
6754             }
6755             if (str2 != NULL)
6756                 xmlFree(str2);
6757         } else if (neq)
6758             return (1);
6759     }
6760     return (0);
6761 }
6762
6763 /**
6764  * xmlXPathEqualNodeSetFloat:
6765  * @arg:  the nodeset object argument
6766  * @f:  the float to compare to
6767  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6768  *
6769  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6770  * If one object to be compared is a node-set and the other is a number,
6771  * then the comparison will be true if and only if there is a node in
6772  * the node-set such that the result of performing the comparison on the
6773  * number to be compared and on the result of converting the string-value
6774  * of that node to a number using the number function is true.
6775  *
6776  * Returns 0 or 1 depending on the results of the test.
6777  */
6778 static int
6779 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6780     xmlXPathObjectPtr arg, double f, int neq) {
6781   int i, ret=0;
6782   xmlNodeSetPtr ns;
6783   xmlChar *str2;
6784   xmlXPathObjectPtr val;
6785   double v;
6786
6787     if ((arg == NULL) ||
6788         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6789         return(0);
6790
6791     ns = arg->nodesetval;
6792     if (ns != NULL) {
6793         for (i=0;i<ns->nodeNr;i++) {
6794             str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6795             if (str2 != NULL) {
6796                 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6797                 xmlFree(str2);
6798                 xmlXPathNumberFunction(ctxt, 1);
6799                 val = valuePop(ctxt);
6800                 v = val->floatval;
6801                 xmlXPathReleaseObject(ctxt->context, val);
6802                 if (!xmlXPathIsNaN(v)) {
6803                     if ((!neq) && (v==f)) {
6804                         ret = 1;
6805                         break;
6806                     } else if ((neq) && (v!=f)) {
6807                         ret = 1;
6808                         break;
6809                     }
6810                 } else {        /* NaN is unequal to any value */
6811                     if (neq)
6812                         ret = 1;
6813                 }
6814             }
6815         }
6816     }
6817
6818     return(ret);
6819 }
6820
6821
6822 /**
6823  * xmlXPathEqualNodeSets:
6824  * @arg1:  first nodeset object argument
6825  * @arg2:  second nodeset object argument
6826  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6827  *
6828  * Implement the equal / not equal operation on XPath nodesets:
6829  * @arg1 == @arg2  or  @arg1 != @arg2
6830  * If both objects to be compared are node-sets, then the comparison
6831  * will be true if and only if there is a node in the first node-set and
6832  * a node in the second node-set such that the result of performing the
6833  * comparison on the string-values of the two nodes is true.
6834  *
6835  * (needless to say, this is a costly operation)
6836  *
6837  * Returns 0 or 1 depending on the results of the test.
6838  */
6839 static int
6840 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6841     int i, j;
6842     unsigned int *hashs1;
6843     unsigned int *hashs2;
6844     xmlChar **values1;
6845     xmlChar **values2;
6846     int ret = 0;
6847     xmlNodeSetPtr ns1;
6848     xmlNodeSetPtr ns2;
6849
6850     if ((arg1 == NULL) ||
6851         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6852         return(0);
6853     if ((arg2 == NULL) ||
6854         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6855         return(0);
6856
6857     ns1 = arg1->nodesetval;
6858     ns2 = arg2->nodesetval;
6859
6860     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6861         return(0);
6862     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6863         return(0);
6864
6865     /*
6866      * for equal, check if there is a node pertaining to both sets
6867      */
6868     if (neq == 0)
6869         for (i = 0;i < ns1->nodeNr;i++)
6870             for (j = 0;j < ns2->nodeNr;j++)
6871                 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6872                     return(1);
6873
6874     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6875     if (values1 == NULL) {
6876         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6877         return(0);
6878     }
6879     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6880     if (hashs1 == NULL) {
6881         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6882         xmlFree(values1);
6883         return(0);
6884     }
6885     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6886     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6887     if (values2 == NULL) {
6888         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6889         xmlFree(hashs1);
6890         xmlFree(values1);
6891         return(0);
6892     }
6893     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6894     if (hashs2 == NULL) {
6895         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6896         xmlFree(hashs1);
6897         xmlFree(values1);
6898         xmlFree(values2);
6899         return(0);
6900     }
6901     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6902     for (i = 0;i < ns1->nodeNr;i++) {
6903         hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6904         for (j = 0;j < ns2->nodeNr;j++) {
6905             if (i == 0)
6906                 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6907             if (hashs1[i] != hashs2[j]) {
6908                 if (neq) {
6909                     ret = 1;
6910                     break;
6911                 }
6912             }
6913             else {
6914                 if (values1[i] == NULL)
6915                     values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6916                 if (values2[j] == NULL)
6917                     values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6918                 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6919                 if (ret)
6920                     break;
6921             }
6922         }
6923         if (ret)
6924             break;
6925     }
6926     for (i = 0;i < ns1->nodeNr;i++)
6927         if (values1[i] != NULL)
6928             xmlFree(values1[i]);
6929     for (j = 0;j < ns2->nodeNr;j++)
6930         if (values2[j] != NULL)
6931             xmlFree(values2[j]);
6932     xmlFree(values1);
6933     xmlFree(values2);
6934     xmlFree(hashs1);
6935     xmlFree(hashs2);
6936     return(ret);
6937 }
6938
6939 static int
6940 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6941   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6942     int ret = 0;
6943     /*
6944      *At this point we are assured neither arg1 nor arg2
6945      *is a nodeset, so we can just pick the appropriate routine.
6946      */
6947     switch (arg1->type) {
6948         case XPATH_UNDEFINED:
6949 #ifdef DEBUG_EXPR
6950             xmlGenericError(xmlGenericErrorContext,
6951                     "Equal: undefined\n");
6952 #endif
6953             break;
6954         case XPATH_BOOLEAN:
6955             switch (arg2->type) {
6956                 case XPATH_UNDEFINED:
6957 #ifdef DEBUG_EXPR
6958                     xmlGenericError(xmlGenericErrorContext,
6959                             "Equal: undefined\n");
6960 #endif
6961                     break;
6962                 case XPATH_BOOLEAN:
6963 #ifdef DEBUG_EXPR
6964                     xmlGenericError(xmlGenericErrorContext,
6965                             "Equal: %d boolean %d \n",
6966                             arg1->boolval, arg2->boolval);
6967 #endif
6968                     ret = (arg1->boolval == arg2->boolval);
6969                     break;
6970                 case XPATH_NUMBER:
6971                     ret = (arg1->boolval ==
6972                            xmlXPathCastNumberToBoolean(arg2->floatval));
6973                     break;
6974                 case XPATH_STRING:
6975                     if ((arg2->stringval == NULL) ||
6976                         (arg2->stringval[0] == 0)) ret = 0;
6977                     else
6978                         ret = 1;
6979                     ret = (arg1->boolval == ret);
6980                     break;
6981                 case XPATH_USERS:
6982                 case XPATH_POINT:
6983                 case XPATH_RANGE:
6984                 case XPATH_LOCATIONSET:
6985                     TODO
6986                     break;
6987                 case XPATH_NODESET:
6988                 case XPATH_XSLT_TREE:
6989                     break;
6990             }
6991             break;
6992         case XPATH_NUMBER:
6993             switch (arg2->type) {
6994                 case XPATH_UNDEFINED:
6995 #ifdef DEBUG_EXPR
6996                     xmlGenericError(xmlGenericErrorContext,
6997                             "Equal: undefined\n");
6998 #endif
6999                     break;
7000                 case XPATH_BOOLEAN:
7001                     ret = (arg2->boolval==
7002                            xmlXPathCastNumberToBoolean(arg1->floatval));
7003                     break;
7004                 case XPATH_STRING:
7005                     valuePush(ctxt, arg2);
7006                     xmlXPathNumberFunction(ctxt, 1);
7007                     arg2 = valuePop(ctxt);
7008                     /* no break on purpose */
7009                 case XPATH_NUMBER:
7010                     /* Hand check NaN and Infinity equalities */
7011                     if (xmlXPathIsNaN(arg1->floatval) ||
7012                             xmlXPathIsNaN(arg2->floatval)) {
7013                         ret = 0;
7014                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7015                         if (xmlXPathIsInf(arg2->floatval) == 1)
7016                             ret = 1;
7017                         else
7018                             ret = 0;
7019                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7020                         if (xmlXPathIsInf(arg2->floatval) == -1)
7021                             ret = 1;
7022                         else
7023                             ret = 0;
7024                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7025                         if (xmlXPathIsInf(arg1->floatval) == 1)
7026                             ret = 1;
7027                         else
7028                             ret = 0;
7029                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7030                         if (xmlXPathIsInf(arg1->floatval) == -1)
7031                             ret = 1;
7032                         else
7033                             ret = 0;
7034                     } else {
7035                         ret = (arg1->floatval == arg2->floatval);
7036                     }
7037                     break;
7038                 case XPATH_USERS:
7039                 case XPATH_POINT:
7040                 case XPATH_RANGE:
7041                 case XPATH_LOCATIONSET:
7042                     TODO
7043                     break;
7044                 case XPATH_NODESET:
7045                 case XPATH_XSLT_TREE:
7046                     break;
7047             }
7048             break;
7049         case XPATH_STRING:
7050             switch (arg2->type) {
7051                 case XPATH_UNDEFINED:
7052 #ifdef DEBUG_EXPR
7053                     xmlGenericError(xmlGenericErrorContext,
7054                             "Equal: undefined\n");
7055 #endif
7056                     break;
7057                 case XPATH_BOOLEAN:
7058                     if ((arg1->stringval == NULL) ||
7059                         (arg1->stringval[0] == 0)) ret = 0;
7060                     else
7061                         ret = 1;
7062                     ret = (arg2->boolval == ret);
7063                     break;
7064                 case XPATH_STRING:
7065                     ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7066                     break;
7067                 case XPATH_NUMBER:
7068                     valuePush(ctxt, arg1);
7069                     xmlXPathNumberFunction(ctxt, 1);
7070                     arg1 = valuePop(ctxt);
7071                     /* Hand check NaN and Infinity equalities */
7072                     if (xmlXPathIsNaN(arg1->floatval) ||
7073                             xmlXPathIsNaN(arg2->floatval)) {
7074                         ret = 0;
7075                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7076                         if (xmlXPathIsInf(arg2->floatval) == 1)
7077                             ret = 1;
7078                         else
7079                             ret = 0;
7080                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7081                         if (xmlXPathIsInf(arg2->floatval) == -1)
7082                             ret = 1;
7083                         else
7084                             ret = 0;
7085                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7086                         if (xmlXPathIsInf(arg1->floatval) == 1)
7087                             ret = 1;
7088                         else
7089                             ret = 0;
7090                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7091                         if (xmlXPathIsInf(arg1->floatval) == -1)
7092                             ret = 1;
7093                         else
7094                             ret = 0;
7095                     } else {
7096                         ret = (arg1->floatval == arg2->floatval);
7097                     }
7098                     break;
7099                 case XPATH_USERS:
7100                 case XPATH_POINT:
7101                 case XPATH_RANGE:
7102                 case XPATH_LOCATIONSET:
7103                     TODO
7104                     break;
7105                 case XPATH_NODESET:
7106                 case XPATH_XSLT_TREE:
7107                     break;
7108             }
7109             break;
7110         case XPATH_USERS:
7111         case XPATH_POINT:
7112         case XPATH_RANGE:
7113         case XPATH_LOCATIONSET:
7114             TODO
7115             break;
7116         case XPATH_NODESET:
7117         case XPATH_XSLT_TREE:
7118             break;
7119     }
7120     xmlXPathReleaseObject(ctxt->context, arg1);
7121     xmlXPathReleaseObject(ctxt->context, arg2);
7122     return(ret);
7123 }
7124
7125 /**
7126  * xmlXPathEqualValues:
7127  * @ctxt:  the XPath Parser context
7128  *
7129  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7130  *
7131  * Returns 0 or 1 depending on the results of the test.
7132  */
7133 int
7134 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7135     xmlXPathObjectPtr arg1, arg2, argtmp;
7136     int ret = 0;
7137
7138     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7139     arg2 = valuePop(ctxt);
7140     arg1 = valuePop(ctxt);
7141     if ((arg1 == NULL) || (arg2 == NULL)) {
7142         if (arg1 != NULL)
7143             xmlXPathReleaseObject(ctxt->context, arg1);
7144         else
7145             xmlXPathReleaseObject(ctxt->context, arg2);
7146         XP_ERROR0(XPATH_INVALID_OPERAND);
7147     }
7148
7149     if (arg1 == arg2) {
7150 #ifdef DEBUG_EXPR
7151         xmlGenericError(xmlGenericErrorContext,
7152                 "Equal: by pointer\n");
7153 #endif
7154         xmlXPathFreeObject(arg1);
7155         return(1);
7156     }
7157
7158     /*
7159      *If either argument is a nodeset, it's a 'special case'
7160      */
7161     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7162       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7163         /*
7164          *Hack it to assure arg1 is the nodeset
7165          */
7166         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7167                 argtmp = arg2;
7168                 arg2 = arg1;
7169                 arg1 = argtmp;
7170         }
7171         switch (arg2->type) {
7172             case XPATH_UNDEFINED:
7173 #ifdef DEBUG_EXPR
7174                 xmlGenericError(xmlGenericErrorContext,
7175                         "Equal: undefined\n");
7176 #endif
7177                 break;
7178             case XPATH_NODESET:
7179             case XPATH_XSLT_TREE:
7180                 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7181                 break;
7182             case XPATH_BOOLEAN:
7183                 if ((arg1->nodesetval == NULL) ||
7184                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
7185                 else
7186                     ret = 1;
7187                 ret = (ret == arg2->boolval);
7188                 break;
7189             case XPATH_NUMBER:
7190                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7191                 break;
7192             case XPATH_STRING:
7193                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7194                 break;
7195             case XPATH_USERS:
7196             case XPATH_POINT:
7197             case XPATH_RANGE:
7198             case XPATH_LOCATIONSET:
7199                 TODO
7200                 break;
7201         }
7202         xmlXPathReleaseObject(ctxt->context, arg1);
7203         xmlXPathReleaseObject(ctxt->context, arg2);
7204         return(ret);
7205     }
7206
7207     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7208 }
7209
7210 /**
7211  * xmlXPathNotEqualValues:
7212  * @ctxt:  the XPath Parser context
7213  *
7214  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7215  *
7216  * Returns 0 or 1 depending on the results of the test.
7217  */
7218 int
7219 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7220     xmlXPathObjectPtr arg1, arg2, argtmp;
7221     int ret = 0;
7222
7223     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7224     arg2 = valuePop(ctxt);
7225     arg1 = valuePop(ctxt);
7226     if ((arg1 == NULL) || (arg2 == NULL)) {
7227         if (arg1 != NULL)
7228             xmlXPathReleaseObject(ctxt->context, arg1);
7229         else
7230             xmlXPathReleaseObject(ctxt->context, arg2);
7231         XP_ERROR0(XPATH_INVALID_OPERAND);
7232     }
7233
7234     if (arg1 == arg2) {
7235 #ifdef DEBUG_EXPR
7236         xmlGenericError(xmlGenericErrorContext,
7237                 "NotEqual: by pointer\n");
7238 #endif
7239         xmlXPathReleaseObject(ctxt->context, arg1);
7240         return(0);
7241     }
7242
7243     /*
7244      *If either argument is a nodeset, it's a 'special case'
7245      */
7246     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7247       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7248         /*
7249          *Hack it to assure arg1 is the nodeset
7250          */
7251         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7252                 argtmp = arg2;
7253                 arg2 = arg1;
7254                 arg1 = argtmp;
7255         }
7256         switch (arg2->type) {
7257             case XPATH_UNDEFINED:
7258 #ifdef DEBUG_EXPR
7259                 xmlGenericError(xmlGenericErrorContext,
7260                         "NotEqual: undefined\n");
7261 #endif
7262                 break;
7263             case XPATH_NODESET:
7264             case XPATH_XSLT_TREE:
7265                 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7266                 break;
7267             case XPATH_BOOLEAN:
7268                 if ((arg1->nodesetval == NULL) ||
7269                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
7270                 else
7271                     ret = 1;
7272                 ret = (ret != arg2->boolval);
7273                 break;
7274             case XPATH_NUMBER:
7275                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7276                 break;
7277             case XPATH_STRING:
7278                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7279                 break;
7280             case XPATH_USERS:
7281             case XPATH_POINT:
7282             case XPATH_RANGE:
7283             case XPATH_LOCATIONSET:
7284                 TODO
7285                 break;
7286         }
7287         xmlXPathReleaseObject(ctxt->context, arg1);
7288         xmlXPathReleaseObject(ctxt->context, arg2);
7289         return(ret);
7290     }
7291
7292     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7293 }
7294
7295 /**
7296  * xmlXPathCompareValues:
7297  * @ctxt:  the XPath Parser context
7298  * @inf:  less than (1) or greater than (0)
7299  * @strict:  is the comparison strict
7300  *
7301  * Implement the compare operation on XPath objects:
7302  *     @arg1 < @arg2    (1, 1, ...
7303  *     @arg1 <= @arg2   (1, 0, ...
7304  *     @arg1 > @arg2    (0, 1, ...
7305  *     @arg1 >= @arg2   (0, 0, ...
7306  *
7307  * When neither object to be compared is a node-set and the operator is
7308  * <=, <, >=, >, then the objects are compared by converted both objects
7309  * to numbers and comparing the numbers according to IEEE 754. The <
7310  * comparison will be true if and only if the first number is less than the
7311  * second number. The <= comparison will be true if and only if the first
7312  * number is less than or equal to the second number. The > comparison
7313  * will be true if and only if the first number is greater than the second
7314  * number. The >= comparison will be true if and only if the first number
7315  * is greater than or equal to the second number.
7316  *
7317  * Returns 1 if the comparison succeeded, 0 if it failed
7318  */
7319 int
7320 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7321     int ret = 0, arg1i = 0, arg2i = 0;
7322     xmlXPathObjectPtr arg1, arg2;
7323
7324     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7325     arg2 = valuePop(ctxt);
7326     arg1 = valuePop(ctxt);
7327     if ((arg1 == NULL) || (arg2 == NULL)) {
7328         if (arg1 != NULL)
7329             xmlXPathReleaseObject(ctxt->context, arg1);
7330         else
7331             xmlXPathReleaseObject(ctxt->context, arg2);
7332         XP_ERROR0(XPATH_INVALID_OPERAND);
7333     }
7334
7335     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7336       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7337         /*
7338          * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7339          * are not freed from within this routine; they will be freed from the
7340          * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7341          */
7342         if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7343           ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7344             ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7345         } else {
7346             if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7347                 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7348                                                   arg1, arg2);
7349             } else {
7350                 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7351                                                   arg2, arg1);
7352             }
7353         }
7354         return(ret);
7355     }
7356
7357     if (arg1->type != XPATH_NUMBER) {
7358         valuePush(ctxt, arg1);
7359         xmlXPathNumberFunction(ctxt, 1);
7360         arg1 = valuePop(ctxt);
7361     }
7362     if (arg1->type != XPATH_NUMBER) {
7363         xmlXPathFreeObject(arg1);
7364         xmlXPathFreeObject(arg2);
7365         XP_ERROR0(XPATH_INVALID_OPERAND);
7366     }
7367     if (arg2->type != XPATH_NUMBER) {
7368         valuePush(ctxt, arg2);
7369         xmlXPathNumberFunction(ctxt, 1);
7370         arg2 = valuePop(ctxt);
7371     }
7372     if (arg2->type != XPATH_NUMBER) {
7373         xmlXPathReleaseObject(ctxt->context, arg1);
7374         xmlXPathReleaseObject(ctxt->context, arg2);
7375         XP_ERROR0(XPATH_INVALID_OPERAND);
7376     }
7377     /*
7378      * Add tests for infinity and nan
7379      * => feedback on 3.4 for Inf and NaN
7380      */
7381     /* Hand check NaN and Infinity comparisons */
7382     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7383         ret=0;
7384     } else {
7385         arg1i=xmlXPathIsInf(arg1->floatval);
7386         arg2i=xmlXPathIsInf(arg2->floatval);
7387         if (inf && strict) {
7388             if ((arg1i == -1 && arg2i != -1) ||
7389                 (arg2i == 1 && arg1i != 1)) {
7390                 ret = 1;
7391             } else if (arg1i == 0 && arg2i == 0) {
7392                 ret = (arg1->floatval < arg2->floatval);
7393             } else {
7394                 ret = 0;
7395             }
7396         }
7397         else if (inf && !strict) {
7398             if (arg1i == -1 || arg2i == 1) {
7399                 ret = 1;
7400             } else if (arg1i == 0 && arg2i == 0) {
7401                 ret = (arg1->floatval <= arg2->floatval);
7402             } else {
7403                 ret = 0;
7404             }
7405         }
7406         else if (!inf && strict) {
7407             if ((arg1i == 1 && arg2i != 1) ||
7408                 (arg2i == -1 && arg1i != -1)) {
7409                 ret = 1;
7410             } else if (arg1i == 0 && arg2i == 0) {
7411                 ret = (arg1->floatval > arg2->floatval);
7412             } else {
7413                 ret = 0;
7414             }
7415         }
7416         else if (!inf && !strict) {
7417             if (arg1i == 1 || arg2i == -1) {
7418                 ret = 1;
7419             } else if (arg1i == 0 && arg2i == 0) {
7420                 ret = (arg1->floatval >= arg2->floatval);
7421             } else {
7422                 ret = 0;
7423             }
7424         }
7425     }
7426     xmlXPathReleaseObject(ctxt->context, arg1);
7427     xmlXPathReleaseObject(ctxt->context, arg2);
7428     return(ret);
7429 }
7430
7431 /**
7432  * xmlXPathValueFlipSign:
7433  * @ctxt:  the XPath Parser context
7434  *
7435  * Implement the unary - operation on an XPath object
7436  * The numeric operators convert their operands to numbers as if
7437  * by calling the number function.
7438  */
7439 void
7440 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7441     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7442     CAST_TO_NUMBER;
7443     CHECK_TYPE(XPATH_NUMBER);
7444     if (xmlXPathIsNaN(ctxt->value->floatval))
7445         ctxt->value->floatval=xmlXPathNAN;
7446     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7447         ctxt->value->floatval=xmlXPathNINF;
7448     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7449         ctxt->value->floatval=xmlXPathPINF;
7450     else if (ctxt->value->floatval == 0) {
7451         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7452             ctxt->value->floatval = xmlXPathNZERO;
7453         else
7454             ctxt->value->floatval = 0;
7455     }
7456     else
7457         ctxt->value->floatval = - ctxt->value->floatval;
7458 }
7459
7460 /**
7461  * xmlXPathAddValues:
7462  * @ctxt:  the XPath Parser context
7463  *
7464  * Implement the add operation on XPath objects:
7465  * The numeric operators convert their operands to numbers as if
7466  * by calling the number function.
7467  */
7468 void
7469 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7470     xmlXPathObjectPtr arg;
7471     double val;
7472
7473     arg = valuePop(ctxt);
7474     if (arg == NULL)
7475         XP_ERROR(XPATH_INVALID_OPERAND);
7476     val = xmlXPathCastToNumber(arg);
7477     xmlXPathReleaseObject(ctxt->context, arg);
7478     CAST_TO_NUMBER;
7479     CHECK_TYPE(XPATH_NUMBER);
7480     ctxt->value->floatval += val;
7481 }
7482
7483 /**
7484  * xmlXPathSubValues:
7485  * @ctxt:  the XPath Parser context
7486  *
7487  * Implement the subtraction operation on XPath objects:
7488  * The numeric operators convert their operands to numbers as if
7489  * by calling the number function.
7490  */
7491 void
7492 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7493     xmlXPathObjectPtr arg;
7494     double val;
7495
7496     arg = valuePop(ctxt);
7497     if (arg == NULL)
7498         XP_ERROR(XPATH_INVALID_OPERAND);
7499     val = xmlXPathCastToNumber(arg);
7500     xmlXPathReleaseObject(ctxt->context, arg);
7501     CAST_TO_NUMBER;
7502     CHECK_TYPE(XPATH_NUMBER);
7503     ctxt->value->floatval -= val;
7504 }
7505
7506 /**
7507  * xmlXPathMultValues:
7508  * @ctxt:  the XPath Parser context
7509  *
7510  * Implement the multiply operation on XPath objects:
7511  * The numeric operators convert their operands to numbers as if
7512  * by calling the number function.
7513  */
7514 void
7515 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7516     xmlXPathObjectPtr arg;
7517     double val;
7518
7519     arg = valuePop(ctxt);
7520     if (arg == NULL)
7521         XP_ERROR(XPATH_INVALID_OPERAND);
7522     val = xmlXPathCastToNumber(arg);
7523     xmlXPathReleaseObject(ctxt->context, arg);
7524     CAST_TO_NUMBER;
7525     CHECK_TYPE(XPATH_NUMBER);
7526     ctxt->value->floatval *= val;
7527 }
7528
7529 /**
7530  * xmlXPathDivValues:
7531  * @ctxt:  the XPath Parser context
7532  *
7533  * Implement the div operation on XPath objects @arg1 / @arg2:
7534  * The numeric operators convert their operands to numbers as if
7535  * by calling the number function.
7536  */
7537 void
7538 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7539     xmlXPathObjectPtr arg;
7540     double val;
7541
7542     arg = valuePop(ctxt);
7543     if (arg == NULL)
7544         XP_ERROR(XPATH_INVALID_OPERAND);
7545     val = xmlXPathCastToNumber(arg);
7546     xmlXPathReleaseObject(ctxt->context, arg);
7547     CAST_TO_NUMBER;
7548     CHECK_TYPE(XPATH_NUMBER);
7549     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7550         ctxt->value->floatval = xmlXPathNAN;
7551     else if (val == 0 && xmlXPathGetSign(val) != 0) {
7552         if (ctxt->value->floatval == 0)
7553             ctxt->value->floatval = xmlXPathNAN;
7554         else if (ctxt->value->floatval > 0)
7555             ctxt->value->floatval = xmlXPathNINF;
7556         else if (ctxt->value->floatval < 0)
7557             ctxt->value->floatval = xmlXPathPINF;
7558     }
7559     else if (val == 0) {
7560         if (ctxt->value->floatval == 0)
7561             ctxt->value->floatval = xmlXPathNAN;
7562         else if (ctxt->value->floatval > 0)
7563             ctxt->value->floatval = xmlXPathPINF;
7564         else if (ctxt->value->floatval < 0)
7565             ctxt->value->floatval = xmlXPathNINF;
7566     } else
7567         ctxt->value->floatval /= val;
7568 }
7569
7570 /**
7571  * xmlXPathModValues:
7572  * @ctxt:  the XPath Parser context
7573  *
7574  * Implement the mod operation on XPath objects: @arg1 / @arg2
7575  * The numeric operators convert their operands to numbers as if
7576  * by calling the number function.
7577  */
7578 void
7579 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7580     xmlXPathObjectPtr arg;
7581     double arg1, arg2;
7582
7583     arg = valuePop(ctxt);
7584     if (arg == NULL)
7585         XP_ERROR(XPATH_INVALID_OPERAND);
7586     arg2 = xmlXPathCastToNumber(arg);
7587     xmlXPathReleaseObject(ctxt->context, arg);
7588     CAST_TO_NUMBER;
7589     CHECK_TYPE(XPATH_NUMBER);
7590     arg1 = ctxt->value->floatval;
7591     if (arg2 == 0)
7592         ctxt->value->floatval = xmlXPathNAN;
7593     else {
7594         ctxt->value->floatval = fmod(arg1, arg2);
7595     }
7596 }
7597
7598 /************************************************************************
7599  *                                                                      *
7600  *              The traversal functions                                 *
7601  *                                                                      *
7602  ************************************************************************/
7603
7604 /*
7605  * A traversal function enumerates nodes along an axis.
7606  * Initially it must be called with NULL, and it indicates
7607  * termination on the axis by returning NULL.
7608  */
7609 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7610                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7611
7612 /*
7613  * xmlXPathTraversalFunctionExt:
7614  * A traversal function enumerates nodes along an axis.
7615  * Initially it must be called with NULL, and it indicates
7616  * termination on the axis by returning NULL.
7617  * The context node of the traversal is specified via @contextNode.
7618  */
7619 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7620                     (xmlNodePtr cur, xmlNodePtr contextNode);
7621
7622 /*
7623  * xmlXPathNodeSetMergeFunction:
7624  * Used for merging node sets in xmlXPathCollectAndTest().
7625  */
7626 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7627                     (xmlNodeSetPtr, xmlNodeSetPtr, int);
7628
7629
7630 /**
7631  * xmlXPathNextSelf:
7632  * @ctxt:  the XPath Parser context
7633  * @cur:  the current node in the traversal
7634  *
7635  * Traversal function for the "self" direction
7636  * The self axis contains just the context node itself
7637  *
7638  * Returns the next element following that axis
7639  */
7640 xmlNodePtr
7641 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7642     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7643     if (cur == NULL)
7644         return(ctxt->context->node);
7645     return(NULL);
7646 }
7647
7648 /**
7649  * xmlXPathNextChild:
7650  * @ctxt:  the XPath Parser context
7651  * @cur:  the current node in the traversal
7652  *
7653  * Traversal function for the "child" direction
7654  * The child axis contains the children of the context node in document order.
7655  *
7656  * Returns the next element following that axis
7657  */
7658 xmlNodePtr
7659 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7660     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7661     if (cur == NULL) {
7662         if (ctxt->context->node == NULL) return(NULL);
7663         switch (ctxt->context->node->type) {
7664             case XML_ELEMENT_NODE:
7665             case XML_TEXT_NODE:
7666             case XML_CDATA_SECTION_NODE:
7667             case XML_ENTITY_REF_NODE:
7668             case XML_ENTITY_NODE:
7669             case XML_PI_NODE:
7670             case XML_COMMENT_NODE:
7671             case XML_NOTATION_NODE:
7672             case XML_DTD_NODE:
7673                 return(ctxt->context->node->children);
7674             case XML_DOCUMENT_NODE:
7675             case XML_DOCUMENT_TYPE_NODE:
7676             case XML_DOCUMENT_FRAG_NODE:
7677             case XML_HTML_DOCUMENT_NODE:
7678 #ifdef LIBXML_DOCB_ENABLED
7679             case XML_DOCB_DOCUMENT_NODE:
7680 #endif
7681                 return(((xmlDocPtr) ctxt->context->node)->children);
7682             case XML_ELEMENT_DECL:
7683             case XML_ATTRIBUTE_DECL:
7684             case XML_ENTITY_DECL:
7685             case XML_ATTRIBUTE_NODE:
7686             case XML_NAMESPACE_DECL:
7687             case XML_XINCLUDE_START:
7688             case XML_XINCLUDE_END:
7689                 return(NULL);
7690         }
7691         return(NULL);
7692     }
7693     if ((cur->type == XML_DOCUMENT_NODE) ||
7694         (cur->type == XML_HTML_DOCUMENT_NODE))
7695         return(NULL);
7696     return(cur->next);
7697 }
7698
7699 /**
7700  * xmlXPathNextChildElement:
7701  * @ctxt:  the XPath Parser context
7702  * @cur:  the current node in the traversal
7703  *
7704  * Traversal function for the "child" direction and nodes of type element.
7705  * The child axis contains the children of the context node in document order.
7706  *
7707  * Returns the next element following that axis
7708  */
7709 static xmlNodePtr
7710 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7711     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7712     if (cur == NULL) {
7713         cur = ctxt->context->node;
7714         if (cur == NULL) return(NULL);
7715         /*
7716         * Get the first element child.
7717         */
7718         switch (cur->type) {
7719             case XML_ELEMENT_NODE:
7720             case XML_DOCUMENT_FRAG_NODE:
7721             case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7722             case XML_ENTITY_NODE:
7723                 cur = cur->children;
7724                 if (cur != NULL) {
7725                     if (cur->type == XML_ELEMENT_NODE)
7726                         return(cur);
7727                     do {
7728                         cur = cur->next;
7729                     } while ((cur != NULL) &&
7730                         (cur->type != XML_ELEMENT_NODE));
7731                     return(cur);
7732                 }
7733                 return(NULL);
7734             case XML_DOCUMENT_NODE:
7735             case XML_HTML_DOCUMENT_NODE:
7736 #ifdef LIBXML_DOCB_ENABLED
7737             case XML_DOCB_DOCUMENT_NODE:
7738 #endif
7739                 return(xmlDocGetRootElement((xmlDocPtr) cur));
7740             default:
7741                 return(NULL);
7742         }
7743         return(NULL);
7744     }
7745     /*
7746     * Get the next sibling element node.
7747     */
7748     switch (cur->type) {
7749         case XML_ELEMENT_NODE:
7750         case XML_TEXT_NODE:
7751         case XML_ENTITY_REF_NODE:
7752         case XML_ENTITY_NODE:
7753         case XML_CDATA_SECTION_NODE:
7754         case XML_PI_NODE:
7755         case XML_COMMENT_NODE:
7756         case XML_XINCLUDE_END:
7757             break;
7758         /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7759         default:
7760             return(NULL);
7761     }
7762     if (cur->next != NULL) {
7763         if (cur->next->type == XML_ELEMENT_NODE)
7764             return(cur->next);
7765         cur = cur->next;
7766         do {
7767             cur = cur->next;
7768         } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7769         return(cur);
7770     }
7771     return(NULL);
7772 }
7773
7774 #if 0
7775 /**
7776  * xmlXPathNextDescendantOrSelfElemParent:
7777  * @ctxt:  the XPath Parser context
7778  * @cur:  the current node in the traversal
7779  *
7780  * Traversal function for the "descendant-or-self" axis.
7781  * Additionally it returns only nodes which can be parents of
7782  * element nodes.
7783  *
7784  *
7785  * Returns the next element following that axis
7786  */
7787 static xmlNodePtr
7788 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7789                                        xmlNodePtr contextNode)
7790 {
7791     if (cur == NULL) {
7792         if (contextNode == NULL)
7793             return(NULL);
7794         switch (contextNode->type) {
7795             case XML_ELEMENT_NODE:
7796             case XML_XINCLUDE_START:
7797             case XML_DOCUMENT_FRAG_NODE:
7798             case XML_DOCUMENT_NODE:
7799 #ifdef LIBXML_DOCB_ENABLED
7800             case XML_DOCB_DOCUMENT_NODE:
7801 #endif
7802             case XML_HTML_DOCUMENT_NODE:
7803                 return(contextNode);
7804             default:
7805                 return(NULL);
7806         }
7807         return(NULL);
7808     } else {
7809         xmlNodePtr start = cur;
7810
7811         while (cur != NULL) {
7812             switch (cur->type) {
7813                 case XML_ELEMENT_NODE:
7814                 /* TODO: OK to have XInclude here? */
7815                 case XML_XINCLUDE_START:
7816                 case XML_DOCUMENT_FRAG_NODE:
7817                     if (cur != start)
7818                         return(cur);
7819                     if (cur->children != NULL) {
7820                         cur = cur->children;
7821                         continue;
7822                     }
7823                     break;
7824                 /* Not sure if we need those here. */
7825                 case XML_DOCUMENT_NODE:
7826 #ifdef LIBXML_DOCB_ENABLED
7827                 case XML_DOCB_DOCUMENT_NODE:
7828 #endif
7829                 case XML_HTML_DOCUMENT_NODE:
7830                     if (cur != start)
7831                         return(cur);
7832                     return(xmlDocGetRootElement((xmlDocPtr) cur));
7833                 default:
7834                     break;
7835             }
7836
7837 next_sibling:
7838             if ((cur == NULL) || (cur == contextNode))
7839                 return(NULL);
7840             if (cur->next != NULL) {
7841                 cur = cur->next;
7842             } else {
7843                 cur = cur->parent;
7844                 goto next_sibling;
7845             }
7846         }
7847     }
7848     return(NULL);
7849 }
7850 #endif
7851
7852 /**
7853  * xmlXPathNextDescendant:
7854  * @ctxt:  the XPath Parser context
7855  * @cur:  the current node in the traversal
7856  *
7857  * Traversal function for the "descendant" direction
7858  * the descendant axis contains the descendants of the context node in document
7859  * order; a descendant is a child or a child of a child and so on.
7860  *
7861  * Returns the next element following that axis
7862  */
7863 xmlNodePtr
7864 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7865     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7866     if (cur == NULL) {
7867         if (ctxt->context->node == NULL)
7868             return(NULL);
7869         if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7870             (ctxt->context->node->type == XML_NAMESPACE_DECL))
7871             return(NULL);
7872
7873         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7874             return(ctxt->context->doc->children);
7875         return(ctxt->context->node->children);
7876     }
7877
7878     if (cur->type == XML_NAMESPACE_DECL)
7879         return(NULL);
7880     if (cur->children != NULL) {
7881         /*
7882          * Do not descend on entities declarations
7883          */
7884         if (cur->children->type != XML_ENTITY_DECL) {
7885             cur = cur->children;
7886             /*
7887              * Skip DTDs
7888              */
7889             if (cur->type != XML_DTD_NODE)
7890                 return(cur);
7891         }
7892     }
7893
7894     if (cur == ctxt->context->node) return(NULL);
7895
7896     while (cur->next != NULL) {
7897         cur = cur->next;
7898         if ((cur->type != XML_ENTITY_DECL) &&
7899             (cur->type != XML_DTD_NODE))
7900             return(cur);
7901     }
7902
7903     do {
7904         cur = cur->parent;
7905         if (cur == NULL) break;
7906         if (cur == ctxt->context->node) return(NULL);
7907         if (cur->next != NULL) {
7908             cur = cur->next;
7909             return(cur);
7910         }
7911     } while (cur != NULL);
7912     return(cur);
7913 }
7914
7915 /**
7916  * xmlXPathNextDescendantOrSelf:
7917  * @ctxt:  the XPath Parser context
7918  * @cur:  the current node in the traversal
7919  *
7920  * Traversal function for the "descendant-or-self" direction
7921  * the descendant-or-self axis contains the context node and the descendants
7922  * of the context node in document order; thus the context node is the first
7923  * node on the axis, and the first child of the context node is the second node
7924  * on the axis
7925  *
7926  * Returns the next element following that axis
7927  */
7928 xmlNodePtr
7929 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7930     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7931     if (cur == NULL) {
7932         if (ctxt->context->node == NULL)
7933             return(NULL);
7934         if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7935             (ctxt->context->node->type == XML_NAMESPACE_DECL))
7936             return(NULL);
7937         return(ctxt->context->node);
7938     }
7939
7940     return(xmlXPathNextDescendant(ctxt, cur));
7941 }
7942
7943 /**
7944  * xmlXPathNextParent:
7945  * @ctxt:  the XPath Parser context
7946  * @cur:  the current node in the traversal
7947  *
7948  * Traversal function for the "parent" direction
7949  * The parent axis contains the parent of the context node, if there is one.
7950  *
7951  * Returns the next element following that axis
7952  */
7953 xmlNodePtr
7954 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7955     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7956     /*
7957      * the parent of an attribute or namespace node is the element
7958      * to which the attribute or namespace node is attached
7959      * Namespace handling !!!
7960      */
7961     if (cur == NULL) {
7962         if (ctxt->context->node == NULL) return(NULL);
7963         switch (ctxt->context->node->type) {
7964             case XML_ELEMENT_NODE:
7965             case XML_TEXT_NODE:
7966             case XML_CDATA_SECTION_NODE:
7967             case XML_ENTITY_REF_NODE:
7968             case XML_ENTITY_NODE:
7969             case XML_PI_NODE:
7970             case XML_COMMENT_NODE:
7971             case XML_NOTATION_NODE:
7972             case XML_DTD_NODE:
7973             case XML_ELEMENT_DECL:
7974             case XML_ATTRIBUTE_DECL:
7975             case XML_XINCLUDE_START:
7976             case XML_XINCLUDE_END:
7977             case XML_ENTITY_DECL:
7978                 if (ctxt->context->node->parent == NULL)
7979                     return((xmlNodePtr) ctxt->context->doc);
7980                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7981                     ((ctxt->context->node->parent->name[0] == ' ') ||
7982                      (xmlStrEqual(ctxt->context->node->parent->name,
7983                                  BAD_CAST "fake node libxslt"))))
7984                     return(NULL);
7985                 return(ctxt->context->node->parent);
7986             case XML_ATTRIBUTE_NODE: {
7987                 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7988
7989                 return(att->parent);
7990             }
7991             case XML_DOCUMENT_NODE:
7992             case XML_DOCUMENT_TYPE_NODE:
7993             case XML_DOCUMENT_FRAG_NODE:
7994             case XML_HTML_DOCUMENT_NODE:
7995 #ifdef LIBXML_DOCB_ENABLED
7996             case XML_DOCB_DOCUMENT_NODE:
7997 #endif
7998                 return(NULL);
7999             case XML_NAMESPACE_DECL: {
8000                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8001
8002                 if ((ns->next != NULL) &&
8003                     (ns->next->type != XML_NAMESPACE_DECL))
8004                     return((xmlNodePtr) ns->next);
8005                 return(NULL);
8006             }
8007         }
8008     }
8009     return(NULL);
8010 }
8011
8012 /**
8013  * xmlXPathNextAncestor:
8014  * @ctxt:  the XPath Parser context
8015  * @cur:  the current node in the traversal
8016  *
8017  * Traversal function for the "ancestor" direction
8018  * the ancestor axis contains the ancestors of the context node; the ancestors
8019  * of the context node consist of the parent of context node and the parent's
8020  * parent and so on; the nodes are ordered in reverse document order; thus the
8021  * parent is the first node on the axis, and the parent's parent is the second
8022  * node on the axis
8023  *
8024  * Returns the next element following that axis
8025  */
8026 xmlNodePtr
8027 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8028     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8029     /*
8030      * the parent of an attribute or namespace node is the element
8031      * to which the attribute or namespace node is attached
8032      * !!!!!!!!!!!!!
8033      */
8034     if (cur == NULL) {
8035         if (ctxt->context->node == NULL) return(NULL);
8036         switch (ctxt->context->node->type) {
8037             case XML_ELEMENT_NODE:
8038             case XML_TEXT_NODE:
8039             case XML_CDATA_SECTION_NODE:
8040             case XML_ENTITY_REF_NODE:
8041             case XML_ENTITY_NODE:
8042             case XML_PI_NODE:
8043             case XML_COMMENT_NODE:
8044             case XML_DTD_NODE:
8045             case XML_ELEMENT_DECL:
8046             case XML_ATTRIBUTE_DECL:
8047             case XML_ENTITY_DECL:
8048             case XML_NOTATION_NODE:
8049             case XML_XINCLUDE_START:
8050             case XML_XINCLUDE_END:
8051                 if (ctxt->context->node->parent == NULL)
8052                     return((xmlNodePtr) ctxt->context->doc);
8053                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8054                     ((ctxt->context->node->parent->name[0] == ' ') ||
8055                      (xmlStrEqual(ctxt->context->node->parent->name,
8056                                  BAD_CAST "fake node libxslt"))))
8057                     return(NULL);
8058                 return(ctxt->context->node->parent);
8059             case XML_ATTRIBUTE_NODE: {
8060                 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8061
8062                 return(tmp->parent);
8063             }
8064             case XML_DOCUMENT_NODE:
8065             case XML_DOCUMENT_TYPE_NODE:
8066             case XML_DOCUMENT_FRAG_NODE:
8067             case XML_HTML_DOCUMENT_NODE:
8068 #ifdef LIBXML_DOCB_ENABLED
8069             case XML_DOCB_DOCUMENT_NODE:
8070 #endif
8071                 return(NULL);
8072             case XML_NAMESPACE_DECL: {
8073                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8074
8075                 if ((ns->next != NULL) &&
8076                     (ns->next->type != XML_NAMESPACE_DECL))
8077                     return((xmlNodePtr) ns->next);
8078                 /* Bad, how did that namespace end up here ? */
8079                 return(NULL);
8080             }
8081         }
8082         return(NULL);
8083     }
8084     if (cur == ctxt->context->doc->children)
8085         return((xmlNodePtr) ctxt->context->doc);
8086     if (cur == (xmlNodePtr) ctxt->context->doc)
8087         return(NULL);
8088     switch (cur->type) {
8089         case XML_ELEMENT_NODE:
8090         case XML_TEXT_NODE:
8091         case XML_CDATA_SECTION_NODE:
8092         case XML_ENTITY_REF_NODE:
8093         case XML_ENTITY_NODE:
8094         case XML_PI_NODE:
8095         case XML_COMMENT_NODE:
8096         case XML_NOTATION_NODE:
8097         case XML_DTD_NODE:
8098         case XML_ELEMENT_DECL:
8099         case XML_ATTRIBUTE_DECL:
8100         case XML_ENTITY_DECL:
8101         case XML_XINCLUDE_START:
8102         case XML_XINCLUDE_END:
8103             if (cur->parent == NULL)
8104                 return(NULL);
8105             if ((cur->parent->type == XML_ELEMENT_NODE) &&
8106                 ((cur->parent->name[0] == ' ') ||
8107                  (xmlStrEqual(cur->parent->name,
8108                               BAD_CAST "fake node libxslt"))))
8109                 return(NULL);
8110             return(cur->parent);
8111         case XML_ATTRIBUTE_NODE: {
8112             xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8113
8114             return(att->parent);
8115         }
8116         case XML_NAMESPACE_DECL: {
8117             xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8118
8119             if ((ns->next != NULL) &&
8120                 (ns->next->type != XML_NAMESPACE_DECL))
8121                 return((xmlNodePtr) ns->next);
8122             /* Bad, how did that namespace end up here ? */
8123             return(NULL);
8124         }
8125         case XML_DOCUMENT_NODE:
8126         case XML_DOCUMENT_TYPE_NODE:
8127         case XML_DOCUMENT_FRAG_NODE:
8128         case XML_HTML_DOCUMENT_NODE:
8129 #ifdef LIBXML_DOCB_ENABLED
8130         case XML_DOCB_DOCUMENT_NODE:
8131 #endif
8132             return(NULL);
8133     }
8134     return(NULL);
8135 }
8136
8137 /**
8138  * xmlXPathNextAncestorOrSelf:
8139  * @ctxt:  the XPath Parser context
8140  * @cur:  the current node in the traversal
8141  *
8142  * Traversal function for the "ancestor-or-self" direction
8143  * he ancestor-or-self axis contains the context node and ancestors of
8144  * the context node in reverse document order; thus the context node is
8145  * the first node on the axis, and the context node's parent the second;
8146  * parent here is defined the same as with the parent axis.
8147  *
8148  * Returns the next element following that axis
8149  */
8150 xmlNodePtr
8151 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8152     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8153     if (cur == NULL)
8154         return(ctxt->context->node);
8155     return(xmlXPathNextAncestor(ctxt, cur));
8156 }
8157
8158 /**
8159  * xmlXPathNextFollowingSibling:
8160  * @ctxt:  the XPath Parser context
8161  * @cur:  the current node in the traversal
8162  *
8163  * Traversal function for the "following-sibling" direction
8164  * The following-sibling axis contains the following siblings of the context
8165  * node in document order.
8166  *
8167  * Returns the next element following that axis
8168  */
8169 xmlNodePtr
8170 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8171     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8172     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8173         (ctxt->context->node->type == XML_NAMESPACE_DECL))
8174         return(NULL);
8175     if (cur == (xmlNodePtr) ctxt->context->doc)
8176         return(NULL);
8177     if (cur == NULL)
8178         return(ctxt->context->node->next);
8179     return(cur->next);
8180 }
8181
8182 /**
8183  * xmlXPathNextPrecedingSibling:
8184  * @ctxt:  the XPath Parser context
8185  * @cur:  the current node in the traversal
8186  *
8187  * Traversal function for the "preceding-sibling" direction
8188  * The preceding-sibling axis contains the preceding siblings of the context
8189  * node in reverse document order; the first preceding sibling is first on the
8190  * axis; the sibling preceding that node is the second on the axis and so on.
8191  *
8192  * Returns the next element following that axis
8193  */
8194 xmlNodePtr
8195 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8196     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8197     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8198         (ctxt->context->node->type == XML_NAMESPACE_DECL))
8199         return(NULL);
8200     if (cur == (xmlNodePtr) ctxt->context->doc)
8201         return(NULL);
8202     if (cur == NULL)
8203         return(ctxt->context->node->prev);
8204     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8205         cur = cur->prev;
8206         if (cur == NULL)
8207             return(ctxt->context->node->prev);
8208     }
8209     return(cur->prev);
8210 }
8211
8212 /**
8213  * xmlXPathNextFollowing:
8214  * @ctxt:  the XPath Parser context
8215  * @cur:  the current node in the traversal
8216  *
8217  * Traversal function for the "following" direction
8218  * The following axis contains all nodes in the same document as the context
8219  * node that are after the context node in document order, excluding any
8220  * descendants and excluding attribute nodes and namespace nodes; the nodes
8221  * are ordered in document order
8222  *
8223  * Returns the next element following that axis
8224  */
8225 xmlNodePtr
8226 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8227     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8228     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8229         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8230         return(cur->children);
8231
8232     if (cur == NULL) {
8233         cur = ctxt->context->node;
8234         if (cur->type == XML_NAMESPACE_DECL)
8235             return(NULL);
8236         if (cur->type == XML_ATTRIBUTE_NODE)
8237             cur = cur->parent;
8238     }
8239     if (cur == NULL) return(NULL) ; /* ERROR */
8240     if (cur->next != NULL) return(cur->next) ;
8241     do {
8242         cur = cur->parent;
8243         if (cur == NULL) break;
8244         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8245         if (cur->next != NULL) return(cur->next);
8246     } while (cur != NULL);
8247     return(cur);
8248 }
8249
8250 /*
8251  * xmlXPathIsAncestor:
8252  * @ancestor:  the ancestor node
8253  * @node:  the current node
8254  *
8255  * Check that @ancestor is a @node's ancestor
8256  *
8257  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8258  */
8259 static int
8260 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8261     if ((ancestor == NULL) || (node == NULL)) return(0);
8262     if (node->type == XML_NAMESPACE_DECL)
8263         return(0);
8264     if (ancestor->type == XML_NAMESPACE_DECL)
8265         return(0);
8266     /* nodes need to be in the same document */
8267     if (ancestor->doc != node->doc) return(0);
8268     /* avoid searching if ancestor or node is the root node */
8269     if (ancestor == (xmlNodePtr) node->doc) return(1);
8270     if (node == (xmlNodePtr) ancestor->doc) return(0);
8271     while (node->parent != NULL) {
8272         if (node->parent == ancestor)
8273             return(1);
8274         node = node->parent;
8275     }
8276     return(0);
8277 }
8278
8279 /**
8280  * xmlXPathNextPreceding:
8281  * @ctxt:  the XPath Parser context
8282  * @cur:  the current node in the traversal
8283  *
8284  * Traversal function for the "preceding" direction
8285  * the preceding axis contains all nodes in the same document as the context
8286  * node that are before the context node in document order, excluding any
8287  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8288  * ordered in reverse document order
8289  *
8290  * Returns the next element following that axis
8291  */
8292 xmlNodePtr
8293 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8294 {
8295     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8296     if (cur == NULL) {
8297         cur = ctxt->context->node;
8298         if (cur->type == XML_NAMESPACE_DECL)
8299             return(NULL);
8300         if (cur->type == XML_ATTRIBUTE_NODE)
8301             return(cur->parent);
8302     }
8303     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8304         return (NULL);
8305     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8306         cur = cur->prev;
8307     do {
8308         if (cur->prev != NULL) {
8309             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8310             return (cur);
8311         }
8312
8313         cur = cur->parent;
8314         if (cur == NULL)
8315             return (NULL);
8316         if (cur == ctxt->context->doc->children)
8317             return (NULL);
8318     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8319     return (cur);
8320 }
8321
8322 /**
8323  * xmlXPathNextPrecedingInternal:
8324  * @ctxt:  the XPath Parser context
8325  * @cur:  the current node in the traversal
8326  *
8327  * Traversal function for the "preceding" direction
8328  * the preceding axis contains all nodes in the same document as the context
8329  * node that are before the context node in document order, excluding any
8330  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8331  * ordered in reverse document order
8332  * This is a faster implementation but internal only since it requires a
8333  * state kept in the parser context: ctxt->ancestor.
8334  *
8335  * Returns the next element following that axis
8336  */
8337 static xmlNodePtr
8338 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8339                               xmlNodePtr cur)
8340 {
8341     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8342     if (cur == NULL) {
8343         cur = ctxt->context->node;
8344         if (cur == NULL)
8345             return (NULL);
8346         if (cur->type == XML_NAMESPACE_DECL)
8347             return (NULL);
8348         ctxt->ancestor = cur->parent;
8349     }
8350     if (cur->type == XML_NAMESPACE_DECL)
8351         return(NULL);
8352     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8353         cur = cur->prev;
8354     while (cur->prev == NULL) {
8355         cur = cur->parent;
8356         if (cur == NULL)
8357             return (NULL);
8358         if (cur == ctxt->context->doc->children)
8359             return (NULL);
8360         if (cur != ctxt->ancestor)
8361             return (cur);
8362         ctxt->ancestor = cur->parent;
8363     }
8364     cur = cur->prev;
8365     while (cur->last != NULL)
8366         cur = cur->last;
8367     return (cur);
8368 }
8369
8370 /**
8371  * xmlXPathNextNamespace:
8372  * @ctxt:  the XPath Parser context
8373  * @cur:  the current attribute in the traversal
8374  *
8375  * Traversal function for the "namespace" direction
8376  * the namespace axis contains the namespace nodes of the context node;
8377  * the order of nodes on this axis is implementation-defined; the axis will
8378  * be empty unless the context node is an element
8379  *
8380  * We keep the XML namespace node at the end of the list.
8381  *
8382  * Returns the next element following that axis
8383  */
8384 xmlNodePtr
8385 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8386     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8387     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8388     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8389         if (ctxt->context->tmpNsList != NULL)
8390             xmlFree(ctxt->context->tmpNsList);
8391         ctxt->context->tmpNsList =
8392             xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8393         ctxt->context->tmpNsNr = 0;
8394         if (ctxt->context->tmpNsList != NULL) {
8395             while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8396                 ctxt->context->tmpNsNr++;
8397             }
8398         }
8399         return((xmlNodePtr) xmlXPathXMLNamespace);
8400     }
8401     if (ctxt->context->tmpNsNr > 0) {
8402         return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8403     } else {
8404         if (ctxt->context->tmpNsList != NULL)
8405             xmlFree(ctxt->context->tmpNsList);
8406         ctxt->context->tmpNsList = NULL;
8407         return(NULL);
8408     }
8409 }
8410
8411 /**
8412  * xmlXPathNextAttribute:
8413  * @ctxt:  the XPath Parser context
8414  * @cur:  the current attribute in the traversal
8415  *
8416  * Traversal function for the "attribute" direction
8417  * TODO: support DTD inherited default attributes
8418  *
8419  * Returns the next element following that axis
8420  */
8421 xmlNodePtr
8422 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8423     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8424     if (ctxt->context->node == NULL)
8425         return(NULL);
8426     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8427         return(NULL);
8428     if (cur == NULL) {
8429         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8430             return(NULL);
8431         return((xmlNodePtr)ctxt->context->node->properties);
8432     }
8433     return((xmlNodePtr)cur->next);
8434 }
8435
8436 /************************************************************************
8437  *                                                                      *
8438  *              NodeTest Functions                                      *
8439  *                                                                      *
8440  ************************************************************************/
8441
8442 #define IS_FUNCTION                     200
8443
8444
8445 /************************************************************************
8446  *                                                                      *
8447  *              Implicit tree core function library                     *
8448  *                                                                      *
8449  ************************************************************************/
8450
8451 /**
8452  * xmlXPathRoot:
8453  * @ctxt:  the XPath Parser context
8454  *
8455  * Initialize the context to the root of the document
8456  */
8457 void
8458 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8459     if ((ctxt == NULL) || (ctxt->context == NULL))
8460         return;
8461     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8462     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8463         ctxt->context->node));
8464 }
8465
8466 /************************************************************************
8467  *                                                                      *
8468  *              The explicit core function library                      *
8469  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8470  *                                                                      *
8471  ************************************************************************/
8472
8473
8474 /**
8475  * xmlXPathLastFunction:
8476  * @ctxt:  the XPath Parser context
8477  * @nargs:  the number of arguments
8478  *
8479  * Implement the last() XPath function
8480  *    number last()
8481  * The last function returns the number of nodes in the context node list.
8482  */
8483 void
8484 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8485     CHECK_ARITY(0);
8486     if (ctxt->context->contextSize >= 0) {
8487         valuePush(ctxt,
8488             xmlXPathCacheNewFloat(ctxt->context,
8489                 (double) ctxt->context->contextSize));
8490 #ifdef DEBUG_EXPR
8491         xmlGenericError(xmlGenericErrorContext,
8492                 "last() : %d\n", ctxt->context->contextSize);
8493 #endif
8494     } else {
8495         XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8496     }
8497 }
8498
8499 /**
8500  * xmlXPathPositionFunction:
8501  * @ctxt:  the XPath Parser context
8502  * @nargs:  the number of arguments
8503  *
8504  * Implement the position() XPath function
8505  *    number position()
8506  * The position function returns the position of the context node in the
8507  * context node list. The first position is 1, and so the last position
8508  * will be equal to last().
8509  */
8510 void
8511 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8512     CHECK_ARITY(0);
8513     if (ctxt->context->proximityPosition >= 0) {
8514         valuePush(ctxt,
8515               xmlXPathCacheNewFloat(ctxt->context,
8516                 (double) ctxt->context->proximityPosition));
8517 #ifdef DEBUG_EXPR
8518         xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8519                 ctxt->context->proximityPosition);
8520 #endif
8521     } else {
8522         XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8523     }
8524 }
8525
8526 /**
8527  * xmlXPathCountFunction:
8528  * @ctxt:  the XPath Parser context
8529  * @nargs:  the number of arguments
8530  *
8531  * Implement the count() XPath function
8532  *    number count(node-set)
8533  */
8534 void
8535 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8536     xmlXPathObjectPtr cur;
8537
8538     CHECK_ARITY(1);
8539     if ((ctxt->value == NULL) ||
8540         ((ctxt->value->type != XPATH_NODESET) &&
8541          (ctxt->value->type != XPATH_XSLT_TREE)))
8542         XP_ERROR(XPATH_INVALID_TYPE);
8543     cur = valuePop(ctxt);
8544
8545     if ((cur == NULL) || (cur->nodesetval == NULL))
8546         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8547     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8548         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8549             (double) cur->nodesetval->nodeNr));
8550     } else {
8551         if ((cur->nodesetval->nodeNr != 1) ||
8552             (cur->nodesetval->nodeTab == NULL)) {
8553             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8554         } else {
8555             xmlNodePtr tmp;
8556             int i = 0;
8557
8558             tmp = cur->nodesetval->nodeTab[0];
8559             if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8560                 tmp = tmp->children;
8561                 while (tmp != NULL) {
8562                     tmp = tmp->next;
8563                     i++;
8564                 }
8565             }
8566             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8567         }
8568     }
8569     xmlXPathReleaseObject(ctxt->context, cur);
8570 }
8571
8572 /**
8573  * xmlXPathGetElementsByIds:
8574  * @doc:  the document
8575  * @ids:  a whitespace separated list of IDs
8576  *
8577  * Selects elements by their unique ID.
8578  *
8579  * Returns a node-set of selected elements.
8580  */
8581 static xmlNodeSetPtr
8582 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8583     xmlNodeSetPtr ret;
8584     const xmlChar *cur = ids;
8585     xmlChar *ID;
8586     xmlAttrPtr attr;
8587     xmlNodePtr elem = NULL;
8588
8589     if (ids == NULL) return(NULL);
8590
8591     ret = xmlXPathNodeSetCreate(NULL);
8592     if (ret == NULL)
8593         return(ret);
8594
8595     while (IS_BLANK_CH(*cur)) cur++;
8596     while (*cur != 0) {
8597         while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8598             cur++;
8599
8600         ID = xmlStrndup(ids, cur - ids);
8601         if (ID != NULL) {
8602             /*
8603              * We used to check the fact that the value passed
8604              * was an NCName, but this generated much troubles for
8605              * me and Aleksey Sanin, people blatantly violated that
8606              * constaint, like Visa3D spec.
8607              * if (xmlValidateNCName(ID, 1) == 0)
8608              */
8609             attr = xmlGetID(doc, ID);
8610             if (attr != NULL) {
8611                 if (attr->type == XML_ATTRIBUTE_NODE)
8612                     elem = attr->parent;
8613                 else if (attr->type == XML_ELEMENT_NODE)
8614                     elem = (xmlNodePtr) attr;
8615                 else
8616                     elem = NULL;
8617                 if (elem != NULL)
8618                     xmlXPathNodeSetAdd(ret, elem);
8619             }
8620             xmlFree(ID);
8621         }
8622
8623         while (IS_BLANK_CH(*cur)) cur++;
8624         ids = cur;
8625     }
8626     return(ret);
8627 }
8628
8629 /**
8630  * xmlXPathIdFunction:
8631  * @ctxt:  the XPath Parser context
8632  * @nargs:  the number of arguments
8633  *
8634  * Implement the id() XPath function
8635  *    node-set id(object)
8636  * The id function selects elements by their unique ID
8637  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8638  * then the result is the union of the result of applying id to the
8639  * string value of each of the nodes in the argument node-set. When the
8640  * argument to id is of any other type, the argument is converted to a
8641  * string as if by a call to the string function; the string is split
8642  * into a whitespace-separated list of tokens (whitespace is any sequence
8643  * of characters matching the production S); the result is a node-set
8644  * containing the elements in the same document as the context node that
8645  * have a unique ID equal to any of the tokens in the list.
8646  */
8647 void
8648 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8649     xmlChar *tokens;
8650     xmlNodeSetPtr ret;
8651     xmlXPathObjectPtr obj;
8652
8653     CHECK_ARITY(1);
8654     obj = valuePop(ctxt);
8655     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8656     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8657         xmlNodeSetPtr ns;
8658         int i;
8659
8660         ret = xmlXPathNodeSetCreate(NULL);
8661         /*
8662          * FIXME -- in an out-of-memory condition this will behave badly.
8663          * The solution is not clear -- we already popped an item from
8664          * ctxt, so the object is in a corrupt state.
8665          */
8666
8667         if (obj->nodesetval != NULL) {
8668             for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8669                 tokens =
8670                     xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8671                 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8672                 ret = xmlXPathNodeSetMerge(ret, ns);
8673                 xmlXPathFreeNodeSet(ns);
8674                 if (tokens != NULL)
8675                     xmlFree(tokens);
8676             }
8677         }
8678         xmlXPathReleaseObject(ctxt->context, obj);
8679         valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8680         return;
8681     }
8682     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8683     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8684     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8685     xmlXPathReleaseObject(ctxt->context, obj);
8686     return;
8687 }
8688
8689 /**
8690  * xmlXPathLocalNameFunction:
8691  * @ctxt:  the XPath Parser context
8692  * @nargs:  the number of arguments
8693  *
8694  * Implement the local-name() XPath function
8695  *    string local-name(node-set?)
8696  * The local-name function returns a string containing the local part
8697  * of the name of the node in the argument node-set that is first in
8698  * document order. If the node-set is empty or the first node has no
8699  * name, an empty string is returned. If the argument is omitted it
8700  * defaults to the context node.
8701  */
8702 void
8703 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8704     xmlXPathObjectPtr cur;
8705
8706     if (ctxt == NULL) return;
8707
8708     if (nargs == 0) {
8709         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8710             ctxt->context->node));
8711         nargs = 1;
8712     }
8713
8714     CHECK_ARITY(1);
8715     if ((ctxt->value == NULL) ||
8716         ((ctxt->value->type != XPATH_NODESET) &&
8717          (ctxt->value->type != XPATH_XSLT_TREE)))
8718         XP_ERROR(XPATH_INVALID_TYPE);
8719     cur = valuePop(ctxt);
8720
8721     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8722         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8723     } else {
8724         int i = 0; /* Should be first in document order !!!!! */
8725         switch (cur->nodesetval->nodeTab[i]->type) {
8726         case XML_ELEMENT_NODE:
8727         case XML_ATTRIBUTE_NODE:
8728         case XML_PI_NODE:
8729             if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8730                 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8731             else
8732                 valuePush(ctxt,
8733                       xmlXPathCacheNewString(ctxt->context,
8734                         cur->nodesetval->nodeTab[i]->name));
8735             break;
8736         case XML_NAMESPACE_DECL:
8737             valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8738                         ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8739             break;
8740         default:
8741             valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8742         }
8743     }
8744     xmlXPathReleaseObject(ctxt->context, cur);
8745 }
8746
8747 /**
8748  * xmlXPathNamespaceURIFunction:
8749  * @ctxt:  the XPath Parser context
8750  * @nargs:  the number of arguments
8751  *
8752  * Implement the namespace-uri() XPath function
8753  *    string namespace-uri(node-set?)
8754  * The namespace-uri function returns a string containing the
8755  * namespace URI of the expanded name of the node in the argument
8756  * node-set that is first in document order. If the node-set is empty,
8757  * the first node has no name, or the expanded name has no namespace
8758  * URI, an empty string is returned. If the argument is omitted it
8759  * defaults to the context node.
8760  */
8761 void
8762 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8763     xmlXPathObjectPtr cur;
8764
8765     if (ctxt == NULL) return;
8766
8767     if (nargs == 0) {
8768         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8769             ctxt->context->node));
8770         nargs = 1;
8771     }
8772     CHECK_ARITY(1);
8773     if ((ctxt->value == NULL) ||
8774         ((ctxt->value->type != XPATH_NODESET) &&
8775          (ctxt->value->type != XPATH_XSLT_TREE)))
8776         XP_ERROR(XPATH_INVALID_TYPE);
8777     cur = valuePop(ctxt);
8778
8779     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8780         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8781     } else {
8782         int i = 0; /* Should be first in document order !!!!! */
8783         switch (cur->nodesetval->nodeTab[i]->type) {
8784         case XML_ELEMENT_NODE:
8785         case XML_ATTRIBUTE_NODE:
8786             if (cur->nodesetval->nodeTab[i]->ns == NULL)
8787                 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8788             else
8789                 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8790                           cur->nodesetval->nodeTab[i]->ns->href));
8791             break;
8792         default:
8793             valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8794         }
8795     }
8796     xmlXPathReleaseObject(ctxt->context, cur);
8797 }
8798
8799 /**
8800  * xmlXPathNameFunction:
8801  * @ctxt:  the XPath Parser context
8802  * @nargs:  the number of arguments
8803  *
8804  * Implement the name() XPath function
8805  *    string name(node-set?)
8806  * The name function returns a string containing a QName representing
8807  * the name of the node in the argument node-set that is first in document
8808  * order. The QName must represent the name with respect to the namespace
8809  * declarations in effect on the node whose name is being represented.
8810  * Typically, this will be the form in which the name occurred in the XML
8811  * source. This need not be the case if there are namespace declarations
8812  * in effect on the node that associate multiple prefixes with the same
8813  * namespace. However, an implementation may include information about
8814  * the original prefix in its representation of nodes; in this case, an
8815  * implementation can ensure that the returned string is always the same
8816  * as the QName used in the XML source. If the argument it omitted it
8817  * defaults to the context node.
8818  * Libxml keep the original prefix so the "real qualified name" used is
8819  * returned.
8820  */
8821 static void
8822 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8823 {
8824     xmlXPathObjectPtr cur;
8825
8826     if (nargs == 0) {
8827         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8828             ctxt->context->node));
8829         nargs = 1;
8830     }
8831
8832     CHECK_ARITY(1);
8833     if ((ctxt->value == NULL) ||
8834         ((ctxt->value->type != XPATH_NODESET) &&
8835          (ctxt->value->type != XPATH_XSLT_TREE)))
8836         XP_ERROR(XPATH_INVALID_TYPE);
8837     cur = valuePop(ctxt);
8838
8839     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8840         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8841     } else {
8842         int i = 0;              /* Should be first in document order !!!!! */
8843
8844         switch (cur->nodesetval->nodeTab[i]->type) {
8845             case XML_ELEMENT_NODE:
8846             case XML_ATTRIBUTE_NODE:
8847                 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8848                     valuePush(ctxt,
8849                         xmlXPathCacheNewCString(ctxt->context, ""));
8850                 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8851                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8852                     valuePush(ctxt,
8853                         xmlXPathCacheNewString(ctxt->context,
8854                             cur->nodesetval->nodeTab[i]->name));
8855                 } else {
8856                     xmlChar *fullname;
8857
8858                     fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8859                                      cur->nodesetval->nodeTab[i]->ns->prefix,
8860                                      NULL, 0);
8861                     if (fullname == cur->nodesetval->nodeTab[i]->name)
8862                         fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8863                     if (fullname == NULL) {
8864                         XP_ERROR(XPATH_MEMORY_ERROR);
8865                     }
8866                     valuePush(ctxt, xmlXPathCacheWrapString(
8867                         ctxt->context, fullname));
8868                 }
8869                 break;
8870             default:
8871                 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8872                     cur->nodesetval->nodeTab[i]));
8873                 xmlXPathLocalNameFunction(ctxt, 1);
8874         }
8875     }
8876     xmlXPathReleaseObject(ctxt->context, cur);
8877 }
8878
8879
8880 /**
8881  * xmlXPathStringFunction:
8882  * @ctxt:  the XPath Parser context
8883  * @nargs:  the number of arguments
8884  *
8885  * Implement the string() XPath function
8886  *    string string(object?)
8887  * The string function converts an object to a string as follows:
8888  *    - A node-set is converted to a string by returning the value of
8889  *      the node in the node-set that is first in document order.
8890  *      If the node-set is empty, an empty string is returned.
8891  *    - A number is converted to a string as follows
8892  *      + NaN is converted to the string NaN
8893  *      + positive zero is converted to the string 0
8894  *      + negative zero is converted to the string 0
8895  *      + positive infinity is converted to the string Infinity
8896  *      + negative infinity is converted to the string -Infinity
8897  *      + if the number is an integer, the number is represented in
8898  *        decimal form as a Number with no decimal point and no leading
8899  *        zeros, preceded by a minus sign (-) if the number is negative
8900  *      + otherwise, the number is represented in decimal form as a
8901  *        Number including a decimal point with at least one digit
8902  *        before the decimal point and at least one digit after the
8903  *        decimal point, preceded by a minus sign (-) if the number
8904  *        is negative; there must be no leading zeros before the decimal
8905  *        point apart possibly from the one required digit immediately
8906  *        before the decimal point; beyond the one required digit
8907  *        after the decimal point there must be as many, but only as
8908  *        many, more digits as are needed to uniquely distinguish the
8909  *        number from all other IEEE 754 numeric values.
8910  *    - The boolean false value is converted to the string false.
8911  *      The boolean true value is converted to the string true.
8912  *
8913  * If the argument is omitted, it defaults to a node-set with the
8914  * context node as its only member.
8915  */
8916 void
8917 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8918     xmlXPathObjectPtr cur;
8919
8920     if (ctxt == NULL) return;
8921     if (nargs == 0) {
8922     valuePush(ctxt,
8923         xmlXPathCacheWrapString(ctxt->context,
8924             xmlXPathCastNodeToString(ctxt->context->node)));
8925         return;
8926     }
8927
8928     CHECK_ARITY(1);
8929     cur = valuePop(ctxt);
8930     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8931     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8932 }
8933
8934 /**
8935  * xmlXPathStringLengthFunction:
8936  * @ctxt:  the XPath Parser context
8937  * @nargs:  the number of arguments
8938  *
8939  * Implement the string-length() XPath function
8940  *    number string-length(string?)
8941  * The string-length returns the number of characters in the string
8942  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8943  * the context node converted to a string, in other words the value
8944  * of the context node.
8945  */
8946 void
8947 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8948     xmlXPathObjectPtr cur;
8949
8950     if (nargs == 0) {
8951         if ((ctxt == NULL) || (ctxt->context == NULL))
8952             return;
8953         if (ctxt->context->node == NULL) {
8954             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8955         } else {
8956             xmlChar *content;
8957
8958             content = xmlXPathCastNodeToString(ctxt->context->node);
8959             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8960                 xmlUTF8Strlen(content)));
8961             xmlFree(content);
8962         }
8963         return;
8964     }
8965     CHECK_ARITY(1);
8966     CAST_TO_STRING;
8967     CHECK_TYPE(XPATH_STRING);
8968     cur = valuePop(ctxt);
8969     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8970         xmlUTF8Strlen(cur->stringval)));
8971     xmlXPathReleaseObject(ctxt->context, cur);
8972 }
8973
8974 /**
8975  * xmlXPathConcatFunction:
8976  * @ctxt:  the XPath Parser context
8977  * @nargs:  the number of arguments
8978  *
8979  * Implement the concat() XPath function
8980  *    string concat(string, string, string*)
8981  * The concat function returns the concatenation of its arguments.
8982  */
8983 void
8984 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8985     xmlXPathObjectPtr cur, newobj;
8986     xmlChar *tmp;
8987
8988     if (ctxt == NULL) return;
8989     if (nargs < 2) {
8990         CHECK_ARITY(2);
8991     }
8992
8993     CAST_TO_STRING;
8994     cur = valuePop(ctxt);
8995     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8996         xmlXPathReleaseObject(ctxt->context, cur);
8997         return;
8998     }
8999     nargs--;
9000
9001     while (nargs > 0) {
9002         CAST_TO_STRING;
9003         newobj = valuePop(ctxt);
9004         if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9005             xmlXPathReleaseObject(ctxt->context, newobj);
9006             xmlXPathReleaseObject(ctxt->context, cur);
9007             XP_ERROR(XPATH_INVALID_TYPE);
9008         }
9009         tmp = xmlStrcat(newobj->stringval, cur->stringval);
9010         newobj->stringval = cur->stringval;
9011         cur->stringval = tmp;
9012         xmlXPathReleaseObject(ctxt->context, newobj);
9013         nargs--;
9014     }
9015     valuePush(ctxt, cur);
9016 }
9017
9018 /**
9019  * xmlXPathContainsFunction:
9020  * @ctxt:  the XPath Parser context
9021  * @nargs:  the number of arguments
9022  *
9023  * Implement the contains() XPath function
9024  *    boolean contains(string, string)
9025  * The contains function returns true if the first argument string
9026  * contains the second argument string, and otherwise returns false.
9027  */
9028 void
9029 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9030     xmlXPathObjectPtr hay, needle;
9031
9032     CHECK_ARITY(2);
9033     CAST_TO_STRING;
9034     CHECK_TYPE(XPATH_STRING);
9035     needle = valuePop(ctxt);
9036     CAST_TO_STRING;
9037     hay = valuePop(ctxt);
9038
9039     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9040         xmlXPathReleaseObject(ctxt->context, hay);
9041         xmlXPathReleaseObject(ctxt->context, needle);
9042         XP_ERROR(XPATH_INVALID_TYPE);
9043     }
9044     if (xmlStrstr(hay->stringval, needle->stringval))
9045         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9046     else
9047         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9048     xmlXPathReleaseObject(ctxt->context, hay);
9049     xmlXPathReleaseObject(ctxt->context, needle);
9050 }
9051
9052 /**
9053  * xmlXPathStartsWithFunction:
9054  * @ctxt:  the XPath Parser context
9055  * @nargs:  the number of arguments
9056  *
9057  * Implement the starts-with() XPath function
9058  *    boolean starts-with(string, string)
9059  * The starts-with function returns true if the first argument string
9060  * starts with the second argument string, and otherwise returns false.
9061  */
9062 void
9063 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9064     xmlXPathObjectPtr hay, needle;
9065     int n;
9066
9067     CHECK_ARITY(2);
9068     CAST_TO_STRING;
9069     CHECK_TYPE(XPATH_STRING);
9070     needle = valuePop(ctxt);
9071     CAST_TO_STRING;
9072     hay = valuePop(ctxt);
9073
9074     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9075         xmlXPathReleaseObject(ctxt->context, hay);
9076         xmlXPathReleaseObject(ctxt->context, needle);
9077         XP_ERROR(XPATH_INVALID_TYPE);
9078     }
9079     n = xmlStrlen(needle->stringval);
9080     if (xmlStrncmp(hay->stringval, needle->stringval, n))
9081         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9082     else
9083         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9084     xmlXPathReleaseObject(ctxt->context, hay);
9085     xmlXPathReleaseObject(ctxt->context, needle);
9086 }
9087
9088 /**
9089  * xmlXPathSubstringFunction:
9090  * @ctxt:  the XPath Parser context
9091  * @nargs:  the number of arguments
9092  *
9093  * Implement the substring() XPath function
9094  *    string substring(string, number, number?)
9095  * The substring function returns the substring of the first argument
9096  * starting at the position specified in the second argument with
9097  * length specified in the third argument. For example,
9098  * substring("12345",2,3) returns "234". If the third argument is not
9099  * specified, it returns the substring starting at the position specified
9100  * in the second argument and continuing to the end of the string. For
9101  * example, substring("12345",2) returns "2345".  More precisely, each
9102  * character in the string (see [3.6 Strings]) is considered to have a
9103  * numeric position: the position of the first character is 1, the position
9104  * of the second character is 2 and so on. The returned substring contains
9105  * those characters for which the position of the character is greater than
9106  * or equal to the second argument and, if the third argument is specified,
9107  * less than the sum of the second and third arguments; the comparisons
9108  * and addition used for the above follow the standard IEEE 754 rules. Thus:
9109  *  - substring("12345", 1.5, 2.6) returns "234"
9110  *  - substring("12345", 0, 3) returns "12"
9111  *  - substring("12345", 0 div 0, 3) returns ""
9112  *  - substring("12345", 1, 0 div 0) returns ""
9113  *  - substring("12345", -42, 1 div 0) returns "12345"
9114  *  - substring("12345", -1 div 0, 1 div 0) returns ""
9115  */
9116 void
9117 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9118     xmlXPathObjectPtr str, start, len;
9119     double le=0, in;
9120     int i, l, m;
9121     xmlChar *ret;
9122
9123     if (nargs < 2) {
9124         CHECK_ARITY(2);
9125     }
9126     if (nargs > 3) {
9127         CHECK_ARITY(3);
9128     }
9129     /*
9130      * take care of possible last (position) argument
9131     */
9132     if (nargs == 3) {
9133         CAST_TO_NUMBER;
9134         CHECK_TYPE(XPATH_NUMBER);
9135         len = valuePop(ctxt);
9136         le = len->floatval;
9137         xmlXPathReleaseObject(ctxt->context, len);
9138     }
9139
9140     CAST_TO_NUMBER;
9141     CHECK_TYPE(XPATH_NUMBER);
9142     start = valuePop(ctxt);
9143     in = start->floatval;
9144     xmlXPathReleaseObject(ctxt->context, start);
9145     CAST_TO_STRING;
9146     CHECK_TYPE(XPATH_STRING);
9147     str = valuePop(ctxt);
9148     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9149
9150     /*
9151      * If last pos not present, calculate last position
9152     */
9153     if (nargs != 3) {
9154         le = (double)m;
9155         if (in < 1.0)
9156             in = 1.0;
9157     }
9158
9159     /* Need to check for the special cases where either
9160      * the index is NaN, the length is NaN, or both
9161      * arguments are infinity (relying on Inf + -Inf = NaN)
9162      */
9163     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9164         /*
9165          * To meet the requirements of the spec, the arguments
9166          * must be converted to integer format before
9167          * initial index calculations are done
9168          *
9169          * First we go to integer form, rounding up
9170          * and checking for special cases
9171          */
9172         i = (int) in;
9173         if (((double)i)+0.5 <= in) i++;
9174
9175         if (xmlXPathIsInf(le) == 1) {
9176             l = m;
9177             if (i < 1)
9178                 i = 1;
9179         }
9180         else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9181             l = 0;
9182         else {
9183             l = (int) le;
9184             if (((double)l)+0.5 <= le) l++;
9185         }
9186
9187         /* Now we normalize inidices */
9188         i -= 1;
9189         l += i;
9190         if (i < 0)
9191             i = 0;
9192         if (l > m)
9193             l = m;
9194
9195         /* number of chars to copy */
9196         l -= i;
9197
9198         ret = xmlUTF8Strsub(str->stringval, i, l);
9199     }
9200     else {
9201         ret = NULL;
9202     }
9203     if (ret == NULL)
9204         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9205     else {
9206         valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9207         xmlFree(ret);
9208     }
9209     xmlXPathReleaseObject(ctxt->context, str);
9210 }
9211
9212 /**
9213  * xmlXPathSubstringBeforeFunction:
9214  * @ctxt:  the XPath Parser context
9215  * @nargs:  the number of arguments
9216  *
9217  * Implement the substring-before() XPath function
9218  *    string substring-before(string, string)
9219  * The substring-before function returns the substring of the first
9220  * argument string that precedes the first occurrence of the second
9221  * argument string in the first argument string, or the empty string
9222  * if the first argument string does not contain the second argument
9223  * string. For example, substring-before("1999/04/01","/") returns 1999.
9224  */
9225 void
9226 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9227   xmlXPathObjectPtr str;
9228   xmlXPathObjectPtr find;
9229   xmlBufPtr target;
9230   const xmlChar *point;
9231   int offset;
9232
9233   CHECK_ARITY(2);
9234   CAST_TO_STRING;
9235   find = valuePop(ctxt);
9236   CAST_TO_STRING;
9237   str = valuePop(ctxt);
9238
9239   target = xmlBufCreate();
9240   if (target) {
9241     point = xmlStrstr(str->stringval, find->stringval);
9242     if (point) {
9243       offset = (int)(point - str->stringval);
9244       xmlBufAdd(target, str->stringval, offset);
9245     }
9246     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9247         xmlBufContent(target)));
9248     xmlBufFree(target);
9249   }
9250   xmlXPathReleaseObject(ctxt->context, str);
9251   xmlXPathReleaseObject(ctxt->context, find);
9252 }
9253
9254 /**
9255  * xmlXPathSubstringAfterFunction:
9256  * @ctxt:  the XPath Parser context
9257  * @nargs:  the number of arguments
9258  *
9259  * Implement the substring-after() XPath function
9260  *    string substring-after(string, string)
9261  * The substring-after function returns the substring of the first
9262  * argument string that follows the first occurrence of the second
9263  * argument string in the first argument string, or the empty stringi
9264  * if the first argument string does not contain the second argument
9265  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9266  * and substring-after("1999/04/01","19") returns 99/04/01.
9267  */
9268 void
9269 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9270   xmlXPathObjectPtr str;
9271   xmlXPathObjectPtr find;
9272   xmlBufPtr target;
9273   const xmlChar *point;
9274   int offset;
9275
9276   CHECK_ARITY(2);
9277   CAST_TO_STRING;
9278   find = valuePop(ctxt);
9279   CAST_TO_STRING;
9280   str = valuePop(ctxt);
9281
9282   target = xmlBufCreate();
9283   if (target) {
9284     point = xmlStrstr(str->stringval, find->stringval);
9285     if (point) {
9286       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9287       xmlBufAdd(target, &str->stringval[offset],
9288                    xmlStrlen(str->stringval) - offset);
9289     }
9290     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9291         xmlBufContent(target)));
9292     xmlBufFree(target);
9293   }
9294   xmlXPathReleaseObject(ctxt->context, str);
9295   xmlXPathReleaseObject(ctxt->context, find);
9296 }
9297
9298 /**
9299  * xmlXPathNormalizeFunction:
9300  * @ctxt:  the XPath Parser context
9301  * @nargs:  the number of arguments
9302  *
9303  * Implement the normalize-space() XPath function
9304  *    string normalize-space(string?)
9305  * The normalize-space function returns the argument string with white
9306  * space normalized by stripping leading and trailing whitespace
9307  * and replacing sequences of whitespace characters by a single
9308  * space. Whitespace characters are the same allowed by the S production
9309  * in XML. If the argument is omitted, it defaults to the context
9310  * node converted to a string, in other words the value of the context node.
9311  */
9312 void
9313 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9314   xmlXPathObjectPtr obj = NULL;
9315   xmlChar *source = NULL;
9316   xmlBufPtr target;
9317   xmlChar blank;
9318
9319   if (ctxt == NULL) return;
9320   if (nargs == 0) {
9321     /* Use current context node */
9322       valuePush(ctxt,
9323           xmlXPathCacheWrapString(ctxt->context,
9324             xmlXPathCastNodeToString(ctxt->context->node)));
9325     nargs = 1;
9326   }
9327
9328   CHECK_ARITY(1);
9329   CAST_TO_STRING;
9330   CHECK_TYPE(XPATH_STRING);
9331   obj = valuePop(ctxt);
9332   source = obj->stringval;
9333
9334   target = xmlBufCreate();
9335   if (target && source) {
9336
9337     /* Skip leading whitespaces */
9338     while (IS_BLANK_CH(*source))
9339       source++;
9340
9341     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9342     blank = 0;
9343     while (*source) {
9344       if (IS_BLANK_CH(*source)) {
9345         blank = 0x20;
9346       } else {
9347         if (blank) {
9348           xmlBufAdd(target, &blank, 1);
9349           blank = 0;
9350         }
9351         xmlBufAdd(target, source, 1);
9352       }
9353       source++;
9354     }
9355     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9356         xmlBufContent(target)));
9357     xmlBufFree(target);
9358   }
9359   xmlXPathReleaseObject(ctxt->context, obj);
9360 }
9361
9362 /**
9363  * xmlXPathTranslateFunction:
9364  * @ctxt:  the XPath Parser context
9365  * @nargs:  the number of arguments
9366  *
9367  * Implement the translate() XPath function
9368  *    string translate(string, string, string)
9369  * The translate function returns the first argument string with
9370  * occurrences of characters in the second argument string replaced
9371  * by the character at the corresponding position in the third argument
9372  * string. For example, translate("bar","abc","ABC") returns the string
9373  * BAr. If there is a character in the second argument string with no
9374  * character at a corresponding position in the third argument string
9375  * (because the second argument string is longer than the third argument
9376  * string), then occurrences of that character in the first argument
9377  * string are removed. For example, translate("--aaa--","abc-","ABC")
9378  * returns "AAA". If a character occurs more than once in second
9379  * argument string, then the first occurrence determines the replacement
9380  * character. If the third argument string is longer than the second
9381  * argument string, then excess characters are ignored.
9382  */
9383 void
9384 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9385     xmlXPathObjectPtr str;
9386     xmlXPathObjectPtr from;
9387     xmlXPathObjectPtr to;
9388     xmlBufPtr target;
9389     int offset, max;
9390     xmlChar ch;
9391     const xmlChar *point;
9392     xmlChar *cptr;
9393
9394     CHECK_ARITY(3);
9395
9396     CAST_TO_STRING;
9397     to = valuePop(ctxt);
9398     CAST_TO_STRING;
9399     from = valuePop(ctxt);
9400     CAST_TO_STRING;
9401     str = valuePop(ctxt);
9402
9403     target = xmlBufCreate();
9404     if (target) {
9405         max = xmlUTF8Strlen(to->stringval);
9406         for (cptr = str->stringval; (ch=*cptr); ) {
9407             offset = xmlUTF8Strloc(from->stringval, cptr);
9408             if (offset >= 0) {
9409                 if (offset < max) {
9410                     point = xmlUTF8Strpos(to->stringval, offset);
9411                     if (point)
9412                         xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9413                 }
9414             } else
9415                 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9416
9417             /* Step to next character in input */
9418             cptr++;
9419             if ( ch & 0x80 ) {
9420                 /* if not simple ascii, verify proper format */
9421                 if ( (ch & 0xc0) != 0xc0 ) {
9422                     xmlGenericError(xmlGenericErrorContext,
9423                         "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9424                     /* not asserting an XPath error is probably better */
9425                     break;
9426                 }
9427                 /* then skip over remaining bytes for this char */
9428                 while ( (ch <<= 1) & 0x80 )
9429                     if ( (*cptr++ & 0xc0) != 0x80 ) {
9430                         xmlGenericError(xmlGenericErrorContext,
9431                             "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9432                         /* not asserting an XPath error is probably better */
9433                         break;
9434                     }
9435                 if (ch & 0x80) /* must have had error encountered */
9436                     break;
9437             }
9438         }
9439     }
9440     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9441         xmlBufContent(target)));
9442     xmlBufFree(target);
9443     xmlXPathReleaseObject(ctxt->context, str);
9444     xmlXPathReleaseObject(ctxt->context, from);
9445     xmlXPathReleaseObject(ctxt->context, to);
9446 }
9447
9448 /**
9449  * xmlXPathBooleanFunction:
9450  * @ctxt:  the XPath Parser context
9451  * @nargs:  the number of arguments
9452  *
9453  * Implement the boolean() XPath function
9454  *    boolean boolean(object)
9455  * The boolean function converts its argument to a boolean as follows:
9456  *    - a number is true if and only if it is neither positive or
9457  *      negative zero nor NaN
9458  *    - a node-set is true if and only if it is non-empty
9459  *    - a string is true if and only if its length is non-zero
9460  */
9461 void
9462 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9463     xmlXPathObjectPtr cur;
9464
9465     CHECK_ARITY(1);
9466     cur = valuePop(ctxt);
9467     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9468     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9469     valuePush(ctxt, cur);
9470 }
9471
9472 /**
9473  * xmlXPathNotFunction:
9474  * @ctxt:  the XPath Parser context
9475  * @nargs:  the number of arguments
9476  *
9477  * Implement the not() XPath function
9478  *    boolean not(boolean)
9479  * The not function returns true if its argument is false,
9480  * and false otherwise.
9481  */
9482 void
9483 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9484     CHECK_ARITY(1);
9485     CAST_TO_BOOLEAN;
9486     CHECK_TYPE(XPATH_BOOLEAN);
9487     ctxt->value->boolval = ! ctxt->value->boolval;
9488 }
9489
9490 /**
9491  * xmlXPathTrueFunction:
9492  * @ctxt:  the XPath Parser context
9493  * @nargs:  the number of arguments
9494  *
9495  * Implement the true() XPath function
9496  *    boolean true()
9497  */
9498 void
9499 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9500     CHECK_ARITY(0);
9501     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9502 }
9503
9504 /**
9505  * xmlXPathFalseFunction:
9506  * @ctxt:  the XPath Parser context
9507  * @nargs:  the number of arguments
9508  *
9509  * Implement the false() XPath function
9510  *    boolean false()
9511  */
9512 void
9513 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9514     CHECK_ARITY(0);
9515     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9516 }
9517
9518 /**
9519  * xmlXPathLangFunction:
9520  * @ctxt:  the XPath Parser context
9521  * @nargs:  the number of arguments
9522  *
9523  * Implement the lang() XPath function
9524  *    boolean lang(string)
9525  * The lang function returns true or false depending on whether the
9526  * language of the context node as specified by xml:lang attributes
9527  * is the same as or is a sublanguage of the language specified by
9528  * the argument string. The language of the context node is determined
9529  * by the value of the xml:lang attribute on the context node, or, if
9530  * the context node has no xml:lang attribute, by the value of the
9531  * xml:lang attribute on the nearest ancestor of the context node that
9532  * has an xml:lang attribute. If there is no such attribute, then lang
9533  * returns false. If there is such an attribute, then lang returns
9534  * true if the attribute value is equal to the argument ignoring case,
9535  * or if there is some suffix starting with - such that the attribute
9536  * value is equal to the argument ignoring that suffix of the attribute
9537  * value and ignoring case.
9538  */
9539 void
9540 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9541     xmlXPathObjectPtr val = NULL;
9542     const xmlChar *theLang = NULL;
9543     const xmlChar *lang;
9544     int ret = 0;
9545     int i;
9546
9547     CHECK_ARITY(1);
9548     CAST_TO_STRING;
9549     CHECK_TYPE(XPATH_STRING);
9550     val = valuePop(ctxt);
9551     lang = val->stringval;
9552     theLang = xmlNodeGetLang(ctxt->context->node);
9553     if ((theLang != NULL) && (lang != NULL)) {
9554         for (i = 0;lang[i] != 0;i++)
9555             if (toupper(lang[i]) != toupper(theLang[i]))
9556                 goto not_equal;
9557         if ((theLang[i] == 0) || (theLang[i] == '-'))
9558             ret = 1;
9559     }
9560 not_equal:
9561     if (theLang != NULL)
9562         xmlFree((void *)theLang);
9563
9564     xmlXPathReleaseObject(ctxt->context, val);
9565     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9566 }
9567
9568 /**
9569  * xmlXPathNumberFunction:
9570  * @ctxt:  the XPath Parser context
9571  * @nargs:  the number of arguments
9572  *
9573  * Implement the number() XPath function
9574  *    number number(object?)
9575  */
9576 void
9577 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9578     xmlXPathObjectPtr cur;
9579     double res;
9580
9581     if (ctxt == NULL) return;
9582     if (nargs == 0) {
9583         if (ctxt->context->node == NULL) {
9584             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9585         } else {
9586             xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9587
9588             res = xmlXPathStringEvalNumber(content);
9589             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9590             xmlFree(content);
9591         }
9592         return;
9593     }
9594
9595     CHECK_ARITY(1);
9596     cur = valuePop(ctxt);
9597     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9598 }
9599
9600 /**
9601  * xmlXPathSumFunction:
9602  * @ctxt:  the XPath Parser context
9603  * @nargs:  the number of arguments
9604  *
9605  * Implement the sum() XPath function
9606  *    number sum(node-set)
9607  * The sum function returns the sum of the values of the nodes in
9608  * the argument node-set.
9609  */
9610 void
9611 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9612     xmlXPathObjectPtr cur;
9613     int i;
9614     double res = 0.0;
9615
9616     CHECK_ARITY(1);
9617     if ((ctxt->value == NULL) ||
9618         ((ctxt->value->type != XPATH_NODESET) &&
9619          (ctxt->value->type != XPATH_XSLT_TREE)))
9620         XP_ERROR(XPATH_INVALID_TYPE);
9621     cur = valuePop(ctxt);
9622
9623     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9624         for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9625             res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9626         }
9627     }
9628     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9629     xmlXPathReleaseObject(ctxt->context, cur);
9630 }
9631
9632 /*
9633  * To assure working code on multiple platforms, we want to only depend
9634  * upon the characteristic truncation of converting a floating point value
9635  * to an integer.  Unfortunately, because of the different storage sizes
9636  * of our internal floating point value (double) and integer (int), we
9637  * can't directly convert (see bug 301162).  This macro is a messy
9638  * 'workaround'
9639  */
9640 #define XTRUNC(f, v)            \
9641     f = fmod((v), INT_MAX);     \
9642     f = (v) - (f) + (double)((int)(f));
9643
9644 /**
9645  * xmlXPathFloorFunction:
9646  * @ctxt:  the XPath Parser context
9647  * @nargs:  the number of arguments
9648  *
9649  * Implement the floor() XPath function
9650  *    number floor(number)
9651  * The floor function returns the largest (closest to positive infinity)
9652  * number that is not greater than the argument and that is an integer.
9653  */
9654 void
9655 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9656     double f;
9657
9658     CHECK_ARITY(1);
9659     CAST_TO_NUMBER;
9660     CHECK_TYPE(XPATH_NUMBER);
9661
9662     XTRUNC(f, ctxt->value->floatval);
9663     if (f != ctxt->value->floatval) {
9664         if (ctxt->value->floatval > 0)
9665             ctxt->value->floatval = f;
9666         else
9667             ctxt->value->floatval = f - 1;
9668     }
9669 }
9670
9671 /**
9672  * xmlXPathCeilingFunction:
9673  * @ctxt:  the XPath Parser context
9674  * @nargs:  the number of arguments
9675  *
9676  * Implement the ceiling() XPath function
9677  *    number ceiling(number)
9678  * The ceiling function returns the smallest (closest to negative infinity)
9679  * number that is not less than the argument and that is an integer.
9680  */
9681 void
9682 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9683     double f;
9684
9685     CHECK_ARITY(1);
9686     CAST_TO_NUMBER;
9687     CHECK_TYPE(XPATH_NUMBER);
9688
9689 #if 0
9690     ctxt->value->floatval = ceil(ctxt->value->floatval);
9691 #else
9692     XTRUNC(f, ctxt->value->floatval);
9693     if (f != ctxt->value->floatval) {
9694         if (ctxt->value->floatval > 0)
9695             ctxt->value->floatval = f + 1;
9696         else {
9697             if (ctxt->value->floatval < 0 && f == 0)
9698                 ctxt->value->floatval = xmlXPathNZERO;
9699             else
9700                 ctxt->value->floatval = f;
9701         }
9702
9703     }
9704 #endif
9705 }
9706
9707 /**
9708  * xmlXPathRoundFunction:
9709  * @ctxt:  the XPath Parser context
9710  * @nargs:  the number of arguments
9711  *
9712  * Implement the round() XPath function
9713  *    number round(number)
9714  * The round function returns the number that is closest to the
9715  * argument and that is an integer. If there are two such numbers,
9716  * then the one that is even is returned.
9717  */
9718 void
9719 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9720     double f;
9721
9722     CHECK_ARITY(1);
9723     CAST_TO_NUMBER;
9724     CHECK_TYPE(XPATH_NUMBER);
9725
9726     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9727         (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9728         (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9729         (ctxt->value->floatval == 0.0))
9730         return;
9731
9732     XTRUNC(f, ctxt->value->floatval);
9733     if (ctxt->value->floatval < 0) {
9734         if (ctxt->value->floatval < f - 0.5)
9735             ctxt->value->floatval = f - 1;
9736         else
9737             ctxt->value->floatval = f;
9738         if (ctxt->value->floatval == 0)
9739             ctxt->value->floatval = xmlXPathNZERO;
9740     } else {
9741         if (ctxt->value->floatval < f + 0.5)
9742             ctxt->value->floatval = f;
9743         else
9744             ctxt->value->floatval = f + 1;
9745     }
9746 }
9747
9748 /************************************************************************
9749  *                                                                      *
9750  *                      The Parser                                      *
9751  *                                                                      *
9752  ************************************************************************/
9753
9754 /*
9755  * a few forward declarations since we use a recursive call based
9756  * implementation.
9757  */
9758 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9759 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9760 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9761 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9762 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9763                                           int qualified);
9764
9765 /**
9766  * xmlXPathCurrentChar:
9767  * @ctxt:  the XPath parser context
9768  * @cur:  pointer to the beginning of the char
9769  * @len:  pointer to the length of the char read
9770  *
9771  * The current char value, if using UTF-8 this may actually span multiple
9772  * bytes in the input buffer.
9773  *
9774  * Returns the current char value and its length
9775  */
9776
9777 static int
9778 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9779     unsigned char c;
9780     unsigned int val;
9781     const xmlChar *cur;
9782
9783     if (ctxt == NULL)
9784         return(0);
9785     cur = ctxt->cur;
9786
9787     /*
9788      * We are supposed to handle UTF8, check it's valid
9789      * From rfc2044: encoding of the Unicode values on UTF-8:
9790      *
9791      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9792      * 0000 0000-0000 007F   0xxxxxxx
9793      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9794      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9795      *
9796      * Check for the 0x110000 limit too
9797      */
9798     c = *cur;
9799     if (c & 0x80) {
9800         if ((cur[1] & 0xc0) != 0x80)
9801             goto encoding_error;
9802         if ((c & 0xe0) == 0xe0) {
9803
9804             if ((cur[2] & 0xc0) != 0x80)
9805                 goto encoding_error;
9806             if ((c & 0xf0) == 0xf0) {
9807                 if (((c & 0xf8) != 0xf0) ||
9808                     ((cur[3] & 0xc0) != 0x80))
9809                     goto encoding_error;
9810                 /* 4-byte code */
9811                 *len = 4;
9812                 val = (cur[0] & 0x7) << 18;
9813                 val |= (cur[1] & 0x3f) << 12;
9814                 val |= (cur[2] & 0x3f) << 6;
9815                 val |= cur[3] & 0x3f;
9816             } else {
9817               /* 3-byte code */
9818                 *len = 3;
9819                 val = (cur[0] & 0xf) << 12;
9820                 val |= (cur[1] & 0x3f) << 6;
9821                 val |= cur[2] & 0x3f;
9822             }
9823         } else {
9824           /* 2-byte code */
9825             *len = 2;
9826             val = (cur[0] & 0x1f) << 6;
9827             val |= cur[1] & 0x3f;
9828         }
9829         if (!IS_CHAR(val)) {
9830             XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9831         }
9832         return(val);
9833     } else {
9834         /* 1-byte code */
9835         *len = 1;
9836         return((int) *cur);
9837     }
9838 encoding_error:
9839     /*
9840      * If we detect an UTF8 error that probably means that the
9841      * input encoding didn't get properly advertised in the
9842      * declaration header. Report the error and switch the encoding
9843      * to ISO-Latin-1 (if you don't like this policy, just declare the
9844      * encoding !)
9845      */
9846     *len = 0;
9847     XP_ERROR0(XPATH_ENCODING_ERROR);
9848 }
9849
9850 /**
9851  * xmlXPathParseNCName:
9852  * @ctxt:  the XPath Parser context
9853  *
9854  * parse an XML namespace non qualified name.
9855  *
9856  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9857  *
9858  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9859  *                       CombiningChar | Extender
9860  *
9861  * Returns the namespace name or NULL
9862  */
9863
9864 xmlChar *
9865 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9866     const xmlChar *in;
9867     xmlChar *ret;
9868     int count = 0;
9869
9870     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9871     /*
9872      * Accelerator for simple ASCII names
9873      */
9874     in = ctxt->cur;
9875     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9876         ((*in >= 0x41) && (*in <= 0x5A)) ||
9877         (*in == '_')) {
9878         in++;
9879         while (((*in >= 0x61) && (*in <= 0x7A)) ||
9880                ((*in >= 0x41) && (*in <= 0x5A)) ||
9881                ((*in >= 0x30) && (*in <= 0x39)) ||
9882                (*in == '_') || (*in == '.') ||
9883                (*in == '-'))
9884             in++;
9885         if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9886             (*in == '[') || (*in == ']') || (*in == ':') ||
9887             (*in == '@') || (*in == '*')) {
9888             count = in - ctxt->cur;
9889             if (count == 0)
9890                 return(NULL);
9891             ret = xmlStrndup(ctxt->cur, count);
9892             ctxt->cur = in;
9893             return(ret);
9894         }
9895     }
9896     return(xmlXPathParseNameComplex(ctxt, 0));
9897 }
9898
9899
9900 /**
9901  * xmlXPathParseQName:
9902  * @ctxt:  the XPath Parser context
9903  * @prefix:  a xmlChar **
9904  *
9905  * parse an XML qualified name
9906  *
9907  * [NS 5] QName ::= (Prefix ':')? LocalPart
9908  *
9909  * [NS 6] Prefix ::= NCName
9910  *
9911  * [NS 7] LocalPart ::= NCName
9912  *
9913  * Returns the function returns the local part, and prefix is updated
9914  *   to get the Prefix if any.
9915  */
9916
9917 static xmlChar *
9918 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9919     xmlChar *ret = NULL;
9920
9921     *prefix = NULL;
9922     ret = xmlXPathParseNCName(ctxt);
9923     if (ret && CUR == ':') {
9924         *prefix = ret;
9925         NEXT;
9926         ret = xmlXPathParseNCName(ctxt);
9927     }
9928     return(ret);
9929 }
9930
9931 /**
9932  * xmlXPathParseName:
9933  * @ctxt:  the XPath Parser context
9934  *
9935  * parse an XML name
9936  *
9937  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9938  *                  CombiningChar | Extender
9939  *
9940  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9941  *
9942  * Returns the namespace name or NULL
9943  */
9944
9945 xmlChar *
9946 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9947     const xmlChar *in;
9948     xmlChar *ret;
9949     size_t count = 0;
9950
9951     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9952     /*
9953      * Accelerator for simple ASCII names
9954      */
9955     in = ctxt->cur;
9956     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9957         ((*in >= 0x41) && (*in <= 0x5A)) ||
9958         (*in == '_') || (*in == ':')) {
9959         in++;
9960         while (((*in >= 0x61) && (*in <= 0x7A)) ||
9961                ((*in >= 0x41) && (*in <= 0x5A)) ||
9962                ((*in >= 0x30) && (*in <= 0x39)) ||
9963                (*in == '_') || (*in == '-') ||
9964                (*in == ':') || (*in == '.'))
9965             in++;
9966         if ((*in > 0) && (*in < 0x80)) {
9967             count = in - ctxt->cur;
9968             if (count > XML_MAX_NAME_LENGTH) {
9969                 ctxt->cur = in;
9970                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9971             }
9972             ret = xmlStrndup(ctxt->cur, count);
9973             ctxt->cur = in;
9974             return(ret);
9975         }
9976     }
9977     return(xmlXPathParseNameComplex(ctxt, 1));
9978 }
9979
9980 static xmlChar *
9981 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9982     xmlChar buf[XML_MAX_NAMELEN + 5];
9983     int len = 0, l;
9984     int c;
9985
9986     /*
9987      * Handler for more complex cases
9988      */
9989     c = CUR_CHAR(l);
9990     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9991         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9992         (c == '*') || /* accelerators */
9993         (!IS_LETTER(c) && (c != '_') &&
9994          ((qualified) && (c != ':')))) {
9995         return(NULL);
9996     }
9997
9998     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9999            ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10000             (c == '.') || (c == '-') ||
10001             (c == '_') || ((qualified) && (c == ':')) ||
10002             (IS_COMBINING(c)) ||
10003             (IS_EXTENDER(c)))) {
10004         COPY_BUF(l,buf,len,c);
10005         NEXTL(l);
10006         c = CUR_CHAR(l);
10007         if (len >= XML_MAX_NAMELEN) {
10008             /*
10009              * Okay someone managed to make a huge name, so he's ready to pay
10010              * for the processing speed.
10011              */
10012             xmlChar *buffer;
10013             int max = len * 2;
10014
10015             if (len > XML_MAX_NAME_LENGTH) {
10016                 XP_ERRORNULL(XPATH_EXPR_ERROR);
10017             }
10018             buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10019             if (buffer == NULL) {
10020                 XP_ERRORNULL(XPATH_MEMORY_ERROR);
10021             }
10022             memcpy(buffer, buf, len);
10023             while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10024                    (c == '.') || (c == '-') ||
10025                    (c == '_') || ((qualified) && (c == ':')) ||
10026                    (IS_COMBINING(c)) ||
10027                    (IS_EXTENDER(c))) {
10028                 if (len + 10 > max) {
10029                     if (max > XML_MAX_NAME_LENGTH) {
10030                         XP_ERRORNULL(XPATH_EXPR_ERROR);
10031                     }
10032                     max *= 2;
10033                     buffer = (xmlChar *) xmlRealloc(buffer,
10034                                                     max * sizeof(xmlChar));
10035                     if (buffer == NULL) {
10036                         XP_ERRORNULL(XPATH_MEMORY_ERROR);
10037                     }
10038                 }
10039                 COPY_BUF(l,buffer,len,c);
10040                 NEXTL(l);
10041                 c = CUR_CHAR(l);
10042             }
10043             buffer[len] = 0;
10044             return(buffer);
10045         }
10046     }
10047     if (len == 0)
10048         return(NULL);
10049     return(xmlStrndup(buf, len));
10050 }
10051
10052 #define MAX_FRAC 20
10053
10054 /*
10055  * These are used as divisors for the fractional part of a number.
10056  * Since the table includes 1.0 (representing '0' fractional digits),
10057  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
10058  */
10059 static double my_pow10[MAX_FRAC+1] = {
10060     1.0, 10.0, 100.0, 1000.0, 10000.0,
10061     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
10062     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
10063     100000000000000.0,
10064     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
10065     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
10066 };
10067
10068 /**
10069  * xmlXPathStringEvalNumber:
10070  * @str:  A string to scan
10071  *
10072  *  [30a]  Float  ::= Number ('e' Digits?)?
10073  *
10074  *  [30]   Number ::=   Digits ('.' Digits?)?
10075  *                    | '.' Digits
10076  *  [31]   Digits ::=   [0-9]+
10077  *
10078  * Compile a Number in the string
10079  * In complement of the Number expression, this function also handles
10080  * negative values : '-' Number.
10081  *
10082  * Returns the double value.
10083  */
10084 double
10085 xmlXPathStringEvalNumber(const xmlChar *str) {
10086     const xmlChar *cur = str;
10087     double ret;
10088     int ok = 0;
10089     int isneg = 0;
10090     int exponent = 0;
10091     int is_exponent_negative = 0;
10092 #ifdef __GNUC__
10093     unsigned long tmp = 0;
10094     double temp;
10095 #endif
10096     if (cur == NULL) return(0);
10097     while (IS_BLANK_CH(*cur)) cur++;
10098     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10099         return(xmlXPathNAN);
10100     }
10101     if (*cur == '-') {
10102         isneg = 1;
10103         cur++;
10104     }
10105
10106 #ifdef __GNUC__
10107     /*
10108      * tmp/temp is a workaround against a gcc compiler bug
10109      * http://veillard.com/gcc.bug
10110      */
10111     ret = 0;
10112     while ((*cur >= '0') && (*cur <= '9')) {
10113         ret = ret * 10;
10114         tmp = (*cur - '0');
10115         ok = 1;
10116         cur++;
10117         temp = (double) tmp;
10118         ret = ret + temp;
10119     }
10120 #else
10121     ret = 0;
10122     while ((*cur >= '0') && (*cur <= '9')) {
10123         ret = ret * 10 + (*cur - '0');
10124         ok = 1;
10125         cur++;
10126     }
10127 #endif
10128
10129     if (*cur == '.') {
10130         int v, frac = 0;
10131         double fraction = 0;
10132
10133         cur++;
10134         if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10135             return(xmlXPathNAN);
10136         }
10137         while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10138             v = (*cur - '0');
10139             fraction = fraction * 10 + v;
10140             frac = frac + 1;
10141             cur++;
10142         }
10143         fraction /= my_pow10[frac];
10144         ret = ret + fraction;
10145         while ((*cur >= '0') && (*cur <= '9'))
10146             cur++;
10147     }
10148     if ((*cur == 'e') || (*cur == 'E')) {
10149       cur++;
10150       if (*cur == '-') {
10151         is_exponent_negative = 1;
10152         cur++;
10153       } else if (*cur == '+') {
10154         cur++;
10155       }
10156       while ((*cur >= '0') && (*cur <= '9')) {
10157         exponent = exponent * 10 + (*cur - '0');
10158         cur++;
10159       }
10160     }
10161     while (IS_BLANK_CH(*cur)) cur++;
10162     if (*cur != 0) return(xmlXPathNAN);
10163     if (isneg) ret = -ret;
10164     if (is_exponent_negative) exponent = -exponent;
10165     ret *= pow(10.0, (double)exponent);
10166     return(ret);
10167 }
10168
10169 /**
10170  * xmlXPathCompNumber:
10171  * @ctxt:  the XPath Parser context
10172  *
10173  *  [30]   Number ::=   Digits ('.' Digits?)?
10174  *                    | '.' Digits
10175  *  [31]   Digits ::=   [0-9]+
10176  *
10177  * Compile a Number, then push it on the stack
10178  *
10179  */
10180 static void
10181 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10182 {
10183     double ret = 0.0;
10184     int ok = 0;
10185     int exponent = 0;
10186     int is_exponent_negative = 0;
10187 #ifdef __GNUC__
10188     unsigned long tmp = 0;
10189     double temp;
10190 #endif
10191
10192     CHECK_ERROR;
10193     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10194         XP_ERROR(XPATH_NUMBER_ERROR);
10195     }
10196 #ifdef __GNUC__
10197     /*
10198      * tmp/temp is a workaround against a gcc compiler bug
10199      * http://veillard.com/gcc.bug
10200      */
10201     ret = 0;
10202     while ((CUR >= '0') && (CUR <= '9')) {
10203         ret = ret * 10;
10204         tmp = (CUR - '0');
10205         ok = 1;
10206         NEXT;
10207         temp = (double) tmp;
10208         ret = ret + temp;
10209     }
10210 #else
10211     ret = 0;
10212     while ((CUR >= '0') && (CUR <= '9')) {
10213         ret = ret * 10 + (CUR - '0');
10214         ok = 1;
10215         NEXT;
10216     }
10217 #endif
10218     if (CUR == '.') {
10219         int v, frac = 0;
10220         double fraction = 0;
10221
10222         NEXT;
10223         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10224             XP_ERROR(XPATH_NUMBER_ERROR);
10225         }
10226         while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10227             v = (CUR - '0');
10228             fraction = fraction * 10 + v;
10229             frac = frac + 1;
10230             NEXT;
10231         }
10232         fraction /= my_pow10[frac];
10233         ret = ret + fraction;
10234         while ((CUR >= '0') && (CUR <= '9'))
10235             NEXT;
10236     }
10237     if ((CUR == 'e') || (CUR == 'E')) {
10238         NEXT;
10239         if (CUR == '-') {
10240             is_exponent_negative = 1;
10241             NEXT;
10242         } else if (CUR == '+') {
10243             NEXT;
10244         }
10245         while ((CUR >= '0') && (CUR <= '9')) {
10246             exponent = exponent * 10 + (CUR - '0');
10247             NEXT;
10248         }
10249         if (is_exponent_negative)
10250             exponent = -exponent;
10251         ret *= pow(10.0, (double) exponent);
10252     }
10253     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10254                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10255 }
10256
10257 /**
10258  * xmlXPathParseLiteral:
10259  * @ctxt:  the XPath Parser context
10260  *
10261  * Parse a Literal
10262  *
10263  *  [29]   Literal ::=   '"' [^"]* '"'
10264  *                    | "'" [^']* "'"
10265  *
10266  * Returns the value found or NULL in case of error
10267  */
10268 static xmlChar *
10269 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10270     const xmlChar *q;
10271     xmlChar *ret = NULL;
10272
10273     if (CUR == '"') {
10274         NEXT;
10275         q = CUR_PTR;
10276         while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10277             NEXT;
10278         if (!IS_CHAR_CH(CUR)) {
10279             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10280         } else {
10281             ret = xmlStrndup(q, CUR_PTR - q);
10282             NEXT;
10283         }
10284     } else if (CUR == '\'') {
10285         NEXT;
10286         q = CUR_PTR;
10287         while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10288             NEXT;
10289         if (!IS_CHAR_CH(CUR)) {
10290             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10291         } else {
10292             ret = xmlStrndup(q, CUR_PTR - q);
10293             NEXT;
10294         }
10295     } else {
10296         XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10297     }
10298     return(ret);
10299 }
10300
10301 /**
10302  * xmlXPathCompLiteral:
10303  * @ctxt:  the XPath Parser context
10304  *
10305  * Parse a Literal and push it on the stack.
10306  *
10307  *  [29]   Literal ::=   '"' [^"]* '"'
10308  *                    | "'" [^']* "'"
10309  *
10310  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10311  */
10312 static void
10313 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10314     const xmlChar *q;
10315     xmlChar *ret = NULL;
10316
10317     if (CUR == '"') {
10318         NEXT;
10319         q = CUR_PTR;
10320         while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10321             NEXT;
10322         if (!IS_CHAR_CH(CUR)) {
10323             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10324         } else {
10325             ret = xmlStrndup(q, CUR_PTR - q);
10326             NEXT;
10327         }
10328     } else if (CUR == '\'') {
10329         NEXT;
10330         q = CUR_PTR;
10331         while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10332             NEXT;
10333         if (!IS_CHAR_CH(CUR)) {
10334             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10335         } else {
10336             ret = xmlStrndup(q, CUR_PTR - q);
10337             NEXT;
10338         }
10339     } else {
10340         XP_ERROR(XPATH_START_LITERAL_ERROR);
10341     }
10342     if (ret == NULL) return;
10343     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10344                    xmlXPathCacheNewString(ctxt->context, ret), NULL);
10345     xmlFree(ret);
10346 }
10347
10348 /**
10349  * xmlXPathCompVariableReference:
10350  * @ctxt:  the XPath Parser context
10351  *
10352  * Parse a VariableReference, evaluate it and push it on the stack.
10353  *
10354  * The variable bindings consist of a mapping from variable names
10355  * to variable values. The value of a variable is an object, which can be
10356  * of any of the types that are possible for the value of an expression,
10357  * and may also be of additional types not specified here.
10358  *
10359  * Early evaluation is possible since:
10360  * The variable bindings [...] used to evaluate a subexpression are
10361  * always the same as those used to evaluate the containing expression.
10362  *
10363  *  [36]   VariableReference ::=   '$' QName
10364  */
10365 static void
10366 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10367     xmlChar *name;
10368     xmlChar *prefix;
10369
10370     SKIP_BLANKS;
10371     if (CUR != '$') {
10372         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10373     }
10374     NEXT;
10375     name = xmlXPathParseQName(ctxt, &prefix);
10376     if (name == NULL) {
10377         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10378     }
10379     ctxt->comp->last = -1;
10380     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10381                    name, prefix);
10382     SKIP_BLANKS;
10383     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10384         XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10385     }
10386 }
10387
10388 /**
10389  * xmlXPathIsNodeType:
10390  * @name:  a name string
10391  *
10392  * Is the name given a NodeType one.
10393  *
10394  *  [38]   NodeType ::=   'comment'
10395  *                    | 'text'
10396  *                    | 'processing-instruction'
10397  *                    | 'node'
10398  *
10399  * Returns 1 if true 0 otherwise
10400  */
10401 int
10402 xmlXPathIsNodeType(const xmlChar *name) {
10403     if (name == NULL)
10404         return(0);
10405
10406     if (xmlStrEqual(name, BAD_CAST "node"))
10407         return(1);
10408     if (xmlStrEqual(name, BAD_CAST "text"))
10409         return(1);
10410     if (xmlStrEqual(name, BAD_CAST "comment"))
10411         return(1);
10412     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10413         return(1);
10414     return(0);
10415 }
10416
10417 /**
10418  * xmlXPathCompFunctionCall:
10419  * @ctxt:  the XPath Parser context
10420  *
10421  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10422  *  [17]   Argument ::=   Expr
10423  *
10424  * Compile a function call, the evaluation of all arguments are
10425  * pushed on the stack
10426  */
10427 static void
10428 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10429     xmlChar *name;
10430     xmlChar *prefix;
10431     int nbargs = 0;
10432     int sort = 1;
10433
10434     name = xmlXPathParseQName(ctxt, &prefix);
10435     if (name == NULL) {
10436         xmlFree(prefix);
10437         XP_ERROR(XPATH_EXPR_ERROR);
10438     }
10439     SKIP_BLANKS;
10440 #ifdef DEBUG_EXPR
10441     if (prefix == NULL)
10442         xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10443                         name);
10444     else
10445         xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10446                         prefix, name);
10447 #endif
10448
10449     if (CUR != '(') {
10450         XP_ERROR(XPATH_EXPR_ERROR);
10451     }
10452     NEXT;
10453     SKIP_BLANKS;
10454
10455     /*
10456     * Optimization for count(): we don't need the node-set to be sorted.
10457     */
10458     if ((prefix == NULL) && (name[0] == 'c') &&
10459         xmlStrEqual(name, BAD_CAST "count"))
10460     {
10461         sort = 0;
10462     }
10463     ctxt->comp->last = -1;
10464     if (CUR != ')') {
10465         while (CUR != 0) {
10466             int op1 = ctxt->comp->last;
10467             ctxt->comp->last = -1;
10468             xmlXPathCompileExpr(ctxt, sort);
10469             if (ctxt->error != XPATH_EXPRESSION_OK) {
10470                 xmlFree(name);
10471                 xmlFree(prefix);
10472                 return;
10473             }
10474             PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10475             nbargs++;
10476             if (CUR == ')') break;
10477             if (CUR != ',') {
10478                 XP_ERROR(XPATH_EXPR_ERROR);
10479             }
10480             NEXT;
10481             SKIP_BLANKS;
10482         }
10483     }
10484     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10485                    name, prefix);
10486     NEXT;
10487     SKIP_BLANKS;
10488 }
10489
10490 /**
10491  * xmlXPathCompPrimaryExpr:
10492  * @ctxt:  the XPath Parser context
10493  *
10494  *  [15]   PrimaryExpr ::=   VariableReference
10495  *                | '(' Expr ')'
10496  *                | Literal
10497  *                | Number
10498  *                | FunctionCall
10499  *
10500  * Compile a primary expression.
10501  */
10502 static void
10503 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10504     SKIP_BLANKS;
10505     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10506     else if (CUR == '(') {
10507         NEXT;
10508         SKIP_BLANKS;
10509         xmlXPathCompileExpr(ctxt, 1);
10510         CHECK_ERROR;
10511         if (CUR != ')') {
10512             XP_ERROR(XPATH_EXPR_ERROR);
10513         }
10514         NEXT;
10515         SKIP_BLANKS;
10516     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10517         xmlXPathCompNumber(ctxt);
10518     } else if ((CUR == '\'') || (CUR == '"')) {
10519         xmlXPathCompLiteral(ctxt);
10520     } else {
10521         xmlXPathCompFunctionCall(ctxt);
10522     }
10523     SKIP_BLANKS;
10524 }
10525
10526 /**
10527  * xmlXPathCompFilterExpr:
10528  * @ctxt:  the XPath Parser context
10529  *
10530  *  [20]   FilterExpr ::=   PrimaryExpr
10531  *               | FilterExpr Predicate
10532  *
10533  * Compile a filter expression.
10534  * Square brackets are used to filter expressions in the same way that
10535  * they are used in location paths. It is an error if the expression to
10536  * be filtered does not evaluate to a node-set. The context node list
10537  * used for evaluating the expression in square brackets is the node-set
10538  * to be filtered listed in document order.
10539  */
10540
10541 static void
10542 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10543     xmlXPathCompPrimaryExpr(ctxt);
10544     CHECK_ERROR;
10545     SKIP_BLANKS;
10546
10547     while (CUR == '[') {
10548         xmlXPathCompPredicate(ctxt, 1);
10549         SKIP_BLANKS;
10550     }
10551
10552
10553 }
10554
10555 /**
10556  * xmlXPathScanName:
10557  * @ctxt:  the XPath Parser context
10558  *
10559  * Trickery: parse an XML name but without consuming the input flow
10560  * Needed to avoid insanity in the parser state.
10561  *
10562  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10563  *                  CombiningChar | Extender
10564  *
10565  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10566  *
10567  * [6] Names ::= Name (S Name)*
10568  *
10569  * Returns the Name parsed or NULL
10570  */
10571
10572 static xmlChar *
10573 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10574     int len = 0, l;
10575     int c;
10576     const xmlChar *cur;
10577     xmlChar *ret;
10578
10579     cur = ctxt->cur;
10580
10581     c = CUR_CHAR(l);
10582     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10583         (!IS_LETTER(c) && (c != '_') &&
10584          (c != ':'))) {
10585         return(NULL);
10586     }
10587
10588     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10589            ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10590             (c == '.') || (c == '-') ||
10591             (c == '_') || (c == ':') ||
10592             (IS_COMBINING(c)) ||
10593             (IS_EXTENDER(c)))) {
10594         len += l;
10595         NEXTL(l);
10596         c = CUR_CHAR(l);
10597     }
10598     ret = xmlStrndup(cur, ctxt->cur - cur);
10599     ctxt->cur = cur;
10600     return(ret);
10601 }
10602
10603 /**
10604  * xmlXPathCompPathExpr:
10605  * @ctxt:  the XPath Parser context
10606  *
10607  *  [19]   PathExpr ::=   LocationPath
10608  *               | FilterExpr
10609  *               | FilterExpr '/' RelativeLocationPath
10610  *               | FilterExpr '//' RelativeLocationPath
10611  *
10612  * Compile a path expression.
10613  * The / operator and // operators combine an arbitrary expression
10614  * and a relative location path. It is an error if the expression
10615  * does not evaluate to a node-set.
10616  * The / operator does composition in the same way as when / is
10617  * used in a location path. As in location paths, // is short for
10618  * /descendant-or-self::node()/.
10619  */
10620
10621 static void
10622 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10623     int lc = 1;           /* Should we branch to LocationPath ?         */
10624     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10625
10626     SKIP_BLANKS;
10627     if ((CUR == '$') || (CUR == '(') ||
10628         (IS_ASCII_DIGIT(CUR)) ||
10629         (CUR == '\'') || (CUR == '"') ||
10630         (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10631         lc = 0;
10632     } else if (CUR == '*') {
10633         /* relative or absolute location path */
10634         lc = 1;
10635     } else if (CUR == '/') {
10636         /* relative or absolute location path */
10637         lc = 1;
10638     } else if (CUR == '@') {
10639         /* relative abbreviated attribute location path */
10640         lc = 1;
10641     } else if (CUR == '.') {
10642         /* relative abbreviated attribute location path */
10643         lc = 1;
10644     } else {
10645         /*
10646          * Problem is finding if we have a name here whether it's:
10647          *   - a nodetype
10648          *   - a function call in which case it's followed by '('
10649          *   - an axis in which case it's followed by ':'
10650          *   - a element name
10651          * We do an a priori analysis here rather than having to
10652          * maintain parsed token content through the recursive function
10653          * calls. This looks uglier but makes the code easier to
10654          * read/write/debug.
10655          */
10656         SKIP_BLANKS;
10657         name = xmlXPathScanName(ctxt);
10658         if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10659 #ifdef DEBUG_STEP
10660             xmlGenericError(xmlGenericErrorContext,
10661                     "PathExpr: Axis\n");
10662 #endif
10663             lc = 1;
10664             xmlFree(name);
10665         } else if (name != NULL) {
10666             int len =xmlStrlen(name);
10667
10668
10669             while (NXT(len) != 0) {
10670                 if (NXT(len) == '/') {
10671                     /* element name */
10672 #ifdef DEBUG_STEP
10673                     xmlGenericError(xmlGenericErrorContext,
10674                             "PathExpr: AbbrRelLocation\n");
10675 #endif
10676                     lc = 1;
10677                     break;
10678                 } else if (IS_BLANK_CH(NXT(len))) {
10679                     /* ignore blanks */
10680                     ;
10681                 } else if (NXT(len) == ':') {
10682 #ifdef DEBUG_STEP
10683                     xmlGenericError(xmlGenericErrorContext,
10684                             "PathExpr: AbbrRelLocation\n");
10685 #endif
10686                     lc = 1;
10687                     break;
10688                 } else if ((NXT(len) == '(')) {
10689                     /* Note Type or Function */
10690                     if (xmlXPathIsNodeType(name)) {
10691 #ifdef DEBUG_STEP
10692                         xmlGenericError(xmlGenericErrorContext,
10693                                 "PathExpr: Type search\n");
10694 #endif
10695                         lc = 1;
10696                     } else {
10697 #ifdef DEBUG_STEP
10698                         xmlGenericError(xmlGenericErrorContext,
10699                                 "PathExpr: function call\n");
10700 #endif
10701                         lc = 0;
10702                     }
10703                     break;
10704                 } else if ((NXT(len) == '[')) {
10705                     /* element name */
10706 #ifdef DEBUG_STEP
10707                     xmlGenericError(xmlGenericErrorContext,
10708                             "PathExpr: AbbrRelLocation\n");
10709 #endif
10710                     lc = 1;
10711                     break;
10712                 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10713                            (NXT(len) == '=')) {
10714                     lc = 1;
10715                     break;
10716                 } else {
10717                     lc = 1;
10718                     break;
10719                 }
10720                 len++;
10721             }
10722             if (NXT(len) == 0) {
10723 #ifdef DEBUG_STEP
10724                 xmlGenericError(xmlGenericErrorContext,
10725                         "PathExpr: AbbrRelLocation\n");
10726 #endif
10727                 /* element name */
10728                 lc = 1;
10729             }
10730             xmlFree(name);
10731         } else {
10732             /* make sure all cases are covered explicitly */
10733             XP_ERROR(XPATH_EXPR_ERROR);
10734         }
10735     }
10736
10737     if (lc) {
10738         if (CUR == '/') {
10739             PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10740         } else {
10741             PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10742         }
10743         xmlXPathCompLocationPath(ctxt);
10744     } else {
10745         xmlXPathCompFilterExpr(ctxt);
10746         CHECK_ERROR;
10747         if ((CUR == '/') && (NXT(1) == '/')) {
10748             SKIP(2);
10749             SKIP_BLANKS;
10750
10751             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10752                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10753             PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10754
10755             xmlXPathCompRelativeLocationPath(ctxt);
10756         } else if (CUR == '/') {
10757             xmlXPathCompRelativeLocationPath(ctxt);
10758         }
10759     }
10760     SKIP_BLANKS;
10761 }
10762
10763 /**
10764  * xmlXPathCompUnionExpr:
10765  * @ctxt:  the XPath Parser context
10766  *
10767  *  [18]   UnionExpr ::=   PathExpr
10768  *               | UnionExpr '|' PathExpr
10769  *
10770  * Compile an union expression.
10771  */
10772
10773 static void
10774 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10775     xmlXPathCompPathExpr(ctxt);
10776     CHECK_ERROR;
10777     SKIP_BLANKS;
10778     while (CUR == '|') {
10779         int op1 = ctxt->comp->last;
10780         PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10781
10782         NEXT;
10783         SKIP_BLANKS;
10784         xmlXPathCompPathExpr(ctxt);
10785
10786         PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10787
10788         SKIP_BLANKS;
10789     }
10790 }
10791
10792 /**
10793  * xmlXPathCompUnaryExpr:
10794  * @ctxt:  the XPath Parser context
10795  *
10796  *  [27]   UnaryExpr ::=   UnionExpr
10797  *                   | '-' UnaryExpr
10798  *
10799  * Compile an unary expression.
10800  */
10801
10802 static void
10803 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10804     int minus = 0;
10805     int found = 0;
10806
10807     SKIP_BLANKS;
10808     while (CUR == '-') {
10809         minus = 1 - minus;
10810         found = 1;
10811         NEXT;
10812         SKIP_BLANKS;
10813     }
10814
10815     xmlXPathCompUnionExpr(ctxt);
10816     CHECK_ERROR;
10817     if (found) {
10818         if (minus)
10819             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10820         else
10821             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10822     }
10823 }
10824
10825 /**
10826  * xmlXPathCompMultiplicativeExpr:
10827  * @ctxt:  the XPath Parser context
10828  *
10829  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10830  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10831  *                   | MultiplicativeExpr 'div' UnaryExpr
10832  *                   | MultiplicativeExpr 'mod' UnaryExpr
10833  *  [34]   MultiplyOperator ::=   '*'
10834  *
10835  * Compile an Additive expression.
10836  */
10837
10838 static void
10839 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10840     xmlXPathCompUnaryExpr(ctxt);
10841     CHECK_ERROR;
10842     SKIP_BLANKS;
10843     while ((CUR == '*') ||
10844            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10845            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10846         int op = -1;
10847         int op1 = ctxt->comp->last;
10848
10849         if (CUR == '*') {
10850             op = 0;
10851             NEXT;
10852         } else if (CUR == 'd') {
10853             op = 1;
10854             SKIP(3);
10855         } else if (CUR == 'm') {
10856             op = 2;
10857             SKIP(3);
10858         }
10859         SKIP_BLANKS;
10860         xmlXPathCompUnaryExpr(ctxt);
10861         CHECK_ERROR;
10862         PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10863         SKIP_BLANKS;
10864     }
10865 }
10866
10867 /**
10868  * xmlXPathCompAdditiveExpr:
10869  * @ctxt:  the XPath Parser context
10870  *
10871  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10872  *                   | AdditiveExpr '+' MultiplicativeExpr
10873  *                   | AdditiveExpr '-' MultiplicativeExpr
10874  *
10875  * Compile an Additive expression.
10876  */
10877
10878 static void
10879 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10880
10881     xmlXPathCompMultiplicativeExpr(ctxt);
10882     CHECK_ERROR;
10883     SKIP_BLANKS;
10884     while ((CUR == '+') || (CUR == '-')) {
10885         int plus;
10886         int op1 = ctxt->comp->last;
10887
10888         if (CUR == '+') plus = 1;
10889         else plus = 0;
10890         NEXT;
10891         SKIP_BLANKS;
10892         xmlXPathCompMultiplicativeExpr(ctxt);
10893         CHECK_ERROR;
10894         PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10895         SKIP_BLANKS;
10896     }
10897 }
10898
10899 /**
10900  * xmlXPathCompRelationalExpr:
10901  * @ctxt:  the XPath Parser context
10902  *
10903  *  [24]   RelationalExpr ::=   AdditiveExpr
10904  *                 | RelationalExpr '<' AdditiveExpr
10905  *                 | RelationalExpr '>' AdditiveExpr
10906  *                 | RelationalExpr '<=' AdditiveExpr
10907  *                 | RelationalExpr '>=' AdditiveExpr
10908  *
10909  *  A <= B > C is allowed ? Answer from James, yes with
10910  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10911  *  which is basically what got implemented.
10912  *
10913  * Compile a Relational expression, then push the result
10914  * on the stack
10915  */
10916
10917 static void
10918 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10919     xmlXPathCompAdditiveExpr(ctxt);
10920     CHECK_ERROR;
10921     SKIP_BLANKS;
10922     while ((CUR == '<') ||
10923            (CUR == '>') ||
10924            ((CUR == '<') && (NXT(1) == '=')) ||
10925            ((CUR == '>') && (NXT(1) == '='))) {
10926         int inf, strict;
10927         int op1 = ctxt->comp->last;
10928
10929         if (CUR == '<') inf = 1;
10930         else inf = 0;
10931         if (NXT(1) == '=') strict = 0;
10932         else strict = 1;
10933         NEXT;
10934         if (!strict) NEXT;
10935         SKIP_BLANKS;
10936         xmlXPathCompAdditiveExpr(ctxt);
10937         CHECK_ERROR;
10938         PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10939         SKIP_BLANKS;
10940     }
10941 }
10942
10943 /**
10944  * xmlXPathCompEqualityExpr:
10945  * @ctxt:  the XPath Parser context
10946  *
10947  *  [23]   EqualityExpr ::=   RelationalExpr
10948  *                 | EqualityExpr '=' RelationalExpr
10949  *                 | EqualityExpr '!=' RelationalExpr
10950  *
10951  *  A != B != C is allowed ? Answer from James, yes with
10952  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10953  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10954  *  which is basically what got implemented.
10955  *
10956  * Compile an Equality expression.
10957  *
10958  */
10959 static void
10960 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10961     xmlXPathCompRelationalExpr(ctxt);
10962     CHECK_ERROR;
10963     SKIP_BLANKS;
10964     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10965         int eq;
10966         int op1 = ctxt->comp->last;
10967
10968         if (CUR == '=') eq = 1;
10969         else eq = 0;
10970         NEXT;
10971         if (!eq) NEXT;
10972         SKIP_BLANKS;
10973         xmlXPathCompRelationalExpr(ctxt);
10974         CHECK_ERROR;
10975         PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10976         SKIP_BLANKS;
10977     }
10978 }
10979
10980 /**
10981  * xmlXPathCompAndExpr:
10982  * @ctxt:  the XPath Parser context
10983  *
10984  *  [22]   AndExpr ::=   EqualityExpr
10985  *                 | AndExpr 'and' EqualityExpr
10986  *
10987  * Compile an AND expression.
10988  *
10989  */
10990 static void
10991 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10992     xmlXPathCompEqualityExpr(ctxt);
10993     CHECK_ERROR;
10994     SKIP_BLANKS;
10995     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10996         int op1 = ctxt->comp->last;
10997         SKIP(3);
10998         SKIP_BLANKS;
10999         xmlXPathCompEqualityExpr(ctxt);
11000         CHECK_ERROR;
11001         PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11002         SKIP_BLANKS;
11003     }
11004 }
11005
11006 /**
11007  * xmlXPathCompileExpr:
11008  * @ctxt:  the XPath Parser context
11009  *
11010  *  [14]   Expr ::=   OrExpr
11011  *  [21]   OrExpr ::=   AndExpr
11012  *                 | OrExpr 'or' AndExpr
11013  *
11014  * Parse and compile an expression
11015  */
11016 static void
11017 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11018     xmlXPathCompAndExpr(ctxt);
11019     CHECK_ERROR;
11020     SKIP_BLANKS;
11021     while ((CUR == 'o') && (NXT(1) == 'r')) {
11022         int op1 = ctxt->comp->last;
11023         SKIP(2);
11024         SKIP_BLANKS;
11025         xmlXPathCompAndExpr(ctxt);
11026         CHECK_ERROR;
11027         PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11028         SKIP_BLANKS;
11029     }
11030     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11031         /* more ops could be optimized too */
11032         /*
11033         * This is the main place to eliminate sorting for
11034         * operations which don't require a sorted node-set.
11035         * E.g. count().
11036         */
11037         PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11038     }
11039 }
11040
11041 /**
11042  * xmlXPathCompPredicate:
11043  * @ctxt:  the XPath Parser context
11044  * @filter:  act as a filter
11045  *
11046  *  [8]   Predicate ::=   '[' PredicateExpr ']'
11047  *  [9]   PredicateExpr ::=   Expr
11048  *
11049  * Compile a predicate expression
11050  */
11051 static void
11052 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11053     int op1 = ctxt->comp->last;
11054
11055     SKIP_BLANKS;
11056     if (CUR != '[') {
11057         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11058     }
11059     NEXT;
11060     SKIP_BLANKS;
11061
11062     ctxt->comp->last = -1;
11063     /*
11064     * This call to xmlXPathCompileExpr() will deactivate sorting
11065     * of the predicate result.
11066     * TODO: Sorting is still activated for filters, since I'm not
11067     *  sure if needed. Normally sorting should not be needed, since
11068     *  a filter can only diminish the number of items in a sequence,
11069     *  but won't change its order; so if the initial sequence is sorted,
11070     *  subsequent sorting is not needed.
11071     */
11072     if (! filter)
11073         xmlXPathCompileExpr(ctxt, 0);
11074     else
11075         xmlXPathCompileExpr(ctxt, 1);
11076     CHECK_ERROR;
11077
11078     if (CUR != ']') {
11079         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11080     }
11081
11082     if (filter)
11083         PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11084     else
11085         PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11086
11087     NEXT;
11088     SKIP_BLANKS;
11089 }
11090
11091 /**
11092  * xmlXPathCompNodeTest:
11093  * @ctxt:  the XPath Parser context
11094  * @test:  pointer to a xmlXPathTestVal
11095  * @type:  pointer to a xmlXPathTypeVal
11096  * @prefix:  placeholder for a possible name prefix
11097  *
11098  * [7] NodeTest ::=   NameTest
11099  *                  | NodeType '(' ')'
11100  *                  | 'processing-instruction' '(' Literal ')'
11101  *
11102  * [37] NameTest ::=  '*'
11103  *                  | NCName ':' '*'
11104  *                  | QName
11105  * [38] NodeType ::= 'comment'
11106  *                 | 'text'
11107  *                 | 'processing-instruction'
11108  *                 | 'node'
11109  *
11110  * Returns the name found and updates @test, @type and @prefix appropriately
11111  */
11112 static xmlChar *
11113 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11114                      xmlXPathTypeVal *type, const xmlChar **prefix,
11115                      xmlChar *name) {
11116     int blanks;
11117
11118     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11119         STRANGE;
11120         return(NULL);
11121     }
11122     *type = (xmlXPathTypeVal) 0;
11123     *test = (xmlXPathTestVal) 0;
11124     *prefix = NULL;
11125     SKIP_BLANKS;
11126
11127     if ((name == NULL) && (CUR == '*')) {
11128         /*
11129          * All elements
11130          */
11131         NEXT;
11132         *test = NODE_TEST_ALL;
11133         return(NULL);
11134     }
11135
11136     if (name == NULL)
11137         name = xmlXPathParseNCName(ctxt);
11138     if (name == NULL) {
11139         XP_ERRORNULL(XPATH_EXPR_ERROR);
11140     }
11141
11142     blanks = IS_BLANK_CH(CUR);
11143     SKIP_BLANKS;
11144     if (CUR == '(') {
11145         NEXT;
11146         /*
11147          * NodeType or PI search
11148          */
11149         if (xmlStrEqual(name, BAD_CAST "comment"))
11150             *type = NODE_TYPE_COMMENT;
11151         else if (xmlStrEqual(name, BAD_CAST "node"))
11152             *type = NODE_TYPE_NODE;
11153         else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11154             *type = NODE_TYPE_PI;
11155         else if (xmlStrEqual(name, BAD_CAST "text"))
11156             *type = NODE_TYPE_TEXT;
11157         else {
11158             if (name != NULL)
11159                 xmlFree(name);
11160             XP_ERRORNULL(XPATH_EXPR_ERROR);
11161         }
11162
11163         *test = NODE_TEST_TYPE;
11164
11165         SKIP_BLANKS;
11166         if (*type == NODE_TYPE_PI) {
11167             /*
11168              * Specific case: search a PI by name.
11169              */
11170             if (name != NULL)
11171                 xmlFree(name);
11172             name = NULL;
11173             if (CUR != ')') {
11174                 name = xmlXPathParseLiteral(ctxt);
11175                 CHECK_ERROR NULL;
11176                 *test = NODE_TEST_PI;
11177                 SKIP_BLANKS;
11178             }
11179         }
11180         if (CUR != ')') {
11181             if (name != NULL)
11182                 xmlFree(name);
11183             XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11184         }
11185         NEXT;
11186         return(name);
11187     }
11188     *test = NODE_TEST_NAME;
11189     if ((!blanks) && (CUR == ':')) {
11190         NEXT;
11191
11192         /*
11193          * Since currently the parser context don't have a
11194          * namespace list associated:
11195          * The namespace name for this prefix can be computed
11196          * only at evaluation time. The compilation is done
11197          * outside of any context.
11198          */
11199 #if 0
11200         *prefix = xmlXPathNsLookup(ctxt->context, name);
11201         if (name != NULL)
11202             xmlFree(name);
11203         if (*prefix == NULL) {
11204             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11205         }
11206 #else
11207         *prefix = name;
11208 #endif
11209
11210         if (CUR == '*') {
11211             /*
11212              * All elements
11213              */
11214             NEXT;
11215             *test = NODE_TEST_ALL;
11216             return(NULL);
11217         }
11218
11219         name = xmlXPathParseNCName(ctxt);
11220         if (name == NULL) {
11221             XP_ERRORNULL(XPATH_EXPR_ERROR);
11222         }
11223     }
11224     return(name);
11225 }
11226
11227 /**
11228  * xmlXPathIsAxisName:
11229  * @name:  a preparsed name token
11230  *
11231  * [6] AxisName ::=   'ancestor'
11232  *                  | 'ancestor-or-self'
11233  *                  | 'attribute'
11234  *                  | 'child'
11235  *                  | 'descendant'
11236  *                  | 'descendant-or-self'
11237  *                  | 'following'
11238  *                  | 'following-sibling'
11239  *                  | 'namespace'
11240  *                  | 'parent'
11241  *                  | 'preceding'
11242  *                  | 'preceding-sibling'
11243  *                  | 'self'
11244  *
11245  * Returns the axis or 0
11246  */
11247 static xmlXPathAxisVal
11248 xmlXPathIsAxisName(const xmlChar *name) {
11249     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11250     switch (name[0]) {
11251         case 'a':
11252             if (xmlStrEqual(name, BAD_CAST "ancestor"))
11253                 ret = AXIS_ANCESTOR;
11254             if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11255                 ret = AXIS_ANCESTOR_OR_SELF;
11256             if (xmlStrEqual(name, BAD_CAST "attribute"))
11257                 ret = AXIS_ATTRIBUTE;
11258             break;
11259         case 'c':
11260             if (xmlStrEqual(name, BAD_CAST "child"))
11261                 ret = AXIS_CHILD;
11262             break;
11263         case 'd':
11264             if (xmlStrEqual(name, BAD_CAST "descendant"))
11265                 ret = AXIS_DESCENDANT;
11266             if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11267                 ret = AXIS_DESCENDANT_OR_SELF;
11268             break;
11269         case 'f':
11270             if (xmlStrEqual(name, BAD_CAST "following"))
11271                 ret = AXIS_FOLLOWING;
11272             if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11273                 ret = AXIS_FOLLOWING_SIBLING;
11274             break;
11275         case 'n':
11276             if (xmlStrEqual(name, BAD_CAST "namespace"))
11277                 ret = AXIS_NAMESPACE;
11278             break;
11279         case 'p':
11280             if (xmlStrEqual(name, BAD_CAST "parent"))
11281                 ret = AXIS_PARENT;
11282             if (xmlStrEqual(name, BAD_CAST "preceding"))
11283                 ret = AXIS_PRECEDING;
11284             if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11285                 ret = AXIS_PRECEDING_SIBLING;
11286             break;
11287         case 's':
11288             if (xmlStrEqual(name, BAD_CAST "self"))
11289                 ret = AXIS_SELF;
11290             break;
11291     }
11292     return(ret);
11293 }
11294
11295 /**
11296  * xmlXPathCompStep:
11297  * @ctxt:  the XPath Parser context
11298  *
11299  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11300  *                  | AbbreviatedStep
11301  *
11302  * [12] AbbreviatedStep ::=   '.' | '..'
11303  *
11304  * [5] AxisSpecifier ::= AxisName '::'
11305  *                  | AbbreviatedAxisSpecifier
11306  *
11307  * [13] AbbreviatedAxisSpecifier ::= '@'?
11308  *
11309  * Modified for XPtr range support as:
11310  *
11311  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11312  *                     | AbbreviatedStep
11313  *                     | 'range-to' '(' Expr ')' Predicate*
11314  *
11315  * Compile one step in a Location Path
11316  * A location step of . is short for self::node(). This is
11317  * particularly useful in conjunction with //. For example, the
11318  * location path .//para is short for
11319  * self::node()/descendant-or-self::node()/child::para
11320  * and so will select all para descendant elements of the context
11321  * node.
11322  * Similarly, a location step of .. is short for parent::node().
11323  * For example, ../title is short for parent::node()/child::title
11324  * and so will select the title children of the parent of the context
11325  * node.
11326  */
11327 static void
11328 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11329 #ifdef LIBXML_XPTR_ENABLED
11330     int rangeto = 0;
11331     int op2 = -1;
11332 #endif
11333
11334     SKIP_BLANKS;
11335     if ((CUR == '.') && (NXT(1) == '.')) {
11336         SKIP(2);
11337         SKIP_BLANKS;
11338         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11339                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11340     } else if (CUR == '.') {
11341         NEXT;
11342         SKIP_BLANKS;
11343     } else {
11344         xmlChar *name = NULL;
11345         const xmlChar *prefix = NULL;
11346         xmlXPathTestVal test = (xmlXPathTestVal) 0;
11347         xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11348         xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11349         int op1;
11350
11351         /*
11352          * The modification needed for XPointer change to the production
11353          */
11354 #ifdef LIBXML_XPTR_ENABLED
11355         if (ctxt->xptr) {
11356             name = xmlXPathParseNCName(ctxt);
11357             if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11358                 op2 = ctxt->comp->last;
11359                 xmlFree(name);
11360                 SKIP_BLANKS;
11361                 if (CUR != '(') {
11362                     XP_ERROR(XPATH_EXPR_ERROR);
11363                 }
11364                 NEXT;
11365                 SKIP_BLANKS;
11366
11367                 xmlXPathCompileExpr(ctxt, 1);
11368                 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11369                 CHECK_ERROR;
11370
11371                 SKIP_BLANKS;
11372                 if (CUR != ')') {
11373                     XP_ERROR(XPATH_EXPR_ERROR);
11374                 }
11375                 NEXT;
11376                 rangeto = 1;
11377                 goto eval_predicates;
11378             }
11379         }
11380 #endif
11381         if (CUR == '*') {
11382             axis = AXIS_CHILD;
11383         } else {
11384             if (name == NULL)
11385                 name = xmlXPathParseNCName(ctxt);
11386             if (name != NULL) {
11387                 axis = xmlXPathIsAxisName(name);
11388                 if (axis != 0) {
11389                     SKIP_BLANKS;
11390                     if ((CUR == ':') && (NXT(1) == ':')) {
11391                         SKIP(2);
11392                         xmlFree(name);
11393                         name = NULL;
11394                     } else {
11395                         /* an element name can conflict with an axis one :-\ */
11396                         axis = AXIS_CHILD;
11397                     }
11398                 } else {
11399                     axis = AXIS_CHILD;
11400                 }
11401             } else if (CUR == '@') {
11402                 NEXT;
11403                 axis = AXIS_ATTRIBUTE;
11404             } else {
11405                 axis = AXIS_CHILD;
11406             }
11407         }
11408
11409         if (ctxt->error != XPATH_EXPRESSION_OK) {
11410             xmlFree(name);
11411             return;
11412         }
11413
11414         name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11415         if (test == 0)
11416             return;
11417
11418         if ((prefix != NULL) && (ctxt->context != NULL) &&
11419             (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11420             if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11421                 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11422             }
11423         }
11424 #ifdef DEBUG_STEP
11425         xmlGenericError(xmlGenericErrorContext,
11426                 "Basis : computing new set\n");
11427 #endif
11428
11429 #ifdef DEBUG_STEP
11430         xmlGenericError(xmlGenericErrorContext, "Basis : ");
11431         if (ctxt->value == NULL)
11432             xmlGenericError(xmlGenericErrorContext, "no value\n");
11433         else if (ctxt->value->nodesetval == NULL)
11434             xmlGenericError(xmlGenericErrorContext, "Empty\n");
11435         else
11436             xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11437 #endif
11438
11439 #ifdef LIBXML_XPTR_ENABLED
11440 eval_predicates:
11441 #endif
11442         op1 = ctxt->comp->last;
11443         ctxt->comp->last = -1;
11444
11445         SKIP_BLANKS;
11446         while (CUR == '[') {
11447             xmlXPathCompPredicate(ctxt, 0);
11448         }
11449
11450 #ifdef LIBXML_XPTR_ENABLED
11451         if (rangeto) {
11452             PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11453         } else
11454 #endif
11455             PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11456                            test, type, (void *)prefix, (void *)name);
11457
11458     }
11459 #ifdef DEBUG_STEP
11460     xmlGenericError(xmlGenericErrorContext, "Step : ");
11461     if (ctxt->value == NULL)
11462         xmlGenericError(xmlGenericErrorContext, "no value\n");
11463     else if (ctxt->value->nodesetval == NULL)
11464         xmlGenericError(xmlGenericErrorContext, "Empty\n");
11465     else
11466         xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11467                 ctxt->value->nodesetval);
11468 #endif
11469 }
11470
11471 /**
11472  * xmlXPathCompRelativeLocationPath:
11473  * @ctxt:  the XPath Parser context
11474  *
11475  *  [3]   RelativeLocationPath ::=   Step
11476  *                     | RelativeLocationPath '/' Step
11477  *                     | AbbreviatedRelativeLocationPath
11478  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11479  *
11480  * Compile a relative location path.
11481  */
11482 static void
11483 xmlXPathCompRelativeLocationPath
11484 (xmlXPathParserContextPtr ctxt) {
11485     SKIP_BLANKS;
11486     if ((CUR == '/') && (NXT(1) == '/')) {
11487         SKIP(2);
11488         SKIP_BLANKS;
11489         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11490                          NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11491     } else if (CUR == '/') {
11492             NEXT;
11493         SKIP_BLANKS;
11494     }
11495     xmlXPathCompStep(ctxt);
11496     CHECK_ERROR;
11497     SKIP_BLANKS;
11498     while (CUR == '/') {
11499         if ((CUR == '/') && (NXT(1) == '/')) {
11500             SKIP(2);
11501             SKIP_BLANKS;
11502             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11503                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11504             xmlXPathCompStep(ctxt);
11505         } else if (CUR == '/') {
11506             NEXT;
11507             SKIP_BLANKS;
11508             xmlXPathCompStep(ctxt);
11509         }
11510         SKIP_BLANKS;
11511     }
11512 }
11513
11514 /**
11515  * xmlXPathCompLocationPath:
11516  * @ctxt:  the XPath Parser context
11517  *
11518  *  [1]   LocationPath ::=   RelativeLocationPath
11519  *                     | AbsoluteLocationPath
11520  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11521  *                     | AbbreviatedAbsoluteLocationPath
11522  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11523  *                           '//' RelativeLocationPath
11524  *
11525  * Compile a location path
11526  *
11527  * // is short for /descendant-or-self::node()/. For example,
11528  * //para is short for /descendant-or-self::node()/child::para and
11529  * so will select any para element in the document (even a para element
11530  * that is a document element will be selected by //para since the
11531  * document element node is a child of the root node); div//para is
11532  * short for div/descendant-or-self::node()/child::para and so will
11533  * select all para descendants of div children.
11534  */
11535 static void
11536 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11537     SKIP_BLANKS;
11538     if (CUR != '/') {
11539         xmlXPathCompRelativeLocationPath(ctxt);
11540     } else {
11541         while (CUR == '/') {
11542             if ((CUR == '/') && (NXT(1) == '/')) {
11543                 SKIP(2);
11544                 SKIP_BLANKS;
11545                 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11546                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11547                 xmlXPathCompRelativeLocationPath(ctxt);
11548             } else if (CUR == '/') {
11549                 NEXT;
11550                 SKIP_BLANKS;
11551                 if ((CUR != 0 ) &&
11552                     ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11553                      (CUR == '@') || (CUR == '*')))
11554                     xmlXPathCompRelativeLocationPath(ctxt);
11555             }
11556             CHECK_ERROR;
11557         }
11558     }
11559 }
11560
11561 /************************************************************************
11562  *                                                                      *
11563  *              XPath precompiled expression evaluation                 *
11564  *                                                                      *
11565  ************************************************************************/
11566
11567 static int
11568 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11569
11570 #ifdef DEBUG_STEP
11571 static void
11572 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11573                           int nbNodes)
11574 {
11575     xmlGenericError(xmlGenericErrorContext, "new step : ");
11576     switch (op->value) {
11577         case AXIS_ANCESTOR:
11578             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11579             break;
11580         case AXIS_ANCESTOR_OR_SELF:
11581             xmlGenericError(xmlGenericErrorContext,
11582                             "axis 'ancestors-or-self' ");
11583             break;
11584         case AXIS_ATTRIBUTE:
11585             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11586             break;
11587         case AXIS_CHILD:
11588             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11589             break;
11590         case AXIS_DESCENDANT:
11591             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11592             break;
11593         case AXIS_DESCENDANT_OR_SELF:
11594             xmlGenericError(xmlGenericErrorContext,
11595                             "axis 'descendant-or-self' ");
11596             break;
11597         case AXIS_FOLLOWING:
11598             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11599             break;
11600         case AXIS_FOLLOWING_SIBLING:
11601             xmlGenericError(xmlGenericErrorContext,
11602                             "axis 'following-siblings' ");
11603             break;
11604         case AXIS_NAMESPACE:
11605             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11606             break;
11607         case AXIS_PARENT:
11608             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11609             break;
11610         case AXIS_PRECEDING:
11611             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11612             break;
11613         case AXIS_PRECEDING_SIBLING:
11614             xmlGenericError(xmlGenericErrorContext,
11615                             "axis 'preceding-sibling' ");
11616             break;
11617         case AXIS_SELF:
11618             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11619             break;
11620     }
11621     xmlGenericError(xmlGenericErrorContext,
11622         " context contains %d nodes\n", nbNodes);
11623     switch (op->value2) {
11624         case NODE_TEST_NONE:
11625             xmlGenericError(xmlGenericErrorContext,
11626                             "           searching for none !!!\n");
11627             break;
11628         case NODE_TEST_TYPE:
11629             xmlGenericError(xmlGenericErrorContext,
11630                             "           searching for type %d\n", op->value3);
11631             break;
11632         case NODE_TEST_PI:
11633             xmlGenericError(xmlGenericErrorContext,
11634                             "           searching for PI !!!\n");
11635             break;
11636         case NODE_TEST_ALL:
11637             xmlGenericError(xmlGenericErrorContext,
11638                             "           searching for *\n");
11639             break;
11640         case NODE_TEST_NS:
11641             xmlGenericError(xmlGenericErrorContext,
11642                             "           searching for namespace %s\n",
11643                             op->value5);
11644             break;
11645         case NODE_TEST_NAME:
11646             xmlGenericError(xmlGenericErrorContext,
11647                             "           searching for name %s\n", op->value5);
11648             if (op->value4)
11649                 xmlGenericError(xmlGenericErrorContext,
11650                                 "           with namespace %s\n", op->value4);
11651             break;
11652     }
11653     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11654 }
11655 #endif /* DEBUG_STEP */
11656
11657 static int
11658 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11659                             xmlXPathStepOpPtr op,
11660                             xmlNodeSetPtr set,
11661                             int contextSize,
11662                             int hasNsNodes)
11663 {
11664     if (op->ch1 != -1) {
11665         xmlXPathCompExprPtr comp = ctxt->comp;
11666         /*
11667         * Process inner predicates first.
11668         */
11669         if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11670             /*
11671             * TODO: raise an internal error.
11672             */
11673         }
11674         contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11675             &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11676         CHECK_ERROR0;
11677         if (contextSize <= 0)
11678             return(0);
11679     }
11680     if (op->ch2 != -1) {
11681         xmlXPathContextPtr xpctxt = ctxt->context;
11682         xmlNodePtr contextNode, oldContextNode;
11683         xmlDocPtr oldContextDoc;
11684         int i, res, contextPos = 0, newContextSize;
11685         xmlXPathStepOpPtr exprOp;
11686         xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11687
11688 #ifdef LIBXML_XPTR_ENABLED
11689         /*
11690         * URGENT TODO: Check the following:
11691         *  We don't expect location sets if evaluating prediates, right?
11692         *  Only filters should expect location sets, right?
11693         */
11694 #endif
11695         /*
11696         * SPEC XPath 1.0:
11697         *  "For each node in the node-set to be filtered, the
11698         *  PredicateExpr is evaluated with that node as the
11699         *  context node, with the number of nodes in the
11700         *  node-set as the context size, and with the proximity
11701         *  position of the node in the node-set with respect to
11702         *  the axis as the context position;"
11703         * @oldset is the node-set" to be filtered.
11704         *
11705         * SPEC XPath 1.0:
11706         *  "only predicates change the context position and
11707         *  context size (see [2.4 Predicates])."
11708         * Example:
11709         *   node-set  context pos
11710         *    nA         1
11711         *    nB         2
11712         *    nC         3
11713         *   After applying predicate [position() > 1] :
11714         *   node-set  context pos
11715         *    nB         1
11716         *    nC         2
11717         */
11718         oldContextNode = xpctxt->node;
11719         oldContextDoc = xpctxt->doc;
11720         /*
11721         * Get the expression of this predicate.
11722         */
11723         exprOp = &ctxt->comp->steps[op->ch2];
11724         newContextSize = 0;
11725         for (i = 0; i < set->nodeNr; i++) {
11726             if (set->nodeTab[i] == NULL)
11727                 continue;
11728
11729             contextNode = set->nodeTab[i];
11730             xpctxt->node = contextNode;
11731             xpctxt->contextSize = contextSize;
11732             xpctxt->proximityPosition = ++contextPos;
11733
11734             /*
11735             * Also set the xpath document in case things like
11736             * key() are evaluated in the predicate.
11737             */
11738             if ((contextNode->type != XML_NAMESPACE_DECL) &&
11739                 (contextNode->doc != NULL))
11740                 xpctxt->doc = contextNode->doc;
11741             /*
11742             * Evaluate the predicate expression with 1 context node
11743             * at a time; this node is packaged into a node set; this
11744             * node set is handed over to the evaluation mechanism.
11745             */
11746             if (contextObj == NULL)
11747                 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11748             else {
11749                 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11750                     contextNode) < 0) {
11751                     ctxt->error = XPATH_MEMORY_ERROR;
11752                     goto evaluation_exit;
11753                 }
11754             }
11755
11756             valuePush(ctxt, contextObj);
11757
11758             res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11759
11760             if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11761                 xmlXPathNodeSetClear(set, hasNsNodes);
11762                 newContextSize = 0;
11763                 goto evaluation_exit;
11764             }
11765
11766             if (res != 0) {
11767                 newContextSize++;
11768             } else {
11769                 /*
11770                 * Remove the entry from the initial node set.
11771                 */
11772                 set->nodeTab[i] = NULL;
11773                 if (contextNode->type == XML_NAMESPACE_DECL)
11774                     xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11775             }
11776             if (ctxt->value == contextObj) {
11777                 /*
11778                 * Don't free the temporary XPath object holding the
11779                 * context node, in order to avoid massive recreation
11780                 * inside this loop.
11781                 */
11782                 valuePop(ctxt);
11783                 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11784             } else {
11785                 /*
11786                 * TODO: The object was lost in the evaluation machinery.
11787                 *  Can this happen? Maybe in internal-error cases.
11788                 */
11789                 contextObj = NULL;
11790             }
11791         }
11792
11793         if (contextObj != NULL) {
11794             if (ctxt->value == contextObj)
11795                 valuePop(ctxt);
11796             xmlXPathReleaseObject(xpctxt, contextObj);
11797         }
11798 evaluation_exit:
11799         if (exprRes != NULL)
11800             xmlXPathReleaseObject(ctxt->context, exprRes);
11801         /*
11802         * Reset/invalidate the context.
11803         */
11804         xpctxt->node = oldContextNode;
11805         xpctxt->doc = oldContextDoc;
11806         xpctxt->contextSize = -1;
11807         xpctxt->proximityPosition = -1;
11808         return(newContextSize);
11809     }
11810     return(contextSize);
11811 }
11812
11813 static int
11814 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11815                                       xmlXPathStepOpPtr op,
11816                                       xmlNodeSetPtr set,
11817                                       int contextSize,
11818                                       int minPos,
11819                                       int maxPos,
11820                                       int hasNsNodes)
11821 {
11822     if (op->ch1 != -1) {
11823         xmlXPathCompExprPtr comp = ctxt->comp;
11824         if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11825             /*
11826             * TODO: raise an internal error.
11827             */
11828         }
11829         contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11830             &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11831         CHECK_ERROR0;
11832         if (contextSize <= 0)
11833             return(0);
11834     }
11835     /*
11836     * Check if the node set contains a sufficient number of nodes for
11837     * the requested range.
11838     */
11839     if (contextSize < minPos) {
11840         xmlXPathNodeSetClear(set, hasNsNodes);
11841         return(0);
11842     }
11843     if (op->ch2 == -1) {
11844         /*
11845         * TODO: Can this ever happen?
11846         */
11847         return (contextSize);
11848     } else {
11849         xmlDocPtr oldContextDoc;
11850         int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11851         xmlXPathStepOpPtr exprOp;
11852         xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11853         xmlNodePtr oldContextNode, contextNode = NULL;
11854         xmlXPathContextPtr xpctxt = ctxt->context;
11855         int frame;
11856
11857 #ifdef LIBXML_XPTR_ENABLED
11858             /*
11859             * URGENT TODO: Check the following:
11860             *  We don't expect location sets if evaluating prediates, right?
11861             *  Only filters should expect location sets, right?
11862         */
11863 #endif /* LIBXML_XPTR_ENABLED */
11864
11865         /*
11866         * Save old context.
11867         */
11868         oldContextNode = xpctxt->node;
11869         oldContextDoc = xpctxt->doc;
11870         /*
11871         * Get the expression of this predicate.
11872         */
11873         exprOp = &ctxt->comp->steps[op->ch2];
11874         for (i = 0; i < set->nodeNr; i++) {
11875             xmlXPathObjectPtr tmp;
11876
11877             if (set->nodeTab[i] == NULL)
11878                 continue;
11879
11880             contextNode = set->nodeTab[i];
11881             xpctxt->node = contextNode;
11882             xpctxt->contextSize = contextSize;
11883             xpctxt->proximityPosition = ++contextPos;
11884
11885             /*
11886             * Initialize the new set.
11887             * Also set the xpath document in case things like
11888             * key() evaluation are attempted on the predicate
11889             */
11890             if ((contextNode->type != XML_NAMESPACE_DECL) &&
11891                 (contextNode->doc != NULL))
11892                 xpctxt->doc = contextNode->doc;
11893             /*
11894             * Evaluate the predicate expression with 1 context node
11895             * at a time; this node is packaged into a node set; this
11896             * node set is handed over to the evaluation mechanism.
11897             */
11898             if (contextObj == NULL)
11899                 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11900             else {
11901                 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11902                     contextNode) < 0) {
11903                     ctxt->error = XPATH_MEMORY_ERROR;
11904                     goto evaluation_exit;
11905                 }
11906             }
11907
11908             frame = xmlXPathSetFrame(ctxt);
11909             valuePush(ctxt, contextObj);
11910             res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11911             tmp = valuePop(ctxt);
11912             xmlXPathPopFrame(ctxt, frame);
11913
11914             if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11915                 while (tmp != contextObj) {
11916                     /*
11917                      * Free up the result
11918                      * then pop off contextObj, which will be freed later
11919                      */
11920                     xmlXPathReleaseObject(xpctxt, tmp);
11921                     tmp = valuePop(ctxt);
11922                 }
11923                 goto evaluation_error;
11924             }
11925             /* push the result back onto the stack */
11926             valuePush(ctxt, tmp);
11927
11928             if (res)
11929                 pos++;
11930
11931             if (res && (pos >= minPos) && (pos <= maxPos)) {
11932                 /*
11933                 * Fits in the requested range.
11934                 */
11935                 newContextSize++;
11936                 if (minPos == maxPos) {
11937                     /*
11938                     * Only 1 node was requested.
11939                     */
11940                     if (contextNode->type == XML_NAMESPACE_DECL) {
11941                         /*
11942                         * As always: take care of those nasty
11943                         * namespace nodes.
11944                         */
11945                         set->nodeTab[i] = NULL;
11946                     }
11947                     xmlXPathNodeSetClear(set, hasNsNodes);
11948                     set->nodeNr = 1;
11949                     set->nodeTab[0] = contextNode;
11950                     goto evaluation_exit;
11951                 }
11952                 if (pos == maxPos) {
11953                     /*
11954                     * We are done.
11955                     */
11956                     xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11957                     goto evaluation_exit;
11958                 }
11959             } else {
11960                 /*
11961                 * Remove the entry from the initial node set.
11962                 */
11963                 set->nodeTab[i] = NULL;
11964                 if (contextNode->type == XML_NAMESPACE_DECL)
11965                     xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11966             }
11967             if (exprRes != NULL) {
11968                 xmlXPathReleaseObject(ctxt->context, exprRes);
11969                 exprRes = NULL;
11970             }
11971             if (ctxt->value == contextObj) {
11972                 /*
11973                 * Don't free the temporary XPath object holding the
11974                 * context node, in order to avoid massive recreation
11975                 * inside this loop.
11976                 */
11977                 valuePop(ctxt);
11978                 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11979             } else {
11980                 /*
11981                 * The object was lost in the evaluation machinery.
11982                 * Can this happen? Maybe in case of internal-errors.
11983                 */
11984                 contextObj = NULL;
11985             }
11986         }
11987         goto evaluation_exit;
11988
11989 evaluation_error:
11990         xmlXPathNodeSetClear(set, hasNsNodes);
11991         newContextSize = 0;
11992
11993 evaluation_exit:
11994         if (contextObj != NULL) {
11995             if (ctxt->value == contextObj)
11996                 valuePop(ctxt);
11997             xmlXPathReleaseObject(xpctxt, contextObj);
11998         }
11999         if (exprRes != NULL)
12000             xmlXPathReleaseObject(ctxt->context, exprRes);
12001         /*
12002         * Reset/invalidate the context.
12003         */
12004         xpctxt->node = oldContextNode;
12005         xpctxt->doc = oldContextDoc;
12006         xpctxt->contextSize = -1;
12007         xpctxt->proximityPosition = -1;
12008         return(newContextSize);
12009     }
12010     return(contextSize);
12011 }
12012
12013 static int
12014 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12015                             xmlXPathStepOpPtr op,
12016                             int *maxPos)
12017 {
12018
12019     xmlXPathStepOpPtr exprOp;
12020
12021     /*
12022     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12023     */
12024
12025     /*
12026     * If not -1, then ch1 will point to:
12027     * 1) For predicates (XPATH_OP_PREDICATE):
12028     *    - an inner predicate operator
12029     * 2) For filters (XPATH_OP_FILTER):
12030     *    - an inner filter operater OR
12031     *    - an expression selecting the node set.
12032     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
12033     */
12034     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12035         return(0);
12036
12037     if (op->ch2 != -1) {
12038         exprOp = &ctxt->comp->steps[op->ch2];
12039     } else
12040         return(0);
12041
12042     if ((exprOp != NULL) &&
12043         (exprOp->op == XPATH_OP_VALUE) &&
12044         (exprOp->value4 != NULL) &&
12045         (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12046     {
12047         /*
12048         * We have a "[n]" predicate here.
12049         * TODO: Unfortunately this simplistic test here is not
12050         * able to detect a position() predicate in compound
12051         * expressions like "[@attr = 'a" and position() = 1],
12052         * and even not the usage of position() in
12053         * "[position() = 1]"; thus - obviously - a position-range,
12054         * like it "[position() < 5]", is also not detected.
12055         * Maybe we could rewrite the AST to ease the optimization.
12056         */
12057         *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12058
12059         if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
12060             (float) *maxPos)
12061         {
12062             return(1);
12063         }
12064     }
12065     return(0);
12066 }
12067
12068 static int
12069 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12070                            xmlXPathStepOpPtr op,
12071                            xmlNodePtr * first, xmlNodePtr * last,
12072                            int toBool)
12073 {
12074
12075 #define XP_TEST_HIT \
12076     if (hasAxisRange != 0) { \
12077         if (++pos == maxPos) { \
12078             if (addNode(seq, cur) < 0) \
12079                 ctxt->error = XPATH_MEMORY_ERROR; \
12080             goto axis_range_end; } \
12081     } else { \
12082         if (addNode(seq, cur) < 0) \
12083             ctxt->error = XPATH_MEMORY_ERROR; \
12084         if (breakOnFirstHit) goto first_hit; }
12085
12086 #define XP_TEST_HIT_NS \
12087     if (hasAxisRange != 0) { \
12088         if (++pos == maxPos) { \
12089             hasNsNodes = 1; \
12090             if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12091                 ctxt->error = XPATH_MEMORY_ERROR; \
12092         goto axis_range_end; } \
12093     } else { \
12094         hasNsNodes = 1; \
12095         if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12096             ctxt->error = XPATH_MEMORY_ERROR; \
12097         if (breakOnFirstHit) goto first_hit; }
12098
12099     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12100     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12101     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12102     const xmlChar *prefix = op->value4;
12103     const xmlChar *name = op->value5;
12104     const xmlChar *URI = NULL;
12105
12106 #ifdef DEBUG_STEP
12107     int nbMatches = 0, prevMatches = 0;
12108 #endif
12109     int total = 0, hasNsNodes = 0;
12110     /* The popped object holding the context nodes */
12111     xmlXPathObjectPtr obj;
12112     /* The set of context nodes for the node tests */
12113     xmlNodeSetPtr contextSeq;
12114     int contextIdx;
12115     xmlNodePtr contextNode;
12116     /* The final resulting node set wrt to all context nodes */
12117     xmlNodeSetPtr outSeq;
12118     /*
12119     * The temporary resulting node set wrt 1 context node.
12120     * Used to feed predicate evaluation.
12121     */
12122     xmlNodeSetPtr seq;
12123     xmlNodePtr cur;
12124     /* First predicate operator */
12125     xmlXPathStepOpPtr predOp;
12126     int maxPos; /* The requested position() (when a "[n]" predicate) */
12127     int hasPredicateRange, hasAxisRange, pos, size, newSize;
12128     int breakOnFirstHit;
12129
12130     xmlXPathTraversalFunction next = NULL;
12131     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12132     xmlXPathNodeSetMergeFunction mergeAndClear;
12133     xmlNodePtr oldContextNode;
12134     xmlXPathContextPtr xpctxt = ctxt->context;
12135
12136
12137     CHECK_TYPE0(XPATH_NODESET);
12138     obj = valuePop(ctxt);
12139     /*
12140     * Setup namespaces.
12141     */
12142     if (prefix != NULL) {
12143         URI = xmlXPathNsLookup(xpctxt, prefix);
12144         if (URI == NULL) {
12145             xmlXPathReleaseObject(xpctxt, obj);
12146             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12147         }
12148     }
12149     /*
12150     * Setup axis.
12151     *
12152     * MAYBE FUTURE TODO: merging optimizations:
12153     * - If the nodes to be traversed wrt to the initial nodes and
12154     *   the current axis cannot overlap, then we could avoid searching
12155     *   for duplicates during the merge.
12156     *   But the question is how/when to evaluate if they cannot overlap.
12157     *   Example: if we know that for two initial nodes, the one is
12158     *   not in the ancestor-or-self axis of the other, then we could safely
12159     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12160     *   the descendant-or-self axis.
12161     */
12162     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12163     switch (axis) {
12164         case AXIS_ANCESTOR:
12165             first = NULL;
12166             next = xmlXPathNextAncestor;
12167             break;
12168         case AXIS_ANCESTOR_OR_SELF:
12169             first = NULL;
12170             next = xmlXPathNextAncestorOrSelf;
12171             break;
12172         case AXIS_ATTRIBUTE:
12173             first = NULL;
12174             last = NULL;
12175             next = xmlXPathNextAttribute;
12176             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12177             break;
12178         case AXIS_CHILD:
12179             last = NULL;
12180             if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12181                 (type == NODE_TYPE_NODE))
12182             {
12183                 /*
12184                 * Optimization if an element node type is 'element'.
12185                 */
12186                 next = xmlXPathNextChildElement;
12187             } else
12188                 next = xmlXPathNextChild;
12189             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12190             break;
12191         case AXIS_DESCENDANT:
12192             last = NULL;
12193             next = xmlXPathNextDescendant;
12194             break;
12195         case AXIS_DESCENDANT_OR_SELF:
12196             last = NULL;
12197             next = xmlXPathNextDescendantOrSelf;
12198             break;
12199         case AXIS_FOLLOWING:
12200             last = NULL;
12201             next = xmlXPathNextFollowing;
12202             break;
12203         case AXIS_FOLLOWING_SIBLING:
12204             last = NULL;
12205             next = xmlXPathNextFollowingSibling;
12206             break;
12207         case AXIS_NAMESPACE:
12208             first = NULL;
12209             last = NULL;
12210             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12211             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12212             break;
12213         case AXIS_PARENT:
12214             first = NULL;
12215             next = xmlXPathNextParent;
12216             break;
12217         case AXIS_PRECEDING:
12218             first = NULL;
12219             next = xmlXPathNextPrecedingInternal;
12220             break;
12221         case AXIS_PRECEDING_SIBLING:
12222             first = NULL;
12223             next = xmlXPathNextPrecedingSibling;
12224             break;
12225         case AXIS_SELF:
12226             first = NULL;
12227             last = NULL;
12228             next = xmlXPathNextSelf;
12229             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12230             break;
12231     }
12232
12233 #ifdef DEBUG_STEP
12234     xmlXPathDebugDumpStepAxis(op,
12235         (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12236 #endif
12237
12238     if (next == NULL) {
12239         xmlXPathReleaseObject(xpctxt, obj);
12240         return(0);
12241     }
12242     contextSeq = obj->nodesetval;
12243     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12244         xmlXPathReleaseObject(xpctxt, obj);
12245         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12246         return(0);
12247     }
12248     /*
12249     * Predicate optimization ---------------------------------------------
12250     * If this step has a last predicate, which contains a position(),
12251     * then we'll optimize (although not exactly "position()", but only
12252     * the  short-hand form, i.e., "[n]".
12253     *
12254     * Example - expression "/foo[parent::bar][1]":
12255     *
12256     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12257     *   ROOT                               -- op->ch1
12258     *   PREDICATE                          -- op->ch2 (predOp)
12259     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12260     *       SORT
12261     *         COLLECT  'parent' 'name' 'node' bar
12262     *           NODE
12263     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12264     *
12265     */
12266     maxPos = 0;
12267     predOp = NULL;
12268     hasPredicateRange = 0;
12269     hasAxisRange = 0;
12270     if (op->ch2 != -1) {
12271         /*
12272         * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12273         */
12274         predOp = &ctxt->comp->steps[op->ch2];
12275         if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12276             if (predOp->ch1 != -1) {
12277                 /*
12278                 * Use the next inner predicate operator.
12279                 */
12280                 predOp = &ctxt->comp->steps[predOp->ch1];
12281                 hasPredicateRange = 1;
12282             } else {
12283                 /*
12284                 * There's no other predicate than the [n] predicate.
12285                 */
12286                 predOp = NULL;
12287                 hasAxisRange = 1;
12288             }
12289         }
12290     }
12291     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12292     /*
12293     * Axis traversal -----------------------------------------------------
12294     */
12295     /*
12296      * 2.3 Node Tests
12297      *  - For the attribute axis, the principal node type is attribute.
12298      *  - For the namespace axis, the principal node type is namespace.
12299      *  - For other axes, the principal node type is element.
12300      *
12301      * A node test * is true for any node of the
12302      * principal node type. For example, child::* will
12303      * select all element children of the context node
12304      */
12305     oldContextNode = xpctxt->node;
12306     addNode = xmlXPathNodeSetAddUnique;
12307     outSeq = NULL;
12308     seq = NULL;
12309     contextNode = NULL;
12310     contextIdx = 0;
12311
12312
12313     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12314            (ctxt->error == XPATH_EXPRESSION_OK)) {
12315         xpctxt->node = contextSeq->nodeTab[contextIdx++];
12316
12317         if (seq == NULL) {
12318             seq = xmlXPathNodeSetCreate(NULL);
12319             if (seq == NULL) {
12320                 total = 0;
12321                 goto error;
12322             }
12323         }
12324         /*
12325         * Traverse the axis and test the nodes.
12326         */
12327         pos = 0;
12328         cur = NULL;
12329         hasNsNodes = 0;
12330         do {
12331             cur = next(ctxt, cur);
12332             if (cur == NULL)
12333                 break;
12334
12335             /*
12336             * QUESTION TODO: What does the "first" and "last" stuff do?
12337             */
12338             if ((first != NULL) && (*first != NULL)) {
12339                 if (*first == cur)
12340                     break;
12341                 if (((total % 256) == 0) &&
12342 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12343                     (xmlXPathCmpNodesExt(*first, cur) >= 0))
12344 #else
12345                     (xmlXPathCmpNodes(*first, cur) >= 0))
12346 #endif
12347                 {
12348                     break;
12349                 }
12350             }
12351             if ((last != NULL) && (*last != NULL)) {
12352                 if (*last == cur)
12353                     break;
12354                 if (((total % 256) == 0) &&
12355 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12356                     (xmlXPathCmpNodesExt(cur, *last) >= 0))
12357 #else
12358                     (xmlXPathCmpNodes(cur, *last) >= 0))
12359 #endif
12360                 {
12361                     break;
12362                 }
12363             }
12364
12365             total++;
12366
12367 #ifdef DEBUG_STEP
12368             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12369 #endif
12370
12371             switch (test) {
12372                 case NODE_TEST_NONE:
12373                     total = 0;
12374                     STRANGE
12375                     goto error;
12376                 case NODE_TEST_TYPE:
12377                     /*
12378                     * TODO: Don't we need to use
12379                     *  xmlXPathNodeSetAddNs() for namespace nodes here?
12380                     *  Surprisingly, some c14n tests fail, if we do this.
12381                     */
12382                     if (type == NODE_TYPE_NODE) {
12383                         switch (cur->type) {
12384                             case XML_DOCUMENT_NODE:
12385                             case XML_HTML_DOCUMENT_NODE:
12386 #ifdef LIBXML_DOCB_ENABLED
12387                             case XML_DOCB_DOCUMENT_NODE:
12388 #endif
12389                             case XML_ELEMENT_NODE:
12390                             case XML_ATTRIBUTE_NODE:
12391                             case XML_PI_NODE:
12392                             case XML_COMMENT_NODE:
12393                             case XML_CDATA_SECTION_NODE:
12394                             case XML_TEXT_NODE:
12395                             case XML_NAMESPACE_DECL:
12396                                 XP_TEST_HIT
12397                                 break;
12398                             default:
12399                                 break;
12400                         }
12401                     } else if (cur->type == type) {
12402                         if (cur->type == XML_NAMESPACE_DECL)
12403                             XP_TEST_HIT_NS
12404                         else
12405                             XP_TEST_HIT
12406                     } else if ((type == NODE_TYPE_TEXT) &&
12407                          (cur->type == XML_CDATA_SECTION_NODE))
12408                     {
12409                         XP_TEST_HIT
12410                     }
12411                     break;
12412                 case NODE_TEST_PI:
12413                     if ((cur->type == XML_PI_NODE) &&
12414                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12415                     {
12416                         XP_TEST_HIT
12417                     }
12418                     break;
12419                 case NODE_TEST_ALL:
12420                     if (axis == AXIS_ATTRIBUTE) {
12421                         if (cur->type == XML_ATTRIBUTE_NODE)
12422                         {
12423                             XP_TEST_HIT
12424                         }
12425                     } else if (axis == AXIS_NAMESPACE) {
12426                         if (cur->type == XML_NAMESPACE_DECL)
12427                         {
12428                             XP_TEST_HIT_NS
12429                         }
12430                     } else {
12431                         if (cur->type == XML_ELEMENT_NODE) {
12432                             if (prefix == NULL)
12433                             {
12434                                 XP_TEST_HIT
12435
12436                             } else if ((cur->ns != NULL) &&
12437                                 (xmlStrEqual(URI, cur->ns->href)))
12438                             {
12439                                 XP_TEST_HIT
12440                             }
12441                         }
12442                     }
12443                     break;
12444                 case NODE_TEST_NS:{
12445                         TODO;
12446                         break;
12447                     }
12448                 case NODE_TEST_NAME:
12449                     if (axis == AXIS_ATTRIBUTE) {
12450                         if (cur->type != XML_ATTRIBUTE_NODE)
12451                             break;
12452                     } else if (axis == AXIS_NAMESPACE) {
12453                         if (cur->type != XML_NAMESPACE_DECL)
12454                             break;
12455                     } else {
12456                         if (cur->type != XML_ELEMENT_NODE)
12457                             break;
12458                     }
12459                     switch (cur->type) {
12460                         case XML_ELEMENT_NODE:
12461                             if (xmlStrEqual(name, cur->name)) {
12462                                 if (prefix == NULL) {
12463                                     if (cur->ns == NULL)
12464                                     {
12465                                         XP_TEST_HIT
12466                                     }
12467                                 } else {
12468                                     if ((cur->ns != NULL) &&
12469                                         (xmlStrEqual(URI, cur->ns->href)))
12470                                     {
12471                                         XP_TEST_HIT
12472                                     }
12473                                 }
12474                             }
12475                             break;
12476                         case XML_ATTRIBUTE_NODE:{
12477                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12478
12479                                 if (xmlStrEqual(name, attr->name)) {
12480                                     if (prefix == NULL) {
12481                                         if ((attr->ns == NULL) ||
12482                                             (attr->ns->prefix == NULL))
12483                                         {
12484                                             XP_TEST_HIT
12485                                         }
12486                                     } else {
12487                                         if ((attr->ns != NULL) &&
12488                                             (xmlStrEqual(URI,
12489                                               attr->ns->href)))
12490                                         {
12491                                             XP_TEST_HIT
12492                                         }
12493                                     }
12494                                 }
12495                                 break;
12496                             }
12497                         case XML_NAMESPACE_DECL:
12498                             if (cur->type == XML_NAMESPACE_DECL) {
12499                                 xmlNsPtr ns = (xmlNsPtr) cur;
12500
12501                                 if ((ns->prefix != NULL) && (name != NULL)
12502                                     && (xmlStrEqual(ns->prefix, name)))
12503                                 {
12504                                     XP_TEST_HIT_NS
12505                                 }
12506                             }
12507                             break;
12508                         default:
12509                             break;
12510                     }
12511                     break;
12512             } /* switch(test) */
12513         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12514
12515         goto apply_predicates;
12516
12517 axis_range_end: /* ----------------------------------------------------- */
12518         /*
12519         * We have a "/foo[n]", and position() = n was reached.
12520         * Note that we can have as well "/foo/::parent::foo[1]", so
12521         * a duplicate-aware merge is still needed.
12522         * Merge with the result.
12523         */
12524         if (outSeq == NULL) {
12525             outSeq = seq;
12526             seq = NULL;
12527         } else
12528             outSeq = mergeAndClear(outSeq, seq, 0);
12529         /*
12530         * Break if only a true/false result was requested.
12531         */
12532         if (toBool)
12533             break;
12534         continue;
12535
12536 first_hit: /* ---------------------------------------------------------- */
12537         /*
12538         * Break if only a true/false result was requested and
12539         * no predicates existed and a node test succeeded.
12540         */
12541         if (outSeq == NULL) {
12542             outSeq = seq;
12543             seq = NULL;
12544         } else
12545             outSeq = mergeAndClear(outSeq, seq, 0);
12546         break;
12547
12548 #ifdef DEBUG_STEP
12549         if (seq != NULL)
12550             nbMatches += seq->nodeNr;
12551 #endif
12552
12553 apply_predicates: /* --------------------------------------------------- */
12554         if (ctxt->error != XPATH_EXPRESSION_OK)
12555             goto error;
12556
12557         /*
12558         * Apply predicates.
12559         */
12560         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12561             /*
12562             * E.g. when we have a "/foo[some expression][n]".
12563             */
12564             /*
12565             * QUESTION TODO: The old predicate evaluation took into
12566             *  account location-sets.
12567             *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12568             *  Do we expect such a set here?
12569             *  All what I learned now from the evaluation semantics
12570             *  does not indicate that a location-set will be processed
12571             *  here, so this looks OK.
12572             */
12573             /*
12574             * Iterate over all predicates, starting with the outermost
12575             * predicate.
12576             * TODO: Problem: we cannot execute the inner predicates first
12577             *  since we cannot go back *up* the operator tree!
12578             *  Options we have:
12579             *  1) Use of recursive functions (like is it currently done
12580             *     via xmlXPathCompOpEval())
12581             *  2) Add a predicate evaluation information stack to the
12582             *     context struct
12583             *  3) Change the way the operators are linked; we need a
12584             *     "parent" field on xmlXPathStepOp
12585             *
12586             * For the moment, I'll try to solve this with a recursive
12587             * function: xmlXPathCompOpEvalPredicate().
12588             */
12589             size = seq->nodeNr;
12590             if (hasPredicateRange != 0)
12591                 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12592                     predOp, seq, size, maxPos, maxPos, hasNsNodes);
12593             else
12594                 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12595                     predOp, seq, size, hasNsNodes);
12596
12597             if (ctxt->error != XPATH_EXPRESSION_OK) {
12598                 total = 0;
12599                 goto error;
12600             }
12601             /*
12602             * Add the filtered set of nodes to the result node set.
12603             */
12604             if (newSize == 0) {
12605                 /*
12606                 * The predicates filtered all nodes out.
12607                 */
12608                 xmlXPathNodeSetClear(seq, hasNsNodes);
12609             } else if (seq->nodeNr > 0) {
12610                 /*
12611                 * Add to result set.
12612                 */
12613                 if (outSeq == NULL) {
12614                     if (size != newSize) {
12615                         /*
12616                         * We need to merge and clear here, since
12617                         * the sequence will contained NULLed entries.
12618                         */
12619                         outSeq = mergeAndClear(NULL, seq, 1);
12620                     } else {
12621                         outSeq = seq;
12622                         seq = NULL;
12623                     }
12624                 } else
12625                     outSeq = mergeAndClear(outSeq, seq,
12626                         (size != newSize) ? 1: 0);
12627                 /*
12628                 * Break if only a true/false result was requested.
12629                 */
12630                 if (toBool)
12631                     break;
12632             }
12633         } else if (seq->nodeNr > 0) {
12634             /*
12635             * Add to result set.
12636             */
12637             if (outSeq == NULL) {
12638                 outSeq = seq;
12639                 seq = NULL;
12640             } else {
12641                 outSeq = mergeAndClear(outSeq, seq, 0);
12642             }
12643         }
12644     }
12645
12646 error:
12647     if ((obj->boolval) && (obj->user != NULL)) {
12648         /*
12649         * QUESTION TODO: What does this do and why?
12650         * TODO: Do we have to do this also for the "error"
12651         * cleanup further down?
12652         */
12653         ctxt->value->boolval = 1;
12654         ctxt->value->user = obj->user;
12655         obj->user = NULL;
12656         obj->boolval = 0;
12657     }
12658     xmlXPathReleaseObject(xpctxt, obj);
12659
12660     /*
12661     * Ensure we return at least an emtpy set.
12662     */
12663     if (outSeq == NULL) {
12664         if ((seq != NULL) && (seq->nodeNr == 0))
12665             outSeq = seq;
12666         else
12667             outSeq = xmlXPathNodeSetCreate(NULL);
12668         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12669     }
12670     if ((seq != NULL) && (seq != outSeq)) {
12671          xmlXPathFreeNodeSet(seq);
12672     }
12673     /*
12674     * Hand over the result. Better to push the set also in
12675     * case of errors.
12676     */
12677     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12678     /*
12679     * Reset the context node.
12680     */
12681     xpctxt->node = oldContextNode;
12682
12683 #ifdef DEBUG_STEP
12684     xmlGenericError(xmlGenericErrorContext,
12685         "\nExamined %d nodes, found %d nodes at that step\n",
12686         total, nbMatches);
12687 #endif
12688
12689     return(total);
12690 }
12691
12692 static int
12693 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12694                               xmlXPathStepOpPtr op, xmlNodePtr * first);
12695
12696 /**
12697  * xmlXPathCompOpEvalFirst:
12698  * @ctxt:  the XPath parser context with the compiled expression
12699  * @op:  an XPath compiled operation
12700  * @first:  the first elem found so far
12701  *
12702  * Evaluate the Precompiled XPath operation searching only the first
12703  * element in document order
12704  *
12705  * Returns the number of examined objects.
12706  */
12707 static int
12708 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12709                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12710 {
12711     int total = 0, cur;
12712     xmlXPathCompExprPtr comp;
12713     xmlXPathObjectPtr arg1, arg2;
12714
12715     CHECK_ERROR0;
12716     comp = ctxt->comp;
12717     switch (op->op) {
12718         case XPATH_OP_END:
12719             return (0);
12720         case XPATH_OP_UNION:
12721             total =
12722                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12723                                         first);
12724             CHECK_ERROR0;
12725             if ((ctxt->value != NULL)
12726                 && (ctxt->value->type == XPATH_NODESET)
12727                 && (ctxt->value->nodesetval != NULL)
12728                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12729                 /*
12730                  * limit tree traversing to first node in the result
12731                  */
12732                 /*
12733                 * OPTIMIZE TODO: This implicitely sorts
12734                 *  the result, even if not needed. E.g. if the argument
12735                 *  of the count() function, no sorting is needed.
12736                 * OPTIMIZE TODO: How do we know if the node-list wasn't
12737                 *  aready sorted?
12738                 */
12739                 if (ctxt->value->nodesetval->nodeNr > 1)
12740                     xmlXPathNodeSetSort(ctxt->value->nodesetval);
12741                 *first = ctxt->value->nodesetval->nodeTab[0];
12742             }
12743             cur =
12744                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12745                                         first);
12746             CHECK_ERROR0;
12747             CHECK_TYPE0(XPATH_NODESET);
12748             arg2 = valuePop(ctxt);
12749
12750             CHECK_TYPE0(XPATH_NODESET);
12751             arg1 = valuePop(ctxt);
12752
12753             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12754                                                     arg2->nodesetval);
12755             valuePush(ctxt, arg1);
12756             xmlXPathReleaseObject(ctxt->context, arg2);
12757             /* optimizer */
12758             if (total > cur)
12759                 xmlXPathCompSwap(op);
12760             return (total + cur);
12761         case XPATH_OP_ROOT:
12762             xmlXPathRoot(ctxt);
12763             return (0);
12764         case XPATH_OP_NODE:
12765             if (op->ch1 != -1)
12766                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12767             CHECK_ERROR0;
12768             if (op->ch2 != -1)
12769                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12770             CHECK_ERROR0;
12771             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12772                 ctxt->context->node));
12773             return (total);
12774         case XPATH_OP_RESET:
12775             if (op->ch1 != -1)
12776                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12777             CHECK_ERROR0;
12778             if (op->ch2 != -1)
12779                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12780             CHECK_ERROR0;
12781             ctxt->context->node = NULL;
12782             return (total);
12783         case XPATH_OP_COLLECT:{
12784                 if (op->ch1 == -1)
12785                     return (total);
12786
12787                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12788                 CHECK_ERROR0;
12789
12790                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12791                 return (total);
12792             }
12793         case XPATH_OP_VALUE:
12794             valuePush(ctxt,
12795                       xmlXPathCacheObjectCopy(ctxt->context,
12796                         (xmlXPathObjectPtr) op->value4));
12797             return (0);
12798         case XPATH_OP_SORT:
12799             if (op->ch1 != -1)
12800                 total +=
12801                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12802                                             first);
12803             CHECK_ERROR0;
12804             if ((ctxt->value != NULL)
12805                 && (ctxt->value->type == XPATH_NODESET)
12806                 && (ctxt->value->nodesetval != NULL)
12807                 && (ctxt->value->nodesetval->nodeNr > 1))
12808                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12809             return (total);
12810 #ifdef XP_OPTIMIZED_FILTER_FIRST
12811         case XPATH_OP_FILTER:
12812                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12813             return (total);
12814 #endif
12815         default:
12816             return (xmlXPathCompOpEval(ctxt, op));
12817     }
12818 }
12819
12820 /**
12821  * xmlXPathCompOpEvalLast:
12822  * @ctxt:  the XPath parser context with the compiled expression
12823  * @op:  an XPath compiled operation
12824  * @last:  the last elem found so far
12825  *
12826  * Evaluate the Precompiled XPath operation searching only the last
12827  * element in document order
12828  *
12829  * Returns the number of nodes traversed
12830  */
12831 static int
12832 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12833                        xmlNodePtr * last)
12834 {
12835     int total = 0, cur;
12836     xmlXPathCompExprPtr comp;
12837     xmlXPathObjectPtr arg1, arg2;
12838     xmlNodePtr bak;
12839     xmlDocPtr bakd;
12840     int pp;
12841     int cs;
12842
12843     CHECK_ERROR0;
12844     comp = ctxt->comp;
12845     switch (op->op) {
12846         case XPATH_OP_END:
12847             return (0);
12848         case XPATH_OP_UNION:
12849             bakd = ctxt->context->doc;
12850             bak = ctxt->context->node;
12851             pp = ctxt->context->proximityPosition;
12852             cs = ctxt->context->contextSize;
12853             total =
12854                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12855             CHECK_ERROR0;
12856             if ((ctxt->value != NULL)
12857                 && (ctxt->value->type == XPATH_NODESET)
12858                 && (ctxt->value->nodesetval != NULL)
12859                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12860                 /*
12861                  * limit tree traversing to first node in the result
12862                  */
12863                 if (ctxt->value->nodesetval->nodeNr > 1)
12864                     xmlXPathNodeSetSort(ctxt->value->nodesetval);
12865                 *last =
12866                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12867                                                      nodesetval->nodeNr -
12868                                                      1];
12869             }
12870             ctxt->context->doc = bakd;
12871             ctxt->context->node = bak;
12872             ctxt->context->proximityPosition = pp;
12873             ctxt->context->contextSize = cs;
12874             cur =
12875                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12876             CHECK_ERROR0;
12877             if ((ctxt->value != NULL)
12878                 && (ctxt->value->type == XPATH_NODESET)
12879                 && (ctxt->value->nodesetval != NULL)
12880                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12881             }
12882             CHECK_TYPE0(XPATH_NODESET);
12883             arg2 = valuePop(ctxt);
12884
12885             CHECK_TYPE0(XPATH_NODESET);
12886             arg1 = valuePop(ctxt);
12887
12888             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12889                                                     arg2->nodesetval);
12890             valuePush(ctxt, arg1);
12891             xmlXPathReleaseObject(ctxt->context, arg2);
12892             /* optimizer */
12893             if (total > cur)
12894                 xmlXPathCompSwap(op);
12895             return (total + cur);
12896         case XPATH_OP_ROOT:
12897             xmlXPathRoot(ctxt);
12898             return (0);
12899         case XPATH_OP_NODE:
12900             if (op->ch1 != -1)
12901                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12902             CHECK_ERROR0;
12903             if (op->ch2 != -1)
12904                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12905             CHECK_ERROR0;
12906             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12907                 ctxt->context->node));
12908             return (total);
12909         case XPATH_OP_RESET:
12910             if (op->ch1 != -1)
12911                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12912             CHECK_ERROR0;
12913             if (op->ch2 != -1)
12914                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12915             CHECK_ERROR0;
12916             ctxt->context->node = NULL;
12917             return (total);
12918         case XPATH_OP_COLLECT:{
12919                 if (op->ch1 == -1)
12920                     return (0);
12921
12922                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12923                 CHECK_ERROR0;
12924
12925                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12926                 return (total);
12927             }
12928         case XPATH_OP_VALUE:
12929             valuePush(ctxt,
12930                       xmlXPathCacheObjectCopy(ctxt->context,
12931                         (xmlXPathObjectPtr) op->value4));
12932             return (0);
12933         case XPATH_OP_SORT:
12934             if (op->ch1 != -1)
12935                 total +=
12936                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12937                                            last);
12938             CHECK_ERROR0;
12939             if ((ctxt->value != NULL)
12940                 && (ctxt->value->type == XPATH_NODESET)
12941                 && (ctxt->value->nodesetval != NULL)
12942                 && (ctxt->value->nodesetval->nodeNr > 1))
12943                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12944             return (total);
12945         default:
12946             return (xmlXPathCompOpEval(ctxt, op));
12947     }
12948 }
12949
12950 #ifdef XP_OPTIMIZED_FILTER_FIRST
12951 static int
12952 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12953                               xmlXPathStepOpPtr op, xmlNodePtr * first)
12954 {
12955     int total = 0;
12956     xmlXPathCompExprPtr comp;
12957     xmlXPathObjectPtr res;
12958     xmlXPathObjectPtr obj;
12959     xmlNodeSetPtr oldset;
12960     xmlNodePtr oldnode;
12961     xmlDocPtr oldDoc;
12962     int i;
12963
12964     CHECK_ERROR0;
12965     comp = ctxt->comp;
12966     /*
12967     * Optimization for ()[last()] selection i.e. the last elem
12968     */
12969     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12970         (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12971         (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12972         int f = comp->steps[op->ch2].ch1;
12973
12974         if ((f != -1) &&
12975             (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12976             (comp->steps[f].value5 == NULL) &&
12977             (comp->steps[f].value == 0) &&
12978             (comp->steps[f].value4 != NULL) &&
12979             (xmlStrEqual
12980             (comp->steps[f].value4, BAD_CAST "last"))) {
12981             xmlNodePtr last = NULL;
12982
12983             total +=
12984                 xmlXPathCompOpEvalLast(ctxt,
12985                     &comp->steps[op->ch1],
12986                     &last);
12987             CHECK_ERROR0;
12988             /*
12989             * The nodeset should be in document order,
12990             * Keep only the last value
12991             */
12992             if ((ctxt->value != NULL) &&
12993                 (ctxt->value->type == XPATH_NODESET) &&
12994                 (ctxt->value->nodesetval != NULL) &&
12995                 (ctxt->value->nodesetval->nodeTab != NULL) &&
12996                 (ctxt->value->nodesetval->nodeNr > 1)) {
12997                 ctxt->value->nodesetval->nodeTab[0] =
12998                     ctxt->value->nodesetval->nodeTab[ctxt->
12999                     value->
13000                     nodesetval->
13001                     nodeNr -
13002                     1];
13003                 ctxt->value->nodesetval->nodeNr = 1;
13004                 *first = *(ctxt->value->nodesetval->nodeTab);
13005             }
13006             return (total);
13007         }
13008     }
13009
13010     if (op->ch1 != -1)
13011         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13012     CHECK_ERROR0;
13013     if (op->ch2 == -1)
13014         return (total);
13015     if (ctxt->value == NULL)
13016         return (total);
13017
13018 #ifdef LIBXML_XPTR_ENABLED
13019     oldnode = ctxt->context->node;
13020     /*
13021     * Hum are we filtering the result of an XPointer expression
13022     */
13023     if (ctxt->value->type == XPATH_LOCATIONSET) {
13024         xmlXPathObjectPtr tmp = NULL;
13025         xmlLocationSetPtr newlocset = NULL;
13026         xmlLocationSetPtr oldlocset;
13027
13028         /*
13029         * Extract the old locset, and then evaluate the result of the
13030         * expression for all the element in the locset. use it to grow
13031         * up a new locset.
13032         */
13033         CHECK_TYPE0(XPATH_LOCATIONSET);
13034         obj = valuePop(ctxt);
13035         oldlocset = obj->user;
13036         ctxt->context->node = NULL;
13037
13038         if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13039             ctxt->context->contextSize = 0;
13040             ctxt->context->proximityPosition = 0;
13041             if (op->ch2 != -1)
13042                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13043             res = valuePop(ctxt);
13044             if (res != NULL) {
13045                 xmlXPathReleaseObject(ctxt->context, res);
13046             }
13047             valuePush(ctxt, obj);
13048             CHECK_ERROR0;
13049             return (total);
13050         }
13051         newlocset = xmlXPtrLocationSetCreate(NULL);
13052
13053         for (i = 0; i < oldlocset->locNr; i++) {
13054             /*
13055             * Run the evaluation with a node list made of a
13056             * single item in the nodelocset.
13057             */
13058             ctxt->context->node = oldlocset->locTab[i]->user;
13059             ctxt->context->contextSize = oldlocset->locNr;
13060             ctxt->context->proximityPosition = i + 1;
13061             if (tmp == NULL) {
13062                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13063                     ctxt->context->node);
13064             } else {
13065                 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13066                                              ctxt->context->node) < 0) {
13067                     ctxt->error = XPATH_MEMORY_ERROR;
13068                 }
13069             }
13070             valuePush(ctxt, tmp);
13071             if (op->ch2 != -1)
13072                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13073             if (ctxt->error != XPATH_EXPRESSION_OK) {
13074                 xmlXPathFreeObject(obj);
13075                 return(0);
13076             }
13077             /*
13078             * The result of the evaluation need to be tested to
13079             * decided whether the filter succeeded or not
13080             */
13081             res = valuePop(ctxt);
13082             if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13083                 xmlXPtrLocationSetAdd(newlocset,
13084                     xmlXPathCacheObjectCopy(ctxt->context,
13085                         oldlocset->locTab[i]));
13086             }
13087             /*
13088             * Cleanup
13089             */
13090             if (res != NULL) {
13091                 xmlXPathReleaseObject(ctxt->context, res);
13092             }
13093             if (ctxt->value == tmp) {
13094                 valuePop(ctxt);
13095                 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13096                 /*
13097                 * REVISIT TODO: Don't create a temporary nodeset
13098                 * for everly iteration.
13099                 */
13100                 /* OLD: xmlXPathFreeObject(res); */
13101             } else
13102                 tmp = NULL;
13103             ctxt->context->node = NULL;
13104             /*
13105             * Only put the first node in the result, then leave.
13106             */
13107             if (newlocset->locNr > 0) {
13108                 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13109                 break;
13110             }
13111         }
13112         if (tmp != NULL) {
13113             xmlXPathReleaseObject(ctxt->context, tmp);
13114         }
13115         /*
13116         * The result is used as the new evaluation locset.
13117         */
13118         xmlXPathReleaseObject(ctxt->context, obj);
13119         ctxt->context->node = NULL;
13120         ctxt->context->contextSize = -1;
13121         ctxt->context->proximityPosition = -1;
13122         valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13123         ctxt->context->node = oldnode;
13124         return (total);
13125     }
13126 #endif /* LIBXML_XPTR_ENABLED */
13127
13128     /*
13129     * Extract the old set, and then evaluate the result of the
13130     * expression for all the element in the set. use it to grow
13131     * up a new set.
13132     */
13133     CHECK_TYPE0(XPATH_NODESET);
13134     obj = valuePop(ctxt);
13135     oldset = obj->nodesetval;
13136
13137     oldnode = ctxt->context->node;
13138     oldDoc = ctxt->context->doc;
13139     ctxt->context->node = NULL;
13140
13141     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13142         ctxt->context->contextSize = 0;
13143         ctxt->context->proximityPosition = 0;
13144         /* QUESTION TODO: Why was this code commented out?
13145             if (op->ch2 != -1)
13146                 total +=
13147                     xmlXPathCompOpEval(ctxt,
13148                         &comp->steps[op->ch2]);
13149             CHECK_ERROR0;
13150             res = valuePop(ctxt);
13151             if (res != NULL)
13152                 xmlXPathFreeObject(res);
13153         */
13154         valuePush(ctxt, obj);
13155         ctxt->context->node = oldnode;
13156         CHECK_ERROR0;
13157     } else {
13158         xmlNodeSetPtr newset;
13159         xmlXPathObjectPtr tmp = NULL;
13160         /*
13161         * Initialize the new set.
13162         * Also set the xpath document in case things like
13163         * key() evaluation are attempted on the predicate
13164         */
13165         newset = xmlXPathNodeSetCreate(NULL);
13166         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13167
13168         for (i = 0; i < oldset->nodeNr; i++) {
13169             /*
13170             * Run the evaluation with a node list made of
13171             * a single item in the nodeset.
13172             */
13173             ctxt->context->node = oldset->nodeTab[i];
13174             if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13175                 (oldset->nodeTab[i]->doc != NULL))
13176                 ctxt->context->doc = oldset->nodeTab[i]->doc;
13177             if (tmp == NULL) {
13178                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13179                     ctxt->context->node);
13180             } else {
13181                 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13182                                              ctxt->context->node) < 0) {
13183                     ctxt->error = XPATH_MEMORY_ERROR;
13184                 }
13185             }
13186             valuePush(ctxt, tmp);
13187             ctxt->context->contextSize = oldset->nodeNr;
13188             ctxt->context->proximityPosition = i + 1;
13189             if (op->ch2 != -1)
13190                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13191             if (ctxt->error != XPATH_EXPRESSION_OK) {
13192                 xmlXPathFreeNodeSet(newset);
13193                 xmlXPathFreeObject(obj);
13194                 return(0);
13195             }
13196             /*
13197             * The result of the evaluation needs to be tested to
13198             * decide whether the filter succeeded or not
13199             */
13200             res = valuePop(ctxt);
13201             if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13202                 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13203                     ctxt->error = XPATH_MEMORY_ERROR;
13204             }
13205             /*
13206             * Cleanup
13207             */
13208             if (res != NULL) {
13209                 xmlXPathReleaseObject(ctxt->context, res);
13210             }
13211             if (ctxt->value == tmp) {
13212                 valuePop(ctxt);
13213                 /*
13214                 * Don't free the temporary nodeset
13215                 * in order to avoid massive recreation inside this
13216                 * loop.
13217                 */
13218                 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13219             } else
13220                 tmp = NULL;
13221             ctxt->context->node = NULL;
13222             /*
13223             * Only put the first node in the result, then leave.
13224             */
13225             if (newset->nodeNr > 0) {
13226                 *first = *(newset->nodeTab);
13227                 break;
13228             }
13229         }
13230         if (tmp != NULL) {
13231             xmlXPathReleaseObject(ctxt->context, tmp);
13232         }
13233         /*
13234         * The result is used as the new evaluation set.
13235         */
13236         xmlXPathReleaseObject(ctxt->context, obj);
13237         ctxt->context->node = NULL;
13238         ctxt->context->contextSize = -1;
13239         ctxt->context->proximityPosition = -1;
13240         /* may want to move this past the '}' later */
13241         ctxt->context->doc = oldDoc;
13242         valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13243     }
13244     ctxt->context->node = oldnode;
13245     return(total);
13246 }
13247 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13248
13249 /**
13250  * xmlXPathCompOpEval:
13251  * @ctxt:  the XPath parser context with the compiled expression
13252  * @op:  an XPath compiled operation
13253  *
13254  * Evaluate the Precompiled XPath operation
13255  * Returns the number of nodes traversed
13256  */
13257 static int
13258 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13259 {
13260     int total = 0;
13261     int equal, ret;
13262     xmlXPathCompExprPtr comp;
13263     xmlXPathObjectPtr arg1, arg2;
13264     xmlNodePtr bak;
13265     xmlDocPtr bakd;
13266     int pp;
13267     int cs;
13268
13269     CHECK_ERROR0;
13270     comp = ctxt->comp;
13271     switch (op->op) {
13272         case XPATH_OP_END:
13273             return (0);
13274         case XPATH_OP_AND:
13275             bakd = ctxt->context->doc;
13276             bak = ctxt->context->node;
13277             pp = ctxt->context->proximityPosition;
13278             cs = ctxt->context->contextSize;
13279             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13280             CHECK_ERROR0;
13281             xmlXPathBooleanFunction(ctxt, 1);
13282             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13283                 return (total);
13284             arg2 = valuePop(ctxt);
13285             ctxt->context->doc = bakd;
13286             ctxt->context->node = bak;
13287             ctxt->context->proximityPosition = pp;
13288             ctxt->context->contextSize = cs;
13289             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13290             if (ctxt->error) {
13291                 xmlXPathFreeObject(arg2);
13292                 return(0);
13293             }
13294             xmlXPathBooleanFunction(ctxt, 1);
13295             arg1 = valuePop(ctxt);
13296             arg1->boolval &= arg2->boolval;
13297             valuePush(ctxt, arg1);
13298             xmlXPathReleaseObject(ctxt->context, arg2);
13299             return (total);
13300         case XPATH_OP_OR:
13301             bakd = ctxt->context->doc;
13302             bak = ctxt->context->node;
13303             pp = ctxt->context->proximityPosition;
13304             cs = ctxt->context->contextSize;
13305             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13306             CHECK_ERROR0;
13307             xmlXPathBooleanFunction(ctxt, 1);
13308             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13309                 return (total);
13310             arg2 = valuePop(ctxt);
13311             ctxt->context->doc = bakd;
13312             ctxt->context->node = bak;
13313             ctxt->context->proximityPosition = pp;
13314             ctxt->context->contextSize = cs;
13315             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13316             if (ctxt->error) {
13317                 xmlXPathFreeObject(arg2);
13318                 return(0);
13319             }
13320             xmlXPathBooleanFunction(ctxt, 1);
13321             arg1 = valuePop(ctxt);
13322             arg1->boolval |= arg2->boolval;
13323             valuePush(ctxt, arg1);
13324             xmlXPathReleaseObject(ctxt->context, arg2);
13325             return (total);
13326         case XPATH_OP_EQUAL:
13327             bakd = ctxt->context->doc;
13328             bak = ctxt->context->node;
13329             pp = ctxt->context->proximityPosition;
13330             cs = ctxt->context->contextSize;
13331             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13332             CHECK_ERROR0;
13333             ctxt->context->doc = bakd;
13334             ctxt->context->node = bak;
13335             ctxt->context->proximityPosition = pp;
13336             ctxt->context->contextSize = cs;
13337             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13338             CHECK_ERROR0;
13339             if (op->value)
13340                 equal = xmlXPathEqualValues(ctxt);
13341             else
13342                 equal = xmlXPathNotEqualValues(ctxt);
13343             valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13344             return (total);
13345         case XPATH_OP_CMP:
13346             bakd = ctxt->context->doc;
13347             bak = ctxt->context->node;
13348             pp = ctxt->context->proximityPosition;
13349             cs = ctxt->context->contextSize;
13350             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13351             CHECK_ERROR0;
13352             ctxt->context->doc = bakd;
13353             ctxt->context->node = bak;
13354             ctxt->context->proximityPosition = pp;
13355             ctxt->context->contextSize = cs;
13356             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13357             CHECK_ERROR0;
13358             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13359             valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13360             return (total);
13361         case XPATH_OP_PLUS:
13362             bakd = ctxt->context->doc;
13363             bak = ctxt->context->node;
13364             pp = ctxt->context->proximityPosition;
13365             cs = ctxt->context->contextSize;
13366             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13367             CHECK_ERROR0;
13368             if (op->ch2 != -1) {
13369                 ctxt->context->doc = bakd;
13370                 ctxt->context->node = bak;
13371                 ctxt->context->proximityPosition = pp;
13372                 ctxt->context->contextSize = cs;
13373                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13374             }
13375             CHECK_ERROR0;
13376             if (op->value == 0)
13377                 xmlXPathSubValues(ctxt);
13378             else if (op->value == 1)
13379                 xmlXPathAddValues(ctxt);
13380             else if (op->value == 2)
13381                 xmlXPathValueFlipSign(ctxt);
13382             else if (op->value == 3) {
13383                 CAST_TO_NUMBER;
13384                 CHECK_TYPE0(XPATH_NUMBER);
13385             }
13386             return (total);
13387         case XPATH_OP_MULT:
13388             bakd = ctxt->context->doc;
13389             bak = ctxt->context->node;
13390             pp = ctxt->context->proximityPosition;
13391             cs = ctxt->context->contextSize;
13392             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13393             CHECK_ERROR0;
13394             ctxt->context->doc = bakd;
13395             ctxt->context->node = bak;
13396             ctxt->context->proximityPosition = pp;
13397             ctxt->context->contextSize = cs;
13398             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13399             CHECK_ERROR0;
13400             if (op->value == 0)
13401                 xmlXPathMultValues(ctxt);
13402             else if (op->value == 1)
13403                 xmlXPathDivValues(ctxt);
13404             else if (op->value == 2)
13405                 xmlXPathModValues(ctxt);
13406             return (total);
13407         case XPATH_OP_UNION:
13408             bakd = ctxt->context->doc;
13409             bak = ctxt->context->node;
13410             pp = ctxt->context->proximityPosition;
13411             cs = ctxt->context->contextSize;
13412             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13413             CHECK_ERROR0;
13414             ctxt->context->doc = bakd;
13415             ctxt->context->node = bak;
13416             ctxt->context->proximityPosition = pp;
13417             ctxt->context->contextSize = cs;
13418             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13419             CHECK_ERROR0;
13420             CHECK_TYPE0(XPATH_NODESET);
13421             arg2 = valuePop(ctxt);
13422
13423             CHECK_TYPE0(XPATH_NODESET);
13424             arg1 = valuePop(ctxt);
13425
13426             if ((arg1->nodesetval == NULL) ||
13427                 ((arg2->nodesetval != NULL) &&
13428                  (arg2->nodesetval->nodeNr != 0)))
13429             {
13430                 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13431                                                         arg2->nodesetval);
13432             }
13433
13434             valuePush(ctxt, arg1);
13435             xmlXPathReleaseObject(ctxt->context, arg2);
13436             return (total);
13437         case XPATH_OP_ROOT:
13438             xmlXPathRoot(ctxt);
13439             return (total);
13440         case XPATH_OP_NODE:
13441             if (op->ch1 != -1)
13442                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13443             CHECK_ERROR0;
13444             if (op->ch2 != -1)
13445                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13446             CHECK_ERROR0;
13447             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13448                 ctxt->context->node));
13449             return (total);
13450         case XPATH_OP_RESET:
13451             if (op->ch1 != -1)
13452                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13453             CHECK_ERROR0;
13454             if (op->ch2 != -1)
13455                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13456             CHECK_ERROR0;
13457             ctxt->context->node = NULL;
13458             return (total);
13459         case XPATH_OP_COLLECT:{
13460                 if (op->ch1 == -1)
13461                     return (total);
13462
13463                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13464                 CHECK_ERROR0;
13465
13466                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13467                 return (total);
13468             }
13469         case XPATH_OP_VALUE:
13470             valuePush(ctxt,
13471                       xmlXPathCacheObjectCopy(ctxt->context,
13472                         (xmlXPathObjectPtr) op->value4));
13473             return (total);
13474         case XPATH_OP_VARIABLE:{
13475                 xmlXPathObjectPtr val;
13476
13477                 if (op->ch1 != -1)
13478                     total +=
13479                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13480                 if (op->value5 == NULL) {
13481                     val = xmlXPathVariableLookup(ctxt->context, op->value4);
13482                     if (val == NULL) {
13483                         ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13484                         return(0);
13485                     }
13486                     valuePush(ctxt, val);
13487                 } else {
13488                     const xmlChar *URI;
13489
13490                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13491                     if (URI == NULL) {
13492                         xmlGenericError(xmlGenericErrorContext,
13493             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13494                                     (char *) op->value4, (char *)op->value5);
13495                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13496                         return (total);
13497                     }
13498                     val = xmlXPathVariableLookupNS(ctxt->context,
13499                                                        op->value4, URI);
13500                     if (val == NULL) {
13501                         ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13502                         return(0);
13503                     }
13504                     valuePush(ctxt, val);
13505                 }
13506                 return (total);
13507             }
13508         case XPATH_OP_FUNCTION:{
13509                 xmlXPathFunction func;
13510                 const xmlChar *oldFunc, *oldFuncURI;
13511                 int i;
13512                 int frame;
13513
13514                 frame = xmlXPathSetFrame(ctxt);
13515                 if (op->ch1 != -1)
13516                     total +=
13517                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13518                 if (ctxt->valueNr < op->value) {
13519                     xmlGenericError(xmlGenericErrorContext,
13520                             "xmlXPathCompOpEval: parameter error\n");
13521                     ctxt->error = XPATH_INVALID_OPERAND;
13522                     xmlXPathPopFrame(ctxt, frame);
13523                     return (total);
13524                 }
13525                 for (i = 0; i < op->value; i++) {
13526                     if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13527                         xmlGenericError(xmlGenericErrorContext,
13528                                 "xmlXPathCompOpEval: parameter error\n");
13529                         ctxt->error = XPATH_INVALID_OPERAND;
13530                         xmlXPathPopFrame(ctxt, frame);
13531                         return (total);
13532                     }
13533                 }
13534                 if (op->cache != NULL)
13535                     XML_CAST_FPTR(func) = op->cache;
13536                 else {
13537                     const xmlChar *URI = NULL;
13538
13539                     if (op->value5 == NULL)
13540                         func =
13541                             xmlXPathFunctionLookup(ctxt->context,
13542                                                    op->value4);
13543                     else {
13544                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13545                         if (URI == NULL) {
13546                             xmlGenericError(xmlGenericErrorContext,
13547             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13548                                     (char *)op->value4, (char *)op->value5);
13549                             xmlXPathPopFrame(ctxt, frame);
13550                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13551                             return (total);
13552                         }
13553                         func = xmlXPathFunctionLookupNS(ctxt->context,
13554                                                         op->value4, URI);
13555                     }
13556                     if (func == NULL) {
13557                         xmlGenericError(xmlGenericErrorContext,
13558                                 "xmlXPathCompOpEval: function %s not found\n",
13559                                         (char *)op->value4);
13560                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13561                     }
13562                     op->cache = XML_CAST_FPTR(func);
13563                     op->cacheURI = (void *) URI;
13564                 }
13565                 oldFunc = ctxt->context->function;
13566                 oldFuncURI = ctxt->context->functionURI;
13567                 ctxt->context->function = op->value4;
13568                 ctxt->context->functionURI = op->cacheURI;
13569                 func(ctxt, op->value);
13570                 ctxt->context->function = oldFunc;
13571                 ctxt->context->functionURI = oldFuncURI;
13572                 xmlXPathPopFrame(ctxt, frame);
13573                 return (total);
13574             }
13575         case XPATH_OP_ARG:
13576             bakd = ctxt->context->doc;
13577             bak = ctxt->context->node;
13578             pp = ctxt->context->proximityPosition;
13579             cs = ctxt->context->contextSize;
13580             if (op->ch1 != -1)
13581                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13582             ctxt->context->contextSize = cs;
13583             ctxt->context->proximityPosition = pp;
13584             ctxt->context->node = bak;
13585             ctxt->context->doc = bakd;
13586             CHECK_ERROR0;
13587             if (op->ch2 != -1) {
13588                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13589                 ctxt->context->doc = bakd;
13590                 ctxt->context->node = bak;
13591                 CHECK_ERROR0;
13592             }
13593             return (total);
13594         case XPATH_OP_PREDICATE:
13595         case XPATH_OP_FILTER:{
13596                 xmlXPathObjectPtr res;
13597                 xmlXPathObjectPtr obj, tmp;
13598                 xmlNodeSetPtr newset = NULL;
13599                 xmlNodeSetPtr oldset;
13600                 xmlNodePtr oldnode;
13601                 xmlDocPtr oldDoc;
13602                 int i;
13603
13604                 /*
13605                  * Optimization for ()[1] selection i.e. the first elem
13606                  */
13607                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13608 #ifdef XP_OPTIMIZED_FILTER_FIRST
13609                     /*
13610                     * FILTER TODO: Can we assume that the inner processing
13611                     *  will result in an ordered list if we have an
13612                     *  XPATH_OP_FILTER?
13613                     *  What about an additional field or flag on
13614                     *  xmlXPathObject like @sorted ? This way we wouln'd need
13615                     *  to assume anything, so it would be more robust and
13616                     *  easier to optimize.
13617                     */
13618                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13619                      (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13620 #else
13621                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13622 #endif
13623                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13624                     xmlXPathObjectPtr val;
13625
13626                     val = comp->steps[op->ch2].value4;
13627                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13628                         (val->floatval == 1.0)) {
13629                         xmlNodePtr first = NULL;
13630
13631                         total +=
13632                             xmlXPathCompOpEvalFirst(ctxt,
13633                                                     &comp->steps[op->ch1],
13634                                                     &first);
13635                         CHECK_ERROR0;
13636                         /*
13637                          * The nodeset should be in document order,
13638                          * Keep only the first value
13639                          */
13640                         if ((ctxt->value != NULL) &&
13641                             (ctxt->value->type == XPATH_NODESET) &&
13642                             (ctxt->value->nodesetval != NULL) &&
13643                             (ctxt->value->nodesetval->nodeNr > 1))
13644                             ctxt->value->nodesetval->nodeNr = 1;
13645                         return (total);
13646                     }
13647                 }
13648                 /*
13649                  * Optimization for ()[last()] selection i.e. the last elem
13650                  */
13651                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13652                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13653                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13654                     int f = comp->steps[op->ch2].ch1;
13655
13656                     if ((f != -1) &&
13657                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13658                         (comp->steps[f].value5 == NULL) &&
13659                         (comp->steps[f].value == 0) &&
13660                         (comp->steps[f].value4 != NULL) &&
13661                         (xmlStrEqual
13662                          (comp->steps[f].value4, BAD_CAST "last"))) {
13663                         xmlNodePtr last = NULL;
13664
13665                         total +=
13666                             xmlXPathCompOpEvalLast(ctxt,
13667                                                    &comp->steps[op->ch1],
13668                                                    &last);
13669                         CHECK_ERROR0;
13670                         /*
13671                          * The nodeset should be in document order,
13672                          * Keep only the last value
13673                          */
13674                         if ((ctxt->value != NULL) &&
13675                             (ctxt->value->type == XPATH_NODESET) &&
13676                             (ctxt->value->nodesetval != NULL) &&
13677                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13678                             (ctxt->value->nodesetval->nodeNr > 1)) {
13679                             ctxt->value->nodesetval->nodeTab[0] =
13680                                 ctxt->value->nodesetval->nodeTab[ctxt->
13681                                                                  value->
13682                                                                  nodesetval->
13683                                                                  nodeNr -
13684                                                                  1];
13685                             ctxt->value->nodesetval->nodeNr = 1;
13686                         }
13687                         return (total);
13688                     }
13689                 }
13690                 /*
13691                 * Process inner predicates first.
13692                 * Example "index[parent::book][1]":
13693                 * ...
13694                 *   PREDICATE   <-- we are here "[1]"
13695                 *     PREDICATE <-- process "[parent::book]" first
13696                 *       SORT
13697                 *         COLLECT  'parent' 'name' 'node' book
13698                 *           NODE
13699                 *     ELEM Object is a number : 1
13700                 */
13701                 if (op->ch1 != -1)
13702                     total +=
13703                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13704                 CHECK_ERROR0;
13705                 if (op->ch2 == -1)
13706                     return (total);
13707                 if (ctxt->value == NULL)
13708                     return (total);
13709
13710                 oldnode = ctxt->context->node;
13711
13712 #ifdef LIBXML_XPTR_ENABLED
13713                 /*
13714                  * Hum are we filtering the result of an XPointer expression
13715                  */
13716                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13717                     xmlLocationSetPtr newlocset = NULL;
13718                     xmlLocationSetPtr oldlocset;
13719
13720                     /*
13721                      * Extract the old locset, and then evaluate the result of the
13722                      * expression for all the element in the locset. use it to grow
13723                      * up a new locset.
13724                      */
13725                     CHECK_TYPE0(XPATH_LOCATIONSET);
13726                     obj = valuePop(ctxt);
13727                     oldlocset = obj->user;
13728                     ctxt->context->node = NULL;
13729
13730                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13731                         ctxt->context->contextSize = 0;
13732                         ctxt->context->proximityPosition = 0;
13733                         if (op->ch2 != -1)
13734                             total +=
13735                                 xmlXPathCompOpEval(ctxt,
13736                                                    &comp->steps[op->ch2]);
13737                         res = valuePop(ctxt);
13738                         if (res != NULL) {
13739                             xmlXPathReleaseObject(ctxt->context, res);
13740                         }
13741                         valuePush(ctxt, obj);
13742                         CHECK_ERROR0;
13743                         return (total);
13744                     }
13745                     newlocset = xmlXPtrLocationSetCreate(NULL);
13746
13747                     for (i = 0; i < oldlocset->locNr; i++) {
13748                         /*
13749                          * Run the evaluation with a node list made of a
13750                          * single item in the nodelocset.
13751                          */
13752                         ctxt->context->node = oldlocset->locTab[i]->user;
13753                         ctxt->context->contextSize = oldlocset->locNr;
13754                         ctxt->context->proximityPosition = i + 1;
13755                         tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13756                             ctxt->context->node);
13757                         valuePush(ctxt, tmp);
13758
13759                         if (op->ch2 != -1)
13760                             total +=
13761                                 xmlXPathCompOpEval(ctxt,
13762                                                    &comp->steps[op->ch2]);
13763                         if (ctxt->error != XPATH_EXPRESSION_OK) {
13764                             xmlXPathFreeObject(obj);
13765                             return(0);
13766                         }
13767
13768                         /*
13769                          * The result of the evaluation need to be tested to
13770                          * decided whether the filter succeeded or not
13771                          */
13772                         res = valuePop(ctxt);
13773                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13774                             xmlXPtrLocationSetAdd(newlocset,
13775                                                   xmlXPathObjectCopy
13776                                                   (oldlocset->locTab[i]));
13777                         }
13778
13779                         /*
13780                          * Cleanup
13781                          */
13782                         if (res != NULL) {
13783                             xmlXPathReleaseObject(ctxt->context, res);
13784                         }
13785                         if (ctxt->value == tmp) {
13786                             res = valuePop(ctxt);
13787                             xmlXPathReleaseObject(ctxt->context, res);
13788                         }
13789
13790                         ctxt->context->node = NULL;
13791                     }
13792
13793                     /*
13794                      * The result is used as the new evaluation locset.
13795                      */
13796                     xmlXPathReleaseObject(ctxt->context, obj);
13797                     ctxt->context->node = NULL;
13798                     ctxt->context->contextSize = -1;
13799                     ctxt->context->proximityPosition = -1;
13800                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13801                     ctxt->context->node = oldnode;
13802                     return (total);
13803                 }
13804 #endif /* LIBXML_XPTR_ENABLED */
13805
13806                 /*
13807                  * Extract the old set, and then evaluate the result of the
13808                  * expression for all the element in the set. use it to grow
13809                  * up a new set.
13810                  */
13811                 CHECK_TYPE0(XPATH_NODESET);
13812                 obj = valuePop(ctxt);
13813                 oldset = obj->nodesetval;
13814
13815                 oldnode = ctxt->context->node;
13816                 oldDoc = ctxt->context->doc;
13817                 ctxt->context->node = NULL;
13818
13819                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13820                     ctxt->context->contextSize = 0;
13821                     ctxt->context->proximityPosition = 0;
13822 /*
13823                     if (op->ch2 != -1)
13824                         total +=
13825                             xmlXPathCompOpEval(ctxt,
13826                                                &comp->steps[op->ch2]);
13827                     CHECK_ERROR0;
13828                     res = valuePop(ctxt);
13829                     if (res != NULL)
13830                         xmlXPathFreeObject(res);
13831 */
13832                     valuePush(ctxt, obj);
13833                     ctxt->context->node = oldnode;
13834                     CHECK_ERROR0;
13835                 } else {
13836                     tmp = NULL;
13837                     /*
13838                      * Initialize the new set.
13839                      * Also set the xpath document in case things like
13840                      * key() evaluation are attempted on the predicate
13841                      */
13842                     newset = xmlXPathNodeSetCreate(NULL);
13843                     /*
13844                     * SPEC XPath 1.0:
13845                     *  "For each node in the node-set to be filtered, the
13846                     *  PredicateExpr is evaluated with that node as the
13847                     *  context node, with the number of nodes in the
13848                     *  node-set as the context size, and with the proximity
13849                     *  position of the node in the node-set with respect to
13850                     *  the axis as the context position;"
13851                     * @oldset is the node-set" to be filtered.
13852                     *
13853                     * SPEC XPath 1.0:
13854                     *  "only predicates change the context position and
13855                     *  context size (see [2.4 Predicates])."
13856                     * Example:
13857                     *   node-set  context pos
13858                     *    nA         1
13859                     *    nB         2
13860                     *    nC         3
13861                     *   After applying predicate [position() > 1] :
13862                     *   node-set  context pos
13863                     *    nB         1
13864                     *    nC         2
13865                     *
13866                     * removed the first node in the node-set, then
13867                     * the context position of the
13868                     */
13869                     for (i = 0; i < oldset->nodeNr; i++) {
13870                         /*
13871                          * Run the evaluation with a node list made of
13872                          * a single item in the nodeset.
13873                          */
13874                         ctxt->context->node = oldset->nodeTab[i];
13875                         if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13876                             (oldset->nodeTab[i]->doc != NULL))
13877                             ctxt->context->doc = oldset->nodeTab[i]->doc;
13878                         if (tmp == NULL) {
13879                             tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13880                                 ctxt->context->node);
13881                         } else {
13882                             if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13883                                                ctxt->context->node) < 0) {
13884                                 ctxt->error = XPATH_MEMORY_ERROR;
13885                             }
13886                         }
13887                         valuePush(ctxt, tmp);
13888                         ctxt->context->contextSize = oldset->nodeNr;
13889                         ctxt->context->proximityPosition = i + 1;
13890                         /*
13891                         * Evaluate the predicate against the context node.
13892                         * Can/should we optimize position() predicates
13893                         * here (e.g. "[1]")?
13894                         */
13895                         if (op->ch2 != -1)
13896                             total +=
13897                                 xmlXPathCompOpEval(ctxt,
13898                                                    &comp->steps[op->ch2]);
13899                         if (ctxt->error != XPATH_EXPRESSION_OK) {
13900                             xmlXPathFreeNodeSet(newset);
13901                             xmlXPathFreeObject(obj);
13902                             return(0);
13903                         }
13904
13905                         /*
13906                          * The result of the evaluation needs to be tested to
13907                          * decide whether the filter succeeded or not
13908                          */
13909                         /*
13910                         * OPTIMIZE TODO: Can we use
13911                         * xmlXPathNodeSetAdd*Unique()* instead?
13912                         */
13913                         res = valuePop(ctxt);
13914                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13915                             if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13916                                 < 0)
13917                                 ctxt->error = XPATH_MEMORY_ERROR;
13918                         }
13919
13920                         /*
13921                          * Cleanup
13922                          */
13923                         if (res != NULL) {
13924                             xmlXPathReleaseObject(ctxt->context, res);
13925                         }
13926                         if (ctxt->value == tmp) {
13927                             valuePop(ctxt);
13928                             xmlXPathNodeSetClear(tmp->nodesetval, 1);
13929                             /*
13930                             * Don't free the temporary nodeset
13931                             * in order to avoid massive recreation inside this
13932                             * loop.
13933                             */
13934                         } else
13935                             tmp = NULL;
13936                         ctxt->context->node = NULL;
13937                     }
13938                     if (tmp != NULL)
13939                         xmlXPathReleaseObject(ctxt->context, tmp);
13940                     /*
13941                      * The result is used as the new evaluation set.
13942                      */
13943                     xmlXPathReleaseObject(ctxt->context, obj);
13944                     ctxt->context->node = NULL;
13945                     ctxt->context->contextSize = -1;
13946                     ctxt->context->proximityPosition = -1;
13947                     /* may want to move this past the '}' later */
13948                     ctxt->context->doc = oldDoc;
13949                     valuePush(ctxt,
13950                         xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13951                 }
13952                 ctxt->context->node = oldnode;
13953                 return (total);
13954             }
13955         case XPATH_OP_SORT:
13956             if (op->ch1 != -1)
13957                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13958             CHECK_ERROR0;
13959             if ((ctxt->value != NULL) &&
13960                 (ctxt->value->type == XPATH_NODESET) &&
13961                 (ctxt->value->nodesetval != NULL) &&
13962                 (ctxt->value->nodesetval->nodeNr > 1))
13963             {
13964                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13965             }
13966             return (total);
13967 #ifdef LIBXML_XPTR_ENABLED
13968         case XPATH_OP_RANGETO:{
13969                 xmlXPathObjectPtr range;
13970                 xmlXPathObjectPtr res, obj;
13971                 xmlXPathObjectPtr tmp;
13972                 xmlLocationSetPtr newlocset = NULL;
13973                     xmlLocationSetPtr oldlocset;
13974                 xmlNodeSetPtr oldset;
13975                 int i, j;
13976
13977                 if (op->ch1 != -1)
13978                     total +=
13979                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13980                 if (op->ch2 == -1)
13981                     return (total);
13982
13983                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13984                     /*
13985                      * Extract the old locset, and then evaluate the result of the
13986                      * expression for all the element in the locset. use it to grow
13987                      * up a new locset.
13988                      */
13989                     CHECK_TYPE0(XPATH_LOCATIONSET);
13990                     obj = valuePop(ctxt);
13991                     oldlocset = obj->user;
13992
13993                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13994                         ctxt->context->node = NULL;
13995                         ctxt->context->contextSize = 0;
13996                         ctxt->context->proximityPosition = 0;
13997                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13998                         res = valuePop(ctxt);
13999                         if (res != NULL) {
14000                             xmlXPathReleaseObject(ctxt->context, res);
14001                         }
14002                         valuePush(ctxt, obj);
14003                         CHECK_ERROR0;
14004                         return (total);
14005                     }
14006                     newlocset = xmlXPtrLocationSetCreate(NULL);
14007
14008                     for (i = 0; i < oldlocset->locNr; i++) {
14009                         /*
14010                          * Run the evaluation with a node list made of a
14011                          * single item in the nodelocset.
14012                          */
14013                         ctxt->context->node = oldlocset->locTab[i]->user;
14014                         ctxt->context->contextSize = oldlocset->locNr;
14015                         ctxt->context->proximityPosition = i + 1;
14016                         tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14017                             ctxt->context->node);
14018                         valuePush(ctxt, tmp);
14019
14020                         if (op->ch2 != -1)
14021                             total +=
14022                                 xmlXPathCompOpEval(ctxt,
14023                                                    &comp->steps[op->ch2]);
14024                         if (ctxt->error != XPATH_EXPRESSION_OK) {
14025                             xmlXPathFreeObject(obj);
14026                             return(0);
14027                         }
14028
14029                         res = valuePop(ctxt);
14030                         if (res->type == XPATH_LOCATIONSET) {
14031                             xmlLocationSetPtr rloc =
14032                                 (xmlLocationSetPtr)res->user;
14033                             for (j=0; j<rloc->locNr; j++) {
14034                                 range = xmlXPtrNewRange(
14035                                   oldlocset->locTab[i]->user,
14036                                   oldlocset->locTab[i]->index,
14037                                   rloc->locTab[j]->user2,
14038                                   rloc->locTab[j]->index2);
14039                                 if (range != NULL) {
14040                                     xmlXPtrLocationSetAdd(newlocset, range);
14041                                 }
14042                             }
14043                         } else {
14044                             range = xmlXPtrNewRangeNodeObject(
14045                                 (xmlNodePtr)oldlocset->locTab[i]->user, res);
14046                             if (range != NULL) {
14047                                 xmlXPtrLocationSetAdd(newlocset,range);
14048                             }
14049                         }
14050
14051                         /*
14052                          * Cleanup
14053                          */
14054                         if (res != NULL) {
14055                             xmlXPathReleaseObject(ctxt->context, res);
14056                         }
14057                         if (ctxt->value == tmp) {
14058                             res = valuePop(ctxt);
14059                             xmlXPathReleaseObject(ctxt->context, res);
14060                         }
14061
14062                         ctxt->context->node = NULL;
14063                     }
14064                 } else {        /* Not a location set */
14065                     CHECK_TYPE0(XPATH_NODESET);
14066                     obj = valuePop(ctxt);
14067                     oldset = obj->nodesetval;
14068                     ctxt->context->node = NULL;
14069
14070                     newlocset = xmlXPtrLocationSetCreate(NULL);
14071
14072                     if (oldset != NULL) {
14073                         for (i = 0; i < oldset->nodeNr; i++) {
14074                             /*
14075                              * Run the evaluation with a node list made of a single item
14076                              * in the nodeset.
14077                              */
14078                             ctxt->context->node = oldset->nodeTab[i];
14079                             /*
14080                             * OPTIMIZE TODO: Avoid recreation for every iteration.
14081                             */
14082                             tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14083                                 ctxt->context->node);
14084                             valuePush(ctxt, tmp);
14085
14086                             if (op->ch2 != -1)
14087                                 total +=
14088                                     xmlXPathCompOpEval(ctxt,
14089                                                    &comp->steps[op->ch2]);
14090                             if (ctxt->error != XPATH_EXPRESSION_OK) {
14091                                 xmlXPathFreeObject(obj);
14092                                 return(0);
14093                             }
14094
14095                             res = valuePop(ctxt);
14096                             range =
14097                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14098                                                       res);
14099                             if (range != NULL) {
14100                                 xmlXPtrLocationSetAdd(newlocset, range);
14101                             }
14102
14103                             /*
14104                              * Cleanup
14105                              */
14106                             if (res != NULL) {
14107                                 xmlXPathReleaseObject(ctxt->context, res);
14108                             }
14109                             if (ctxt->value == tmp) {
14110                                 res = valuePop(ctxt);
14111                                 xmlXPathReleaseObject(ctxt->context, res);
14112                             }
14113
14114                             ctxt->context->node = NULL;
14115                         }
14116                     }
14117                 }
14118
14119                 /*
14120                  * The result is used as the new evaluation set.
14121                  */
14122                 xmlXPathReleaseObject(ctxt->context, obj);
14123                 ctxt->context->node = NULL;
14124                 ctxt->context->contextSize = -1;
14125                 ctxt->context->proximityPosition = -1;
14126                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14127                 return (total);
14128             }
14129 #endif /* LIBXML_XPTR_ENABLED */
14130     }
14131     xmlGenericError(xmlGenericErrorContext,
14132                     "XPath: unknown precompiled operation %d\n", op->op);
14133     ctxt->error = XPATH_INVALID_OPERAND;
14134     return (total);
14135 }
14136
14137 /**
14138  * xmlXPathCompOpEvalToBoolean:
14139  * @ctxt:  the XPath parser context
14140  *
14141  * Evaluates if the expression evaluates to true.
14142  *
14143  * Returns 1 if true, 0 if false and -1 on API or internal errors.
14144  */
14145 static int
14146 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14147                             xmlXPathStepOpPtr op,
14148                             int isPredicate)
14149 {
14150     xmlXPathObjectPtr resObj = NULL;
14151
14152 start:
14153     /* comp = ctxt->comp; */
14154     switch (op->op) {
14155         case XPATH_OP_END:
14156             return (0);
14157         case XPATH_OP_VALUE:
14158             resObj = (xmlXPathObjectPtr) op->value4;
14159             if (isPredicate)
14160                 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14161             return(xmlXPathCastToBoolean(resObj));
14162         case XPATH_OP_SORT:
14163             /*
14164             * We don't need sorting for boolean results. Skip this one.
14165             */
14166             if (op->ch1 != -1) {
14167                 op = &ctxt->comp->steps[op->ch1];
14168                 goto start;
14169             }
14170             return(0);
14171         case XPATH_OP_COLLECT:
14172             if (op->ch1 == -1)
14173                 return(0);
14174
14175             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14176             if (ctxt->error != XPATH_EXPRESSION_OK)
14177                 return(-1);
14178
14179             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14180             if (ctxt->error != XPATH_EXPRESSION_OK)
14181                 return(-1);
14182
14183             resObj = valuePop(ctxt);
14184             if (resObj == NULL)
14185                 return(-1);
14186             break;
14187         default:
14188             /*
14189             * Fallback to call xmlXPathCompOpEval().
14190             */
14191             xmlXPathCompOpEval(ctxt, op);
14192             if (ctxt->error != XPATH_EXPRESSION_OK)
14193                 return(-1);
14194
14195             resObj = valuePop(ctxt);
14196             if (resObj == NULL)
14197                 return(-1);
14198             break;
14199     }
14200
14201     if (resObj) {
14202         int res;
14203
14204         if (resObj->type == XPATH_BOOLEAN) {
14205             res = resObj->boolval;
14206         } else if (isPredicate) {
14207             /*
14208             * For predicates a result of type "number" is handled
14209             * differently:
14210             * SPEC XPath 1.0:
14211             * "If the result is a number, the result will be converted
14212             *  to true if the number is equal to the context position
14213             *  and will be converted to false otherwise;"
14214             */
14215             res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14216         } else {
14217             res = xmlXPathCastToBoolean(resObj);
14218         }
14219         xmlXPathReleaseObject(ctxt->context, resObj);
14220         return(res);
14221     }
14222
14223     return(0);
14224 }
14225
14226 #ifdef XPATH_STREAMING
14227 /**
14228  * xmlXPathRunStreamEval:
14229  * @ctxt:  the XPath parser context with the compiled expression
14230  *
14231  * Evaluate the Precompiled Streamable XPath expression in the given context.
14232  */
14233 static int
14234 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14235                       xmlXPathObjectPtr *resultSeq, int toBool)
14236 {
14237     int max_depth, min_depth;
14238     int from_root;
14239     int ret, depth;
14240     int eval_all_nodes;
14241     xmlNodePtr cur = NULL, limit = NULL;
14242     xmlStreamCtxtPtr patstream = NULL;
14243
14244     int nb_nodes = 0;
14245
14246     if ((ctxt == NULL) || (comp == NULL))
14247         return(-1);
14248     max_depth = xmlPatternMaxDepth(comp);
14249     if (max_depth == -1)
14250         return(-1);
14251     if (max_depth == -2)
14252         max_depth = 10000;
14253     min_depth = xmlPatternMinDepth(comp);
14254     if (min_depth == -1)
14255         return(-1);
14256     from_root = xmlPatternFromRoot(comp);
14257     if (from_root < 0)
14258         return(-1);
14259 #if 0
14260     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14261 #endif
14262
14263     if (! toBool) {
14264         if (resultSeq == NULL)
14265             return(-1);
14266         *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14267         if (*resultSeq == NULL)
14268             return(-1);
14269     }
14270
14271     /*
14272      * handle the special cases of "/" amd "." being matched
14273      */
14274     if (min_depth == 0) {
14275         if (from_root) {
14276             /* Select "/" */
14277             if (toBool)
14278                 return(1);
14279             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14280                                      (xmlNodePtr) ctxt->doc);
14281         } else {
14282             /* Select "self::node()" */
14283             if (toBool)
14284                 return(1);
14285             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14286         }
14287     }
14288     if (max_depth == 0) {
14289         return(0);
14290     }
14291
14292     if (from_root) {
14293         cur = (xmlNodePtr)ctxt->doc;
14294     } else if (ctxt->node != NULL) {
14295         switch (ctxt->node->type) {
14296             case XML_ELEMENT_NODE:
14297             case XML_DOCUMENT_NODE:
14298             case XML_DOCUMENT_FRAG_NODE:
14299             case XML_HTML_DOCUMENT_NODE:
14300 #ifdef LIBXML_DOCB_ENABLED
14301             case XML_DOCB_DOCUMENT_NODE:
14302 #endif
14303                 cur = ctxt->node;
14304                 break;
14305             case XML_ATTRIBUTE_NODE:
14306             case XML_TEXT_NODE:
14307             case XML_CDATA_SECTION_NODE:
14308             case XML_ENTITY_REF_NODE:
14309             case XML_ENTITY_NODE:
14310             case XML_PI_NODE:
14311             case XML_COMMENT_NODE:
14312             case XML_NOTATION_NODE:
14313             case XML_DTD_NODE:
14314             case XML_DOCUMENT_TYPE_NODE:
14315             case XML_ELEMENT_DECL:
14316             case XML_ATTRIBUTE_DECL:
14317             case XML_ENTITY_DECL:
14318             case XML_NAMESPACE_DECL:
14319             case XML_XINCLUDE_START:
14320             case XML_XINCLUDE_END:
14321                 break;
14322         }
14323         limit = cur;
14324     }
14325     if (cur == NULL) {
14326         return(0);
14327     }
14328
14329     patstream = xmlPatternGetStreamCtxt(comp);
14330     if (patstream == NULL) {
14331         /*
14332         * QUESTION TODO: Is this an error?
14333         */
14334         return(0);
14335     }
14336
14337     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14338
14339     if (from_root) {
14340         ret = xmlStreamPush(patstream, NULL, NULL);
14341         if (ret < 0) {
14342         } else if (ret == 1) {
14343             if (toBool)
14344                 goto return_1;
14345             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14346         }
14347     }
14348     depth = 0;
14349     goto scan_children;
14350 next_node:
14351     do {
14352         nb_nodes++;
14353
14354         switch (cur->type) {
14355             case XML_ELEMENT_NODE:
14356             case XML_TEXT_NODE:
14357             case XML_CDATA_SECTION_NODE:
14358             case XML_COMMENT_NODE:
14359             case XML_PI_NODE:
14360                 if (cur->type == XML_ELEMENT_NODE) {
14361                     ret = xmlStreamPush(patstream, cur->name,
14362                                 (cur->ns ? cur->ns->href : NULL));
14363                 } else if (eval_all_nodes)
14364                     ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14365                 else
14366                     break;
14367
14368                 if (ret < 0) {
14369                     /* NOP. */
14370                 } else if (ret == 1) {
14371                     if (toBool)
14372                         goto return_1;
14373                     if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14374                         < 0) {
14375                         ctxt->lastError.domain = XML_FROM_XPATH;
14376                         ctxt->lastError.code = XML_ERR_NO_MEMORY;
14377                     }
14378                 }
14379                 if ((cur->children == NULL) || (depth >= max_depth)) {
14380                     ret = xmlStreamPop(patstream);
14381                     while (cur->next != NULL) {
14382                         cur = cur->next;
14383                         if ((cur->type != XML_ENTITY_DECL) &&
14384                             (cur->type != XML_DTD_NODE))
14385                             goto next_node;
14386                     }
14387                 }
14388             default:
14389                 break;
14390         }
14391
14392 scan_children:
14393         if (cur->type == XML_NAMESPACE_DECL) break;
14394         if ((cur->children != NULL) && (depth < max_depth)) {
14395             /*
14396              * Do not descend on entities declarations
14397              */
14398             if (cur->children->type != XML_ENTITY_DECL) {
14399                 cur = cur->children;
14400                 depth++;
14401                 /*
14402                  * Skip DTDs
14403                  */
14404                 if (cur->type != XML_DTD_NODE)
14405                     continue;
14406             }
14407         }
14408
14409         if (cur == limit)
14410             break;
14411
14412         while (cur->next != NULL) {
14413             cur = cur->next;
14414             if ((cur->type != XML_ENTITY_DECL) &&
14415                 (cur->type != XML_DTD_NODE))
14416                 goto next_node;
14417         }
14418
14419         do {
14420             cur = cur->parent;
14421             depth--;
14422             if ((cur == NULL) || (cur == limit))
14423                 goto done;
14424             if (cur->type == XML_ELEMENT_NODE) {
14425                 ret = xmlStreamPop(patstream);
14426             } else if ((eval_all_nodes) &&
14427                 ((cur->type == XML_TEXT_NODE) ||
14428                  (cur->type == XML_CDATA_SECTION_NODE) ||
14429                  (cur->type == XML_COMMENT_NODE) ||
14430                  (cur->type == XML_PI_NODE)))
14431             {
14432                 ret = xmlStreamPop(patstream);
14433             }
14434             if (cur->next != NULL) {
14435                 cur = cur->next;
14436                 break;
14437             }
14438         } while (cur != NULL);
14439
14440     } while ((cur != NULL) && (depth >= 0));
14441
14442 done:
14443
14444 #if 0
14445     printf("stream eval: checked %d nodes selected %d\n",
14446            nb_nodes, retObj->nodesetval->nodeNr);
14447 #endif
14448
14449     if (patstream)
14450         xmlFreeStreamCtxt(patstream);
14451     return(0);
14452
14453 return_1:
14454     if (patstream)
14455         xmlFreeStreamCtxt(patstream);
14456     return(1);
14457 }
14458 #endif /* XPATH_STREAMING */
14459
14460 /**
14461  * xmlXPathRunEval:
14462  * @ctxt:  the XPath parser context with the compiled expression
14463  * @toBool:  evaluate to a boolean result
14464  *
14465  * Evaluate the Precompiled XPath expression in the given context.
14466  */
14467 static int
14468 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14469 {
14470     xmlXPathCompExprPtr comp;
14471
14472     if ((ctxt == NULL) || (ctxt->comp == NULL))
14473         return(-1);
14474
14475     if (ctxt->valueTab == NULL) {
14476         /* Allocate the value stack */
14477         ctxt->valueTab = (xmlXPathObjectPtr *)
14478                          xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14479         if (ctxt->valueTab == NULL) {
14480             xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14481             xmlFree(ctxt);
14482         }
14483         ctxt->valueNr = 0;
14484         ctxt->valueMax = 10;
14485         ctxt->value = NULL;
14486         ctxt->valueFrame = 0;
14487     }
14488 #ifdef XPATH_STREAMING
14489     if (ctxt->comp->stream) {
14490         int res;
14491
14492         if (toBool) {
14493             /*
14494             * Evaluation to boolean result.
14495             */
14496             res = xmlXPathRunStreamEval(ctxt->context,
14497                 ctxt->comp->stream, NULL, 1);
14498             if (res != -1)
14499                 return(res);
14500         } else {
14501             xmlXPathObjectPtr resObj = NULL;
14502
14503             /*
14504             * Evaluation to a sequence.
14505             */
14506             res = xmlXPathRunStreamEval(ctxt->context,
14507                 ctxt->comp->stream, &resObj, 0);
14508
14509             if ((res != -1) && (resObj != NULL)) {
14510                 valuePush(ctxt, resObj);
14511                 return(0);
14512             }
14513             if (resObj != NULL)
14514                 xmlXPathReleaseObject(ctxt->context, resObj);
14515         }
14516         /*
14517         * QUESTION TODO: This falls back to normal XPath evaluation
14518         * if res == -1. Is this intended?
14519         */
14520     }
14521 #endif
14522     comp = ctxt->comp;
14523     if (comp->last < 0) {
14524         xmlGenericError(xmlGenericErrorContext,
14525             "xmlXPathRunEval: last is less than zero\n");
14526         return(-1);
14527     }
14528     if (toBool)
14529         return(xmlXPathCompOpEvalToBoolean(ctxt,
14530             &comp->steps[comp->last], 0));
14531     else
14532         xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14533
14534     return(0);
14535 }
14536
14537 /************************************************************************
14538  *                                                                      *
14539  *                      Public interfaces                               *
14540  *                                                                      *
14541  ************************************************************************/
14542
14543 /**
14544  * xmlXPathEvalPredicate:
14545  * @ctxt:  the XPath context
14546  * @res:  the Predicate Expression evaluation result
14547  *
14548  * Evaluate a predicate result for the current node.
14549  * A PredicateExpr is evaluated by evaluating the Expr and converting
14550  * the result to a boolean. If the result is a number, the result will
14551  * be converted to true if the number is equal to the position of the
14552  * context node in the context node list (as returned by the position
14553  * function) and will be converted to false otherwise; if the result
14554  * is not a number, then the result will be converted as if by a call
14555  * to the boolean function.
14556  *
14557  * Returns 1 if predicate is true, 0 otherwise
14558  */
14559 int
14560 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14561     if ((ctxt == NULL) || (res == NULL)) return(0);
14562     switch (res->type) {
14563         case XPATH_BOOLEAN:
14564             return(res->boolval);
14565         case XPATH_NUMBER:
14566             return(res->floatval == ctxt->proximityPosition);
14567         case XPATH_NODESET:
14568         case XPATH_XSLT_TREE:
14569             if (res->nodesetval == NULL)
14570                 return(0);
14571             return(res->nodesetval->nodeNr != 0);
14572         case XPATH_STRING:
14573             return((res->stringval != NULL) &&
14574                    (xmlStrlen(res->stringval) != 0));
14575         default:
14576             STRANGE
14577     }
14578     return(0);
14579 }
14580
14581 /**
14582  * xmlXPathEvaluatePredicateResult:
14583  * @ctxt:  the XPath Parser context
14584  * @res:  the Predicate Expression evaluation result
14585  *
14586  * Evaluate a predicate result for the current node.
14587  * A PredicateExpr is evaluated by evaluating the Expr and converting
14588  * the result to a boolean. If the result is a number, the result will
14589  * be converted to true if the number is equal to the position of the
14590  * context node in the context node list (as returned by the position
14591  * function) and will be converted to false otherwise; if the result
14592  * is not a number, then the result will be converted as if by a call
14593  * to the boolean function.
14594  *
14595  * Returns 1 if predicate is true, 0 otherwise
14596  */
14597 int
14598 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14599                                 xmlXPathObjectPtr res) {
14600     if ((ctxt == NULL) || (res == NULL)) return(0);
14601     switch (res->type) {
14602         case XPATH_BOOLEAN:
14603             return(res->boolval);
14604         case XPATH_NUMBER:
14605 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14606             return((res->floatval == ctxt->context->proximityPosition) &&
14607                    (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14608 #else
14609             return(res->floatval == ctxt->context->proximityPosition);
14610 #endif
14611         case XPATH_NODESET:
14612         case XPATH_XSLT_TREE:
14613             if (res->nodesetval == NULL)
14614                 return(0);
14615             return(res->nodesetval->nodeNr != 0);
14616         case XPATH_STRING:
14617             return((res->stringval != NULL) && (res->stringval[0] != 0));
14618 #ifdef LIBXML_XPTR_ENABLED
14619         case XPATH_LOCATIONSET:{
14620             xmlLocationSetPtr ptr = res->user;
14621             if (ptr == NULL)
14622                 return(0);
14623             return (ptr->locNr != 0);
14624             }
14625 #endif
14626         default:
14627             STRANGE
14628     }
14629     return(0);
14630 }
14631
14632 #ifdef XPATH_STREAMING
14633 /**
14634  * xmlXPathTryStreamCompile:
14635  * @ctxt: an XPath context
14636  * @str:  the XPath expression
14637  *
14638  * Try to compile the XPath expression as a streamable subset.
14639  *
14640  * Returns the compiled expression or NULL if failed to compile.
14641  */
14642 static xmlXPathCompExprPtr
14643 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14644     /*
14645      * Optimization: use streaming patterns when the XPath expression can
14646      * be compiled to a stream lookup
14647      */
14648     xmlPatternPtr stream;
14649     xmlXPathCompExprPtr comp;
14650     xmlDictPtr dict = NULL;
14651     const xmlChar **namespaces = NULL;
14652     xmlNsPtr ns;
14653     int i, j;
14654
14655     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14656         (!xmlStrchr(str, '@'))) {
14657         const xmlChar *tmp;
14658
14659         /*
14660          * We don't try to handle expressions using the verbose axis
14661          * specifiers ("::"), just the simplied form at this point.
14662          * Additionally, if there is no list of namespaces available and
14663          *  there's a ":" in the expression, indicating a prefixed QName,
14664          *  then we won't try to compile either. xmlPatterncompile() needs
14665          *  to have a list of namespaces at compilation time in order to
14666          *  compile prefixed name tests.
14667          */
14668         tmp = xmlStrchr(str, ':');
14669         if ((tmp != NULL) &&
14670             ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14671             return(NULL);
14672
14673         if (ctxt != NULL) {
14674             dict = ctxt->dict;
14675             if (ctxt->nsNr > 0) {
14676                 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14677                 if (namespaces == NULL) {
14678                     xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14679                     return(NULL);
14680                 }
14681                 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14682                     ns = ctxt->namespaces[j];
14683                     namespaces[i++] = ns->href;
14684                     namespaces[i++] = ns->prefix;
14685                 }
14686                 namespaces[i++] = NULL;
14687                 namespaces[i] = NULL;
14688             }
14689         }
14690
14691         stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14692                         &namespaces[0]);
14693         if (namespaces != NULL) {
14694             xmlFree((xmlChar **)namespaces);
14695         }
14696         if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14697             comp = xmlXPathNewCompExpr();
14698             if (comp == NULL) {
14699                 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14700                 return(NULL);
14701             }
14702             comp->stream = stream;
14703             comp->dict = dict;
14704             if (comp->dict)
14705                 xmlDictReference(comp->dict);
14706             return(comp);
14707         }
14708         xmlFreePattern(stream);
14709     }
14710     return(NULL);
14711 }
14712 #endif /* XPATH_STREAMING */
14713
14714 static void
14715 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14716 {
14717     /*
14718     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14719     * internal representation.
14720     */
14721
14722     if ((op->ch1 != -1) &&
14723         (op->op == XPATH_OP_COLLECT /* 11 */))
14724     {
14725         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14726
14727         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14728             ((xmlXPathAxisVal) prevop->value ==
14729                 AXIS_DESCENDANT_OR_SELF) &&
14730             (prevop->ch2 == -1) &&
14731             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14732             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14733         {
14734             /*
14735             * This is a "descendant-or-self::node()" without predicates.
14736             * Try to eliminate it.
14737             */
14738
14739             switch ((xmlXPathAxisVal) op->value) {
14740                 case AXIS_CHILD:
14741                 case AXIS_DESCENDANT:
14742                     /*
14743                     * Convert "descendant-or-self::node()/child::" or
14744                     * "descendant-or-self::node()/descendant::" to
14745                     * "descendant::"
14746                     */
14747                     op->ch1   = prevop->ch1;
14748                     op->value = AXIS_DESCENDANT;
14749                     break;
14750                 case AXIS_SELF:
14751                 case AXIS_DESCENDANT_OR_SELF:
14752                     /*
14753                     * Convert "descendant-or-self::node()/self::" or
14754                     * "descendant-or-self::node()/descendant-or-self::" to
14755                     * to "descendant-or-self::"
14756                     */
14757                     op->ch1   = prevop->ch1;
14758                     op->value = AXIS_DESCENDANT_OR_SELF;
14759                     break;
14760                 default:
14761                     break;
14762             }
14763         }
14764     }
14765
14766     /* Recurse */
14767     if (op->ch1 != -1)
14768         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14769     if (op->ch2 != -1)
14770         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14771 }
14772
14773 /**
14774  * xmlXPathCtxtCompile:
14775  * @ctxt: an XPath context
14776  * @str:  the XPath expression
14777  *
14778  * Compile an XPath expression
14779  *
14780  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14781  *         the caller has to free the object.
14782  */
14783 xmlXPathCompExprPtr
14784 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14785     xmlXPathParserContextPtr pctxt;
14786     xmlXPathCompExprPtr comp;
14787
14788 #ifdef XPATH_STREAMING
14789     comp = xmlXPathTryStreamCompile(ctxt, str);
14790     if (comp != NULL)
14791         return(comp);
14792 #endif
14793
14794     xmlXPathInit();
14795
14796     pctxt = xmlXPathNewParserContext(str, ctxt);
14797     if (pctxt == NULL)
14798         return NULL;
14799     xmlXPathCompileExpr(pctxt, 1);
14800
14801     if( pctxt->error != XPATH_EXPRESSION_OK )
14802     {
14803         xmlXPathFreeParserContext(pctxt);
14804         return(NULL);
14805     }
14806
14807     if (*pctxt->cur != 0) {
14808         /*
14809          * aleksey: in some cases this line prints *second* error message
14810          * (see bug #78858) and probably this should be fixed.
14811          * However, we are not sure that all error messages are printed
14812          * out in other places. It's not critical so we leave it as-is for now
14813          */
14814         xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14815         comp = NULL;
14816     } else {
14817         comp = pctxt->comp;
14818         pctxt->comp = NULL;
14819     }
14820     xmlXPathFreeParserContext(pctxt);
14821
14822     if (comp != NULL) {
14823         comp->expr = xmlStrdup(str);
14824 #ifdef DEBUG_EVAL_COUNTS
14825         comp->string = xmlStrdup(str);
14826         comp->nb = 0;
14827 #endif
14828         if ((comp->nbStep > 1) && (comp->last >= 0)) {
14829             xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14830         }
14831     }
14832     return(comp);
14833 }
14834
14835 /**
14836  * xmlXPathCompile:
14837  * @str:  the XPath expression
14838  *
14839  * Compile an XPath expression
14840  *
14841  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14842  *         the caller has to free the object.
14843  */
14844 xmlXPathCompExprPtr
14845 xmlXPathCompile(const xmlChar *str) {
14846     return(xmlXPathCtxtCompile(NULL, str));
14847 }
14848
14849 /**
14850  * xmlXPathCompiledEvalInternal:
14851  * @comp:  the compiled XPath expression
14852  * @ctxt:  the XPath context
14853  * @resObj: the resulting XPath object or NULL
14854  * @toBool: 1 if only a boolean result is requested
14855  *
14856  * Evaluate the Precompiled XPath expression in the given context.
14857  * The caller has to free @resObj.
14858  *
14859  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14860  *         the caller has to free the object.
14861  */
14862 static int
14863 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14864                              xmlXPathContextPtr ctxt,
14865                              xmlXPathObjectPtr *resObj,
14866                              int toBool)
14867 {
14868     xmlXPathParserContextPtr pctxt;
14869 #ifndef LIBXML_THREAD_ENABLED
14870     static int reentance = 0;
14871 #endif
14872     int res;
14873
14874     CHECK_CTXT_NEG(ctxt)
14875
14876     if (comp == NULL)
14877         return(-1);
14878     xmlXPathInit();
14879
14880 #ifndef LIBXML_THREAD_ENABLED
14881     reentance++;
14882     if (reentance > 1)
14883         xmlXPathDisableOptimizer = 1;
14884 #endif
14885
14886 #ifdef DEBUG_EVAL_COUNTS
14887     comp->nb++;
14888     if ((comp->string != NULL) && (comp->nb > 100)) {
14889         fprintf(stderr, "100 x %s\n", comp->string);
14890         comp->nb = 0;
14891     }
14892 #endif
14893     pctxt = xmlXPathCompParserContext(comp, ctxt);
14894     res = xmlXPathRunEval(pctxt, toBool);
14895
14896     if (resObj) {
14897         if (pctxt->value == NULL) {
14898             xmlGenericError(xmlGenericErrorContext,
14899                 "xmlXPathCompiledEval: evaluation failed\n");
14900             *resObj = NULL;
14901         } else {
14902             *resObj = valuePop(pctxt);
14903         }
14904     }
14905
14906     /*
14907     * Pop all remaining objects from the stack.
14908     */
14909     if (pctxt->valueNr > 0) {
14910         xmlXPathObjectPtr tmp;
14911         int stack = 0;
14912
14913         do {
14914             tmp = valuePop(pctxt);
14915             if (tmp != NULL) {
14916                 stack++;
14917                 xmlXPathReleaseObject(ctxt, tmp);
14918             }
14919         } while (tmp != NULL);
14920         if ((stack != 0) &&
14921             ((toBool) || ((resObj) && (*resObj))))
14922         {
14923             xmlGenericError(xmlGenericErrorContext,
14924                 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14925                 stack);
14926         }
14927     }
14928
14929     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14930         xmlXPathFreeObject(*resObj);
14931         *resObj = NULL;
14932     }
14933     pctxt->comp = NULL;
14934     xmlXPathFreeParserContext(pctxt);
14935 #ifndef LIBXML_THREAD_ENABLED
14936     reentance--;
14937 #endif
14938
14939     return(res);
14940 }
14941
14942 /**
14943  * xmlXPathCompiledEval:
14944  * @comp:  the compiled XPath expression
14945  * @ctx:  the XPath context
14946  *
14947  * Evaluate the Precompiled XPath expression in the given context.
14948  *
14949  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14950  *         the caller has to free the object.
14951  */
14952 xmlXPathObjectPtr
14953 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14954 {
14955     xmlXPathObjectPtr res = NULL;
14956
14957     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14958     return(res);
14959 }
14960
14961 /**
14962  * xmlXPathCompiledEvalToBoolean:
14963  * @comp:  the compiled XPath expression
14964  * @ctxt:  the XPath context
14965  *
14966  * Applies the XPath boolean() function on the result of the given
14967  * compiled expression.
14968  *
14969  * Returns 1 if the expression evaluated to true, 0 if to false and
14970  *         -1 in API and internal errors.
14971  */
14972 int
14973 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14974                               xmlXPathContextPtr ctxt)
14975 {
14976     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14977 }
14978
14979 /**
14980  * xmlXPathEvalExpr:
14981  * @ctxt:  the XPath Parser context
14982  *
14983  * Parse and evaluate an XPath expression in the given context,
14984  * then push the result on the context stack
14985  */
14986 void
14987 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14988 #ifdef XPATH_STREAMING
14989     xmlXPathCompExprPtr comp;
14990 #endif
14991
14992     if (ctxt == NULL) return;
14993
14994 #ifdef XPATH_STREAMING
14995     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14996     if (comp != NULL) {
14997         if (ctxt->comp != NULL)
14998             xmlXPathFreeCompExpr(ctxt->comp);
14999         ctxt->comp = comp;
15000         if (ctxt->cur != NULL)
15001             while (*ctxt->cur != 0) ctxt->cur++;
15002     } else
15003 #endif
15004     {
15005         xmlXPathCompileExpr(ctxt, 1);
15006         if ((ctxt->error == XPATH_EXPRESSION_OK) &&
15007             (ctxt->comp != NULL) &&
15008             (ctxt->comp->nbStep > 1) &&
15009             (ctxt->comp->last >= 0))
15010         {
15011             xmlXPathOptimizeExpression(ctxt->comp,
15012                 &ctxt->comp->steps[ctxt->comp->last]);
15013         }
15014     }
15015     CHECK_ERROR;
15016     xmlXPathRunEval(ctxt, 0);
15017 }
15018
15019 /**
15020  * xmlXPathEval:
15021  * @str:  the XPath expression
15022  * @ctx:  the XPath context
15023  *
15024  * Evaluate the XPath Location Path in the given context.
15025  *
15026  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15027  *         the caller has to free the object.
15028  */
15029 xmlXPathObjectPtr
15030 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15031     xmlXPathParserContextPtr ctxt;
15032     xmlXPathObjectPtr res, tmp, init = NULL;
15033     int stack = 0;
15034
15035     CHECK_CTXT(ctx)
15036
15037     xmlXPathInit();
15038
15039     ctxt = xmlXPathNewParserContext(str, ctx);
15040     if (ctxt == NULL)
15041         return NULL;
15042     xmlXPathEvalExpr(ctxt);
15043
15044     if (ctxt->value == NULL) {
15045         xmlGenericError(xmlGenericErrorContext,
15046                 "xmlXPathEval: evaluation failed\n");
15047         res = NULL;
15048     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
15049 #ifdef XPATH_STREAMING
15050             && (ctxt->comp->stream == NULL)
15051 #endif
15052               ) {
15053         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15054         res = NULL;
15055     } else {
15056         res = valuePop(ctxt);
15057     }
15058
15059     do {
15060         tmp = valuePop(ctxt);
15061         if (tmp != NULL) {
15062             if (tmp != init)
15063                 stack++;
15064             xmlXPathReleaseObject(ctx, tmp);
15065         }
15066     } while (tmp != NULL);
15067     if ((stack != 0) && (res != NULL)) {
15068         xmlGenericError(xmlGenericErrorContext,
15069                 "xmlXPathEval: %d object left on the stack\n",
15070                 stack);
15071     }
15072     if (ctxt->error != XPATH_EXPRESSION_OK) {
15073         xmlXPathFreeObject(res);
15074         res = NULL;
15075     }
15076
15077     xmlXPathFreeParserContext(ctxt);
15078     return(res);
15079 }
15080
15081 /**
15082  * xmlXPathSetContextNode:
15083  * @node: the node to to use as the context node
15084  * @ctx:  the XPath context
15085  *
15086  * Sets 'node' as the context node. The node must be in the same
15087  * document as that associated with the context.
15088  *
15089  * Returns -1 in case of error or 0 if successful
15090  */
15091 int
15092 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15093     if ((node == NULL) || (ctx == NULL))
15094         return(-1);
15095
15096     if (node->doc == ctx->doc) {
15097         ctx->node = node;
15098         return(0);
15099     }
15100     return(-1);
15101 }
15102
15103 /**
15104  * xmlXPathNodeEval:
15105  * @node: the node to to use as the context node
15106  * @str:  the XPath expression
15107  * @ctx:  the XPath context
15108  *
15109  * Evaluate the XPath Location Path in the given context. The node 'node'
15110  * is set as the context node. The context node is not restored.
15111  *
15112  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15113  *         the caller has to free the object.
15114  */
15115 xmlXPathObjectPtr
15116 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15117     if (str == NULL)
15118         return(NULL);
15119     if (xmlXPathSetContextNode(node, ctx) < 0)
15120         return(NULL);
15121     return(xmlXPathEval(str, ctx));
15122 }
15123
15124 /**
15125  * xmlXPathEvalExpression:
15126  * @str:  the XPath expression
15127  * @ctxt:  the XPath context
15128  *
15129  * Evaluate the XPath expression in the given context.
15130  *
15131  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15132  *         the caller has to free the object.
15133  */
15134 xmlXPathObjectPtr
15135 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15136     xmlXPathParserContextPtr pctxt;
15137     xmlXPathObjectPtr res, tmp;
15138     int stack = 0;
15139
15140     CHECK_CTXT(ctxt)
15141
15142     xmlXPathInit();
15143
15144     pctxt = xmlXPathNewParserContext(str, ctxt);
15145     if (pctxt == NULL)
15146         return NULL;
15147     xmlXPathEvalExpr(pctxt);
15148
15149     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
15150         xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15151         res = NULL;
15152     } else {
15153         res = valuePop(pctxt);
15154     }
15155     do {
15156         tmp = valuePop(pctxt);
15157         if (tmp != NULL) {
15158             xmlXPathReleaseObject(ctxt, tmp);
15159             stack++;
15160         }
15161     } while (tmp != NULL);
15162     if ((stack != 0) && (res != NULL)) {
15163         xmlGenericError(xmlGenericErrorContext,
15164                 "xmlXPathEvalExpression: %d object left on the stack\n",
15165                 stack);
15166     }
15167     xmlXPathFreeParserContext(pctxt);
15168     return(res);
15169 }
15170
15171 /************************************************************************
15172  *                                                                      *
15173  *      Extra functions not pertaining to the XPath spec                *
15174  *                                                                      *
15175  ************************************************************************/
15176 /**
15177  * xmlXPathEscapeUriFunction:
15178  * @ctxt:  the XPath Parser context
15179  * @nargs:  the number of arguments
15180  *
15181  * Implement the escape-uri() XPath function
15182  *    string escape-uri(string $str, bool $escape-reserved)
15183  *
15184  * This function applies the URI escaping rules defined in section 2 of [RFC
15185  * 2396] to the string supplied as $uri-part, which typically represents all
15186  * or part of a URI. The effect of the function is to replace any special
15187  * character in the string by an escape sequence of the form %xx%yy...,
15188  * where xxyy... is the hexadecimal representation of the octets used to
15189  * represent the character in UTF-8.
15190  *
15191  * The set of characters that are escaped depends on the setting of the
15192  * boolean argument $escape-reserved.
15193  *
15194  * If $escape-reserved is true, all characters are escaped other than lower
15195  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15196  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15197  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15198  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15199  * A-F).
15200  *
15201  * If $escape-reserved is false, the behavior differs in that characters
15202  * referred to in [RFC 2396] as reserved characters are not escaped. These
15203  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15204  *
15205  * [RFC 2396] does not define whether escaped URIs should use lower case or
15206  * upper case for hexadecimal digits. To ensure that escaped URIs can be
15207  * compared using string comparison functions, this function must always use
15208  * the upper-case letters A-F.
15209  *
15210  * Generally, $escape-reserved should be set to true when escaping a string
15211  * that is to form a single part of a URI, and to false when escaping an
15212  * entire URI or URI reference.
15213  *
15214  * In the case of non-ascii characters, the string is encoded according to
15215  * utf-8 and then converted according to RFC 2396.
15216  *
15217  * Examples
15218  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15219  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15220  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15221  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15222  *
15223  */
15224 static void
15225 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15226     xmlXPathObjectPtr str;
15227     int escape_reserved;
15228     xmlBufPtr target;
15229     xmlChar *cptr;
15230     xmlChar escape[4];
15231
15232     CHECK_ARITY(2);
15233
15234     escape_reserved = xmlXPathPopBoolean(ctxt);
15235
15236     CAST_TO_STRING;
15237     str = valuePop(ctxt);
15238
15239     target = xmlBufCreate();
15240
15241     escape[0] = '%';
15242     escape[3] = 0;
15243
15244     if (target) {
15245         for (cptr = str->stringval; *cptr; cptr++) {
15246             if ((*cptr >= 'A' && *cptr <= 'Z') ||
15247                 (*cptr >= 'a' && *cptr <= 'z') ||
15248                 (*cptr >= '0' && *cptr <= '9') ||
15249                 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15250                 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15251                 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15252                 (*cptr == '%' &&
15253                  ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15254                   (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15255                   (cptr[1] >= '0' && cptr[1] <= '9')) &&
15256                  ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15257                   (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15258                   (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15259                 (!escape_reserved &&
15260                  (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15261                   *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15262                   *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15263                   *cptr == ','))) {
15264                 xmlBufAdd(target, cptr, 1);
15265             } else {
15266                 if ((*cptr >> 4) < 10)
15267                     escape[1] = '0' + (*cptr >> 4);
15268                 else
15269                     escape[1] = 'A' - 10 + (*cptr >> 4);
15270                 if ((*cptr & 0xF) < 10)
15271                     escape[2] = '0' + (*cptr & 0xF);
15272                 else
15273                     escape[2] = 'A' - 10 + (*cptr & 0xF);
15274
15275                 xmlBufAdd(target, &escape[0], 3);
15276             }
15277         }
15278     }
15279     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15280         xmlBufContent(target)));
15281     xmlBufFree(target);
15282     xmlXPathReleaseObject(ctxt->context, str);
15283 }
15284
15285 /**
15286  * xmlXPathRegisterAllFunctions:
15287  * @ctxt:  the XPath context
15288  *
15289  * Registers all default XPath functions in this context
15290  */
15291 void
15292 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15293 {
15294     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15295                          xmlXPathBooleanFunction);
15296     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15297                          xmlXPathCeilingFunction);
15298     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15299                          xmlXPathCountFunction);
15300     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15301                          xmlXPathConcatFunction);
15302     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15303                          xmlXPathContainsFunction);
15304     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15305                          xmlXPathIdFunction);
15306     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15307                          xmlXPathFalseFunction);
15308     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15309                          xmlXPathFloorFunction);
15310     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15311                          xmlXPathLastFunction);
15312     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15313                          xmlXPathLangFunction);
15314     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15315                          xmlXPathLocalNameFunction);
15316     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15317                          xmlXPathNotFunction);
15318     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15319                          xmlXPathNameFunction);
15320     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15321                          xmlXPathNamespaceURIFunction);
15322     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15323                          xmlXPathNormalizeFunction);
15324     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15325                          xmlXPathNumberFunction);
15326     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15327                          xmlXPathPositionFunction);
15328     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15329                          xmlXPathRoundFunction);
15330     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15331                          xmlXPathStringFunction);
15332     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15333                          xmlXPathStringLengthFunction);
15334     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15335                          xmlXPathStartsWithFunction);
15336     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15337                          xmlXPathSubstringFunction);
15338     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15339                          xmlXPathSubstringBeforeFunction);
15340     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15341                          xmlXPathSubstringAfterFunction);
15342     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15343                          xmlXPathSumFunction);
15344     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15345                          xmlXPathTrueFunction);
15346     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15347                          xmlXPathTranslateFunction);
15348
15349     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15350          (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15351                          xmlXPathEscapeUriFunction);
15352 }
15353
15354 #endif /* LIBXML_XPATH_ENABLED */
15355 #define bottom_xpath
15356 #include "elfgcchack.h"