tizen 2.3.1 release
[external/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 #ifdef LIBXML_PATTERN_ENABLED
59 #define XPATH_STREAMING
60 #endif
61
62 #define TODO                                                            \
63     xmlGenericError(xmlGenericErrorContext,                             \
64             "Unimplemented block at %s:%d\n",                           \
65             __FILE__, __LINE__);
66
67 /*
68 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
69 * If defined, this will use xmlXPathCmpNodesExt() instead of
70 * xmlXPathCmpNodes(). The new function is optimized comparison of
71 * non-element nodes; actually it will speed up comparison only if
72 * xmlXPathOrderDocElems() was called in order to index the elements of
73 * a tree in document order; Libxslt does such an indexing, thus it will
74 * benefit from this optimization.
75 */
76 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
77
78 /*
79 * XP_OPTIMIZED_FILTER_FIRST:
80 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81 * in a way, that it stop evaluation at the first node.
82 */
83 #define XP_OPTIMIZED_FILTER_FIRST
84
85 /*
86 * XP_DEBUG_OBJ_USAGE:
87 * Internal flag to enable tracking of how much XPath objects have been
88 * created.
89 */
90 /* #define XP_DEBUG_OBJ_USAGE */
91
92 /*
93  * TODO:
94  * There are a few spots where some tests are done which depend upon ascii
95  * data.  These should be enhanced for full UTF8 support (see particularly
96  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
97  */
98
99 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
100
101 /************************************************************************
102  *                                                                      *
103  *                      Floating point stuff                            *
104  *                                                                      *
105  ************************************************************************/
106
107 #ifndef TRIO_REPLACE_STDIO
108 #define TRIO_PUBLIC static
109 #endif
110 #include "trionan.c"
111
112 /*
113  * The lack of portability of this section of the libc is annoying !
114  */
115 double xmlXPathNAN = 0;
116 double xmlXPathPINF = 1;
117 double xmlXPathNINF = -1;
118 static double xmlXPathNZERO = 0; /* not exported from headers */
119 static int xmlXPathInitialized = 0;
120
121 /**
122  * xmlXPathInit:
123  *
124  * Initialize the XPath environment
125  */
126 void
127 xmlXPathInit(void) {
128     if (xmlXPathInitialized) return;
129
130     xmlXPathPINF = trio_pinf();
131     xmlXPathNINF = trio_ninf();
132     xmlXPathNAN = trio_nan();
133     xmlXPathNZERO = trio_nzero();
134
135     xmlXPathInitialized = 1;
136 }
137
138 /**
139  * xmlXPathIsNaN:
140  * @val:  a double value
141  *
142  * Provides a portable isnan() function to detect whether a double
143  * is a NotaNumber. Based on trio code
144  * http://sourceforge.net/projects/ctrio/
145  *
146  * Returns 1 if the value is a NaN, 0 otherwise
147  */
148 int
149 xmlXPathIsNaN(double val) {
150     return(trio_isnan(val));
151 }
152
153 /**
154  * xmlXPathIsInf:
155  * @val:  a double value
156  *
157  * Provides a portable isinf() function to detect whether a double
158  * is a +Infinite or -Infinite. Based on trio code
159  * http://sourceforge.net/projects/ctrio/
160  *
161  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
162  */
163 int
164 xmlXPathIsInf(double val) {
165     return(trio_isinf(val));
166 }
167
168 #endif /* SCHEMAS or XPATH */
169 #ifdef LIBXML_XPATH_ENABLED
170 /**
171  * xmlXPathGetSign:
172  * @val:  a double value
173  *
174  * Provides a portable function to detect the sign of a double
175  * Modified from trio code
176  * http://sourceforge.net/projects/ctrio/
177  *
178  * Returns 1 if the value is Negative, 0 if positive
179  */
180 static int
181 xmlXPathGetSign(double val) {
182     return(trio_signbit(val));
183 }
184
185
186 /*
187  * TODO: when compatibility allows remove all "fake node libxslt" strings
188  *       the test should just be name[0] = ' '
189  */
190 #ifdef DEBUG_XPATH_EXPRESSION
191 #define DEBUG_STEP
192 #define DEBUG_EXPR
193 #define DEBUG_EVAL_COUNTS
194 #endif
195
196 static xmlNs xmlXPathXMLNamespaceStruct = {
197     NULL,
198     XML_NAMESPACE_DECL,
199     XML_XML_NAMESPACE,
200     BAD_CAST "xml",
201     NULL,
202     NULL
203 };
204 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
205 #ifndef LIBXML_THREAD_ENABLED
206 /*
207  * Optimizer is disabled only when threaded apps are detected while
208  * the library ain't compiled for thread safety.
209  */
210 static int xmlXPathDisableOptimizer = 0;
211 #endif
212
213 /************************************************************************
214  *                                                                      *
215  *                      Error handling routines                         *
216  *                                                                      *
217  ************************************************************************/
218
219 /**
220  * XP_ERRORNULL:
221  * @X:  the error code
222  *
223  * Macro to raise an XPath error and return NULL.
224  */
225 #define XP_ERRORNULL(X)                                                 \
226     { xmlXPathErr(ctxt, X); return(NULL); }
227
228 /*
229  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
230  */
231 static const char *xmlXPathErrorMessages[] = {
232     "Ok\n",
233     "Number encoding\n",
234     "Unfinished literal\n",
235     "Start of literal\n",
236     "Expected $ for variable reference\n",
237     "Undefined variable\n",
238     "Invalid predicate\n",
239     "Invalid expression\n",
240     "Missing closing curly brace\n",
241     "Unregistered function\n",
242     "Invalid operand\n",
243     "Invalid type\n",
244     "Invalid number of arguments\n",
245     "Invalid context size\n",
246     "Invalid context position\n",
247     "Memory allocation error\n",
248     "Syntax error\n",
249     "Resource error\n",
250     "Sub resource error\n",
251     "Undefined namespace prefix\n",
252     "Encoding error\n",
253     "Char out of XML range\n",
254     "Invalid or incomplete context\n",
255     "?? Unknown error ??\n"     /* Must be last in the list! */
256 };
257 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
258                    sizeof(xmlXPathErrorMessages[0])) - 1)
259 /**
260  * xmlXPathErrMemory:
261  * @ctxt:  an XPath context
262  * @extra:  extra informations
263  *
264  * Handle a redefinition of attribute error
265  */
266 static void
267 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
268 {
269     if (ctxt != NULL) {
270         if (extra) {
271             xmlChar buf[200];
272
273             xmlStrPrintf(buf, 200,
274                          BAD_CAST "Memory allocation failed : %s\n",
275                          extra);
276             ctxt->lastError.message = (char *) xmlStrdup(buf);
277         } else {
278             ctxt->lastError.message = (char *)
279                xmlStrdup(BAD_CAST "Memory allocation failed\n");
280         }
281         ctxt->lastError.domain = XML_FROM_XPATH;
282         ctxt->lastError.code = XML_ERR_NO_MEMORY;
283         if (ctxt->error != NULL)
284             ctxt->error(ctxt->userData, &ctxt->lastError);
285     } else {
286         if (extra)
287             __xmlRaiseError(NULL, NULL, NULL,
288                             NULL, NULL, XML_FROM_XPATH,
289                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
290                             extra, NULL, NULL, 0, 0,
291                             "Memory allocation failed : %s\n", extra);
292         else
293             __xmlRaiseError(NULL, NULL, NULL,
294                             NULL, NULL, XML_FROM_XPATH,
295                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
296                             NULL, NULL, NULL, 0, 0,
297                             "Memory allocation failed\n");
298     }
299 }
300
301 /**
302  * xmlXPathPErrMemory:
303  * @ctxt:  an XPath parser context
304  * @extra:  extra informations
305  *
306  * Handle a redefinition of attribute error
307  */
308 static void
309 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
310 {
311     if (ctxt == NULL)
312         xmlXPathErrMemory(NULL, extra);
313     else {
314         ctxt->error = XPATH_MEMORY_ERROR;
315         xmlXPathErrMemory(ctxt->context, extra);
316     }
317 }
318
319 /**
320  * xmlXPathErr:
321  * @ctxt:  a XPath parser context
322  * @error:  the error code
323  *
324  * Handle an XPath error
325  */
326 void
327 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
328 {
329     if ((error < 0) || (error > MAXERRNO))
330         error = MAXERRNO;
331     if (ctxt == NULL) {
332         __xmlRaiseError(NULL, NULL, NULL,
333                         NULL, NULL, XML_FROM_XPATH,
334                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
335                         XML_ERR_ERROR, NULL, 0,
336                         NULL, NULL, NULL, 0, 0,
337                         "%s", xmlXPathErrorMessages[error]);
338         return;
339     }
340     ctxt->error = error;
341     if (ctxt->context == NULL) {
342         __xmlRaiseError(NULL, NULL, NULL,
343                         NULL, NULL, XML_FROM_XPATH,
344                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
345                         XML_ERR_ERROR, NULL, 0,
346                         (const char *) ctxt->base, NULL, NULL,
347                         ctxt->cur - ctxt->base, 0,
348                         "%s", xmlXPathErrorMessages[error]);
349         return;
350     }
351
352     /* cleanup current last error */
353     xmlResetError(&ctxt->context->lastError);
354
355     ctxt->context->lastError.domain = XML_FROM_XPATH;
356     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
357                            XPATH_EXPRESSION_OK;
358     ctxt->context->lastError.level = XML_ERR_ERROR;
359     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
360     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
361     ctxt->context->lastError.node = ctxt->context->debugNode;
362     if (ctxt->context->error != NULL) {
363         ctxt->context->error(ctxt->context->userData,
364                              &ctxt->context->lastError);
365     } else {
366         __xmlRaiseError(NULL, NULL, NULL,
367                         NULL, ctxt->context->debugNode, XML_FROM_XPATH,
368                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
369                         XML_ERR_ERROR, NULL, 0,
370                         (const char *) ctxt->base, NULL, NULL,
371                         ctxt->cur - ctxt->base, 0,
372                         "%s", xmlXPathErrorMessages[error]);
373     }
374
375 }
376
377 /**
378  * xmlXPatherror:
379  * @ctxt:  the XPath Parser context
380  * @file:  the file name
381  * @line:  the line number
382  * @no:  the error number
383  *
384  * Formats an error message.
385  */
386 void
387 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
388               int line ATTRIBUTE_UNUSED, int no) {
389     xmlXPathErr(ctxt, no);
390 }
391
392 /************************************************************************
393  *                                                                      *
394  *                      Utilities                                       *
395  *                                                                      *
396  ************************************************************************/
397
398 /**
399  * xsltPointerList:
400  *
401  * Pointer-list for various purposes.
402  */
403 typedef struct _xmlPointerList xmlPointerList;
404 typedef xmlPointerList *xmlPointerListPtr;
405 struct _xmlPointerList {
406     void **items;
407     int number;
408     int size;
409 };
410 /*
411 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
412 * and here, we should make the functions public.
413 */
414 static int
415 xmlPointerListAddSize(xmlPointerListPtr list,
416                        void *item,
417                        int initialSize)
418 {
419     if (list->items == NULL) {
420         if (initialSize <= 0)
421             initialSize = 1;
422         list->items = (void **) xmlMalloc(
423             initialSize * sizeof(void *));
424         if (list->items == NULL) {
425             xmlXPathErrMemory(NULL,
426                 "xmlPointerListCreate: allocating item\n");
427             return(-1);
428         }
429         list->number = 0;
430         list->size = initialSize;
431     } else if (list->size <= list->number) {
432         list->size *= 2;
433         list->items = (void **) xmlRealloc(list->items,
434             list->size * sizeof(void *));
435         if (list->items == NULL) {
436             xmlXPathErrMemory(NULL,
437                 "xmlPointerListCreate: re-allocating item\n");
438             list->size = 0;
439             return(-1);
440         }
441     }
442     list->items[list->number++] = item;
443     return(0);
444 }
445
446 /**
447  * xsltPointerListCreate:
448  *
449  * Creates an xsltPointerList structure.
450  *
451  * Returns a xsltPointerList structure or NULL in case of an error.
452  */
453 static xmlPointerListPtr
454 xmlPointerListCreate(int initialSize)
455 {
456     xmlPointerListPtr ret;
457
458     ret = xmlMalloc(sizeof(xmlPointerList));
459     if (ret == NULL) {
460         xmlXPathErrMemory(NULL,
461             "xmlPointerListCreate: allocating item\n");
462         return (NULL);
463     }
464     memset(ret, 0, sizeof(xmlPointerList));
465     if (initialSize > 0) {
466         xmlPointerListAddSize(ret, NULL, initialSize);
467         ret->number = 0;
468     }
469     return (ret);
470 }
471
472 /**
473  * xsltPointerListFree:
474  *
475  * Frees the xsltPointerList structure. This does not free
476  * the content of the list.
477  */
478 static void
479 xmlPointerListFree(xmlPointerListPtr list)
480 {
481     if (list == NULL)
482         return;
483     if (list->items != NULL)
484         xmlFree(list->items);
485     xmlFree(list);
486 }
487
488 /************************************************************************
489  *                                                                      *
490  *                      Parser Types                                    *
491  *                                                                      *
492  ************************************************************************/
493
494 /*
495  * Types are private:
496  */
497
498 typedef enum {
499     XPATH_OP_END=0,
500     XPATH_OP_AND,
501     XPATH_OP_OR,
502     XPATH_OP_EQUAL,
503     XPATH_OP_CMP,
504     XPATH_OP_PLUS,
505     XPATH_OP_MULT,
506     XPATH_OP_UNION,
507     XPATH_OP_ROOT,
508     XPATH_OP_NODE,
509     XPATH_OP_RESET, /* 10 */
510     XPATH_OP_COLLECT,
511     XPATH_OP_VALUE, /* 12 */
512     XPATH_OP_VARIABLE,
513     XPATH_OP_FUNCTION,
514     XPATH_OP_ARG,
515     XPATH_OP_PREDICATE,
516     XPATH_OP_FILTER, /* 17 */
517     XPATH_OP_SORT /* 18 */
518 #ifdef LIBXML_XPTR_ENABLED
519     ,XPATH_OP_RANGETO
520 #endif
521 } xmlXPathOp;
522
523 typedef enum {
524     AXIS_ANCESTOR = 1,
525     AXIS_ANCESTOR_OR_SELF,
526     AXIS_ATTRIBUTE,
527     AXIS_CHILD,
528     AXIS_DESCENDANT,
529     AXIS_DESCENDANT_OR_SELF,
530     AXIS_FOLLOWING,
531     AXIS_FOLLOWING_SIBLING,
532     AXIS_NAMESPACE,
533     AXIS_PARENT,
534     AXIS_PRECEDING,
535     AXIS_PRECEDING_SIBLING,
536     AXIS_SELF
537 } xmlXPathAxisVal;
538
539 typedef enum {
540     NODE_TEST_NONE = 0,
541     NODE_TEST_TYPE = 1,
542     NODE_TEST_PI = 2,
543     NODE_TEST_ALL = 3,
544     NODE_TEST_NS = 4,
545     NODE_TEST_NAME = 5
546 } xmlXPathTestVal;
547
548 typedef enum {
549     NODE_TYPE_NODE = 0,
550     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
551     NODE_TYPE_TEXT = XML_TEXT_NODE,
552     NODE_TYPE_PI = XML_PI_NODE
553 } xmlXPathTypeVal;
554
555 #define XP_REWRITE_DOS_CHILD_ELEM 1
556
557 typedef struct _xmlXPathStepOp xmlXPathStepOp;
558 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
559 struct _xmlXPathStepOp {
560     xmlXPathOp op;              /* The identifier of the operation */
561     int ch1;                    /* First child */
562     int ch2;                    /* Second child */
563     int value;
564     int value2;
565     int value3;
566     void *value4;
567     void *value5;
568     void *cache;
569     void *cacheURI;
570     int rewriteType;
571 };
572
573 struct _xmlXPathCompExpr {
574     int nbStep;                 /* Number of steps in this expression */
575     int maxStep;                /* Maximum number of steps allocated */
576     xmlXPathStepOp *steps;      /* ops for computation of this expression */
577     int last;                   /* index of last step in expression */
578     xmlChar *expr;              /* the expression being computed */
579     xmlDictPtr dict;            /* the dictionnary to use if any */
580 #ifdef DEBUG_EVAL_COUNTS
581     int nb;
582     xmlChar *string;
583 #endif
584 #ifdef XPATH_STREAMING
585     xmlPatternPtr stream;
586 #endif
587 };
588
589 /************************************************************************
590  *                                                                      *
591  *                      Forward declarations                            *
592  *                                                                      *
593  ************************************************************************/
594 static void
595 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
596 static void
597 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
598 static int
599 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
600                         xmlXPathStepOpPtr op, xmlNodePtr *first);
601 static int
602 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
603                             xmlXPathStepOpPtr op,
604                             int isPredicate);
605
606 /************************************************************************
607  *                                                                      *
608  *                      Parser Type functions                           *
609  *                                                                      *
610  ************************************************************************/
611
612 /**
613  * xmlXPathNewCompExpr:
614  *
615  * Create a new Xpath component
616  *
617  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
618  */
619 static xmlXPathCompExprPtr
620 xmlXPathNewCompExpr(void) {
621     xmlXPathCompExprPtr cur;
622
623     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
624     if (cur == NULL) {
625         xmlXPathErrMemory(NULL, "allocating component\n");
626         return(NULL);
627     }
628     memset(cur, 0, sizeof(xmlXPathCompExpr));
629     cur->maxStep = 10;
630     cur->nbStep = 0;
631     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
632                                            sizeof(xmlXPathStepOp));
633     if (cur->steps == NULL) {
634         xmlXPathErrMemory(NULL, "allocating steps\n");
635         xmlFree(cur);
636         return(NULL);
637     }
638     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
639     cur->last = -1;
640 #ifdef DEBUG_EVAL_COUNTS
641     cur->nb = 0;
642 #endif
643     return(cur);
644 }
645
646 /**
647  * xmlXPathFreeCompExpr:
648  * @comp:  an XPATH comp
649  *
650  * Free up the memory allocated by @comp
651  */
652 void
653 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
654 {
655     xmlXPathStepOpPtr op;
656     int i;
657
658     if (comp == NULL)
659         return;
660     if (comp->dict == NULL) {
661         for (i = 0; i < comp->nbStep; i++) {
662             op = &comp->steps[i];
663             if (op->value4 != NULL) {
664                 if (op->op == XPATH_OP_VALUE)
665                     xmlXPathFreeObject(op->value4);
666                 else
667                     xmlFree(op->value4);
668             }
669             if (op->value5 != NULL)
670                 xmlFree(op->value5);
671         }
672     } else {
673         for (i = 0; i < comp->nbStep; i++) {
674             op = &comp->steps[i];
675             if (op->value4 != NULL) {
676                 if (op->op == XPATH_OP_VALUE)
677                     xmlXPathFreeObject(op->value4);
678             }
679         }
680         xmlDictFree(comp->dict);
681     }
682     if (comp->steps != NULL) {
683         xmlFree(comp->steps);
684     }
685 #ifdef DEBUG_EVAL_COUNTS
686     if (comp->string != NULL) {
687         xmlFree(comp->string);
688     }
689 #endif
690 #ifdef XPATH_STREAMING
691     if (comp->stream != NULL) {
692         xmlFreePatternList(comp->stream);
693     }
694 #endif
695     if (comp->expr != NULL) {
696         xmlFree(comp->expr);
697     }
698
699     xmlFree(comp);
700 }
701
702 /**
703  * xmlXPathCompExprAdd:
704  * @comp:  the compiled expression
705  * @ch1: first child index
706  * @ch2: second child index
707  * @op:  an op
708  * @value:  the first int value
709  * @value2:  the second int value
710  * @value3:  the third int value
711  * @value4:  the first string value
712  * @value5:  the second string value
713  *
714  * Add a step to an XPath Compiled Expression
715  *
716  * Returns -1 in case of failure, the index otherwise
717  */
718 static int
719 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
720    xmlXPathOp op, int value,
721    int value2, int value3, void *value4, void *value5) {
722     if (comp->nbStep >= comp->maxStep) {
723         xmlXPathStepOp *real;
724
725         comp->maxStep *= 2;
726         real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
727                                       comp->maxStep * sizeof(xmlXPathStepOp));
728         if (real == NULL) {
729             comp->maxStep /= 2;
730             xmlXPathErrMemory(NULL, "adding step\n");
731             return(-1);
732         }
733         comp->steps = real;
734     }
735     comp->last = comp->nbStep;
736     comp->steps[comp->nbStep].rewriteType = 0;
737     comp->steps[comp->nbStep].ch1 = ch1;
738     comp->steps[comp->nbStep].ch2 = ch2;
739     comp->steps[comp->nbStep].op = op;
740     comp->steps[comp->nbStep].value = value;
741     comp->steps[comp->nbStep].value2 = value2;
742     comp->steps[comp->nbStep].value3 = value3;
743     if ((comp->dict != NULL) &&
744         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
745          (op == XPATH_OP_COLLECT))) {
746         if (value4 != NULL) {
747             comp->steps[comp->nbStep].value4 = (xmlChar *)
748                 (void *)xmlDictLookup(comp->dict, value4, -1);
749             xmlFree(value4);
750         } else
751             comp->steps[comp->nbStep].value4 = NULL;
752         if (value5 != NULL) {
753             comp->steps[comp->nbStep].value5 = (xmlChar *)
754                 (void *)xmlDictLookup(comp->dict, value5, -1);
755             xmlFree(value5);
756         } else
757             comp->steps[comp->nbStep].value5 = NULL;
758     } else {
759         comp->steps[comp->nbStep].value4 = value4;
760         comp->steps[comp->nbStep].value5 = value5;
761     }
762     comp->steps[comp->nbStep].cache = NULL;
763     return(comp->nbStep++);
764 }
765
766 /**
767  * xmlXPathCompSwap:
768  * @comp:  the compiled expression
769  * @op: operation index
770  *
771  * Swaps 2 operations in the compiled expression
772  */
773 static void
774 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
775     int tmp;
776
777 #ifndef LIBXML_THREAD_ENABLED
778     /*
779      * Since this manipulates possibly shared variables, this is
780      * disabled if one detects that the library is used in a multithreaded
781      * application
782      */
783     if (xmlXPathDisableOptimizer)
784         return;
785 #endif
786
787     tmp = op->ch1;
788     op->ch1 = op->ch2;
789     op->ch2 = tmp;
790 }
791
792 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)       \
793     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),                       \
794                         (op), (val), (val2), (val3), (val4), (val5))
795 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)                 \
796     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,               \
797                         (op), (val), (val2), (val3), (val4), (val5))
798
799 #define PUSH_LEAVE_EXPR(op, val, val2)                                  \
800 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
801
802 #define PUSH_UNARY_EXPR(op, ch, val, val2)                              \
803 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
804
805 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)                       \
806 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),                     \
807                         (val), (val2), 0 ,NULL ,NULL)
808
809 /************************************************************************
810  *                                                                      *
811  *              XPath object cache structures                           *
812  *                                                                      *
813  ************************************************************************/
814
815 /* #define XP_DEFAULT_CACHE_ON */
816
817 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
818
819 typedef struct _xmlXPathContextCache xmlXPathContextCache;
820 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
821 struct _xmlXPathContextCache {
822     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
823     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
824     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
825     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
826     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
827     int maxNodeset;
828     int maxString;
829     int maxBoolean;
830     int maxNumber;
831     int maxMisc;
832 #ifdef XP_DEBUG_OBJ_USAGE
833     int dbgCachedAll;
834     int dbgCachedNodeset;
835     int dbgCachedString;
836     int dbgCachedBool;
837     int dbgCachedNumber;
838     int dbgCachedPoint;
839     int dbgCachedRange;
840     int dbgCachedLocset;
841     int dbgCachedUsers;
842     int dbgCachedXSLTTree;
843     int dbgCachedUndefined;
844
845
846     int dbgReusedAll;
847     int dbgReusedNodeset;
848     int dbgReusedString;
849     int dbgReusedBool;
850     int dbgReusedNumber;
851     int dbgReusedPoint;
852     int dbgReusedRange;
853     int dbgReusedLocset;
854     int dbgReusedUsers;
855     int dbgReusedXSLTTree;
856     int dbgReusedUndefined;
857
858 #endif
859 };
860
861 /************************************************************************
862  *                                                                      *
863  *              Debugging related functions                             *
864  *                                                                      *
865  ************************************************************************/
866
867 #define STRANGE                                                 \
868     xmlGenericError(xmlGenericErrorContext,                             \
869             "Internal error at %s:%d\n",                                \
870             __FILE__, __LINE__);
871
872 #ifdef LIBXML_DEBUG_ENABLED
873 static void
874 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
875     int i;
876     char shift[100];
877
878     for (i = 0;((i < depth) && (i < 25));i++)
879         shift[2 * i] = shift[2 * i + 1] = ' ';
880     shift[2 * i] = shift[2 * i + 1] = 0;
881     if (cur == NULL) {
882         fprintf(output, "%s", shift);
883         fprintf(output, "Node is NULL !\n");
884         return;
885
886     }
887
888     if ((cur->type == XML_DOCUMENT_NODE) ||
889              (cur->type == XML_HTML_DOCUMENT_NODE)) {
890         fprintf(output, "%s", shift);
891         fprintf(output, " /\n");
892     } else if (cur->type == XML_ATTRIBUTE_NODE)
893         xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
894     else
895         xmlDebugDumpOneNode(output, cur, depth);
896 }
897 static void
898 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
899     xmlNodePtr tmp;
900     int i;
901     char shift[100];
902
903     for (i = 0;((i < depth) && (i < 25));i++)
904         shift[2 * i] = shift[2 * i + 1] = ' ';
905     shift[2 * i] = shift[2 * i + 1] = 0;
906     if (cur == NULL) {
907         fprintf(output, "%s", shift);
908         fprintf(output, "Node is NULL !\n");
909         return;
910
911     }
912
913     while (cur != NULL) {
914         tmp = cur;
915         cur = cur->next;
916         xmlDebugDumpOneNode(output, tmp, depth);
917     }
918 }
919
920 static void
921 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
922     int i;
923     char shift[100];
924
925     for (i = 0;((i < depth) && (i < 25));i++)
926         shift[2 * i] = shift[2 * i + 1] = ' ';
927     shift[2 * i] = shift[2 * i + 1] = 0;
928
929     if (cur == NULL) {
930         fprintf(output, "%s", shift);
931         fprintf(output, "NodeSet is NULL !\n");
932         return;
933
934     }
935
936     if (cur != NULL) {
937         fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
938         for (i = 0;i < cur->nodeNr;i++) {
939             fprintf(output, "%s", shift);
940             fprintf(output, "%d", i + 1);
941             xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
942         }
943     }
944 }
945
946 static void
947 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
948     int i;
949     char shift[100];
950
951     for (i = 0;((i < depth) && (i < 25));i++)
952         shift[2 * i] = shift[2 * i + 1] = ' ';
953     shift[2 * i] = shift[2 * i + 1] = 0;
954
955     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
956         fprintf(output, "%s", shift);
957         fprintf(output, "Value Tree is NULL !\n");
958         return;
959
960     }
961
962     fprintf(output, "%s", shift);
963     fprintf(output, "%d", i + 1);
964     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
965 }
966 #if defined(LIBXML_XPTR_ENABLED)
967 static void
968 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
969     int i;
970     char shift[100];
971
972     for (i = 0;((i < depth) && (i < 25));i++)
973         shift[2 * i] = shift[2 * i + 1] = ' ';
974     shift[2 * i] = shift[2 * i + 1] = 0;
975
976     if (cur == NULL) {
977         fprintf(output, "%s", shift);
978         fprintf(output, "LocationSet is NULL !\n");
979         return;
980
981     }
982
983     for (i = 0;i < cur->locNr;i++) {
984         fprintf(output, "%s", shift);
985         fprintf(output, "%d : ", i + 1);
986         xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
987     }
988 }
989 #endif /* LIBXML_XPTR_ENABLED */
990
991 /**
992  * xmlXPathDebugDumpObject:
993  * @output:  the FILE * to dump the output
994  * @cur:  the object to inspect
995  * @depth:  indentation level
996  *
997  * Dump the content of the object for debugging purposes
998  */
999 void
1000 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1001     int i;
1002     char shift[100];
1003
1004     if (output == NULL) return;
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
1011     fprintf(output, "%s", shift);
1012
1013     if (cur == NULL) {
1014         fprintf(output, "Object is empty (NULL)\n");
1015         return;
1016     }
1017     switch(cur->type) {
1018         case XPATH_UNDEFINED:
1019             fprintf(output, "Object is uninitialized\n");
1020             break;
1021         case XPATH_NODESET:
1022             fprintf(output, "Object is a Node Set :\n");
1023             xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1024             break;
1025         case XPATH_XSLT_TREE:
1026             fprintf(output, "Object is an XSLT value tree :\n");
1027             xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1028             break;
1029         case XPATH_BOOLEAN:
1030             fprintf(output, "Object is a Boolean : ");
1031             if (cur->boolval) fprintf(output, "true\n");
1032             else fprintf(output, "false\n");
1033             break;
1034         case XPATH_NUMBER:
1035             switch (xmlXPathIsInf(cur->floatval)) {
1036             case 1:
1037                 fprintf(output, "Object is a number : Infinity\n");
1038                 break;
1039             case -1:
1040                 fprintf(output, "Object is a number : -Infinity\n");
1041                 break;
1042             default:
1043                 if (xmlXPathIsNaN(cur->floatval)) {
1044                     fprintf(output, "Object is a number : NaN\n");
1045                 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1046                     fprintf(output, "Object is a number : 0\n");
1047                 } else {
1048                     fprintf(output, "Object is a number : %0g\n", cur->floatval);
1049                 }
1050             }
1051             break;
1052         case XPATH_STRING:
1053             fprintf(output, "Object is a string : ");
1054             xmlDebugDumpString(output, cur->stringval);
1055             fprintf(output, "\n");
1056             break;
1057         case XPATH_POINT:
1058             fprintf(output, "Object is a point : index %d in node", cur->index);
1059             xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1060             fprintf(output, "\n");
1061             break;
1062         case XPATH_RANGE:
1063             if ((cur->user2 == NULL) ||
1064                 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1065                 fprintf(output, "Object is a collapsed range :\n");
1066                 fprintf(output, "%s", shift);
1067                 if (cur->index >= 0)
1068                     fprintf(output, "index %d in ", cur->index);
1069                 fprintf(output, "node\n");
1070                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1071                                       depth + 1);
1072             } else  {
1073                 fprintf(output, "Object is a range :\n");
1074                 fprintf(output, "%s", shift);
1075                 fprintf(output, "From ");
1076                 if (cur->index >= 0)
1077                     fprintf(output, "index %d in ", cur->index);
1078                 fprintf(output, "node\n");
1079                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1080                                       depth + 1);
1081                 fprintf(output, "%s", shift);
1082                 fprintf(output, "To ");
1083                 if (cur->index2 >= 0)
1084                     fprintf(output, "index %d in ", cur->index2);
1085                 fprintf(output, "node\n");
1086                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1087                                       depth + 1);
1088                 fprintf(output, "\n");
1089             }
1090             break;
1091         case XPATH_LOCATIONSET:
1092 #if defined(LIBXML_XPTR_ENABLED)
1093             fprintf(output, "Object is a Location Set:\n");
1094             xmlXPathDebugDumpLocationSet(output,
1095                     (xmlLocationSetPtr) cur->user, depth);
1096 #endif
1097             break;
1098         case XPATH_USERS:
1099             fprintf(output, "Object is user defined\n");
1100             break;
1101     }
1102 }
1103
1104 static void
1105 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1106                              xmlXPathStepOpPtr op, int depth) {
1107     int i;
1108     char shift[100];
1109
1110     for (i = 0;((i < depth) && (i < 25));i++)
1111         shift[2 * i] = shift[2 * i + 1] = ' ';
1112     shift[2 * i] = shift[2 * i + 1] = 0;
1113
1114     fprintf(output, "%s", shift);
1115     if (op == NULL) {
1116         fprintf(output, "Step is NULL\n");
1117         return;
1118     }
1119     switch (op->op) {
1120         case XPATH_OP_END:
1121             fprintf(output, "END"); break;
1122         case XPATH_OP_AND:
1123             fprintf(output, "AND"); break;
1124         case XPATH_OP_OR:
1125             fprintf(output, "OR"); break;
1126         case XPATH_OP_EQUAL:
1127              if (op->value)
1128                  fprintf(output, "EQUAL =");
1129              else
1130                  fprintf(output, "EQUAL !=");
1131              break;
1132         case XPATH_OP_CMP:
1133              if (op->value)
1134                  fprintf(output, "CMP <");
1135              else
1136                  fprintf(output, "CMP >");
1137              if (!op->value2)
1138                  fprintf(output, "=");
1139              break;
1140         case XPATH_OP_PLUS:
1141              if (op->value == 0)
1142                  fprintf(output, "PLUS -");
1143              else if (op->value == 1)
1144                  fprintf(output, "PLUS +");
1145              else if (op->value == 2)
1146                  fprintf(output, "PLUS unary -");
1147              else if (op->value == 3)
1148                  fprintf(output, "PLUS unary - -");
1149              break;
1150         case XPATH_OP_MULT:
1151              if (op->value == 0)
1152                  fprintf(output, "MULT *");
1153              else if (op->value == 1)
1154                  fprintf(output, "MULT div");
1155              else
1156                  fprintf(output, "MULT mod");
1157              break;
1158         case XPATH_OP_UNION:
1159              fprintf(output, "UNION"); break;
1160         case XPATH_OP_ROOT:
1161              fprintf(output, "ROOT"); break;
1162         case XPATH_OP_NODE:
1163              fprintf(output, "NODE"); break;
1164         case XPATH_OP_RESET:
1165              fprintf(output, "RESET"); break;
1166         case XPATH_OP_SORT:
1167              fprintf(output, "SORT"); break;
1168         case XPATH_OP_COLLECT: {
1169             xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1170             xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1171             xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1172             const xmlChar *prefix = op->value4;
1173             const xmlChar *name = op->value5;
1174
1175             fprintf(output, "COLLECT ");
1176             switch (axis) {
1177                 case AXIS_ANCESTOR:
1178                     fprintf(output, " 'ancestors' "); break;
1179                 case AXIS_ANCESTOR_OR_SELF:
1180                     fprintf(output, " 'ancestors-or-self' "); break;
1181                 case AXIS_ATTRIBUTE:
1182                     fprintf(output, " 'attributes' "); break;
1183                 case AXIS_CHILD:
1184                     fprintf(output, " 'child' "); break;
1185                 case AXIS_DESCENDANT:
1186                     fprintf(output, " 'descendant' "); break;
1187                 case AXIS_DESCENDANT_OR_SELF:
1188                     fprintf(output, " 'descendant-or-self' "); break;
1189                 case AXIS_FOLLOWING:
1190                     fprintf(output, " 'following' "); break;
1191                 case AXIS_FOLLOWING_SIBLING:
1192                     fprintf(output, " 'following-siblings' "); break;
1193                 case AXIS_NAMESPACE:
1194                     fprintf(output, " 'namespace' "); break;
1195                 case AXIS_PARENT:
1196                     fprintf(output, " 'parent' "); break;
1197                 case AXIS_PRECEDING:
1198                     fprintf(output, " 'preceding' "); break;
1199                 case AXIS_PRECEDING_SIBLING:
1200                     fprintf(output, " 'preceding-sibling' "); break;
1201                 case AXIS_SELF:
1202                     fprintf(output, " 'self' "); break;
1203             }
1204             switch (test) {
1205                 case NODE_TEST_NONE:
1206                     fprintf(output, "'none' "); break;
1207                 case NODE_TEST_TYPE:
1208                     fprintf(output, "'type' "); break;
1209                 case NODE_TEST_PI:
1210                     fprintf(output, "'PI' "); break;
1211                 case NODE_TEST_ALL:
1212                     fprintf(output, "'all' "); break;
1213                 case NODE_TEST_NS:
1214                     fprintf(output, "'namespace' "); break;
1215                 case NODE_TEST_NAME:
1216                     fprintf(output, "'name' "); break;
1217             }
1218             switch (type) {
1219                 case NODE_TYPE_NODE:
1220                     fprintf(output, "'node' "); break;
1221                 case NODE_TYPE_COMMENT:
1222                     fprintf(output, "'comment' "); break;
1223                 case NODE_TYPE_TEXT:
1224                     fprintf(output, "'text' "); break;
1225                 case NODE_TYPE_PI:
1226                     fprintf(output, "'PI' "); break;
1227             }
1228             if (prefix != NULL)
1229                 fprintf(output, "%s:", prefix);
1230             if (name != NULL)
1231                 fprintf(output, "%s", (const char *) name);
1232             break;
1233
1234         }
1235         case XPATH_OP_VALUE: {
1236             xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1237
1238             fprintf(output, "ELEM ");
1239             xmlXPathDebugDumpObject(output, object, 0);
1240             goto finish;
1241         }
1242         case XPATH_OP_VARIABLE: {
1243             const xmlChar *prefix = op->value5;
1244             const xmlChar *name = op->value4;
1245
1246             if (prefix != NULL)
1247                 fprintf(output, "VARIABLE %s:%s", prefix, name);
1248             else
1249                 fprintf(output, "VARIABLE %s", name);
1250             break;
1251         }
1252         case XPATH_OP_FUNCTION: {
1253             int nbargs = op->value;
1254             const xmlChar *prefix = op->value5;
1255             const xmlChar *name = op->value4;
1256
1257             if (prefix != NULL)
1258                 fprintf(output, "FUNCTION %s:%s(%d args)",
1259                         prefix, name, nbargs);
1260             else
1261                 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1262             break;
1263         }
1264         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1265         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1266         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1267 #ifdef LIBXML_XPTR_ENABLED
1268         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1269 #endif
1270         default:
1271         fprintf(output, "UNKNOWN %d\n", op->op); return;
1272     }
1273     fprintf(output, "\n");
1274 finish:
1275     if (op->ch1 >= 0)
1276         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1277     if (op->ch2 >= 0)
1278         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1279 }
1280
1281 /**
1282  * xmlXPathDebugDumpCompExpr:
1283  * @output:  the FILE * for the output
1284  * @comp:  the precompiled XPath expression
1285  * @depth:  the indentation level.
1286  *
1287  * Dumps the tree of the compiled XPath expression.
1288  */
1289 void
1290 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1291                           int depth) {
1292     int i;
1293     char shift[100];
1294
1295     if ((output == NULL) || (comp == NULL)) return;
1296
1297     for (i = 0;((i < depth) && (i < 25));i++)
1298         shift[2 * i] = shift[2 * i + 1] = ' ';
1299     shift[2 * i] = shift[2 * i + 1] = 0;
1300
1301     fprintf(output, "%s", shift);
1302
1303     fprintf(output, "Compiled Expression : %d elements\n",
1304             comp->nbStep);
1305     i = comp->last;
1306     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1307 }
1308
1309 #ifdef XP_DEBUG_OBJ_USAGE
1310
1311 /*
1312 * XPath object usage related debugging variables.
1313 */
1314 static int xmlXPathDebugObjCounterUndefined = 0;
1315 static int xmlXPathDebugObjCounterNodeset = 0;
1316 static int xmlXPathDebugObjCounterBool = 0;
1317 static int xmlXPathDebugObjCounterNumber = 0;
1318 static int xmlXPathDebugObjCounterString = 0;
1319 static int xmlXPathDebugObjCounterPoint = 0;
1320 static int xmlXPathDebugObjCounterRange = 0;
1321 static int xmlXPathDebugObjCounterLocset = 0;
1322 static int xmlXPathDebugObjCounterUsers = 0;
1323 static int xmlXPathDebugObjCounterXSLTTree = 0;
1324 static int xmlXPathDebugObjCounterAll = 0;
1325
1326 static int xmlXPathDebugObjTotalUndefined = 0;
1327 static int xmlXPathDebugObjTotalNodeset = 0;
1328 static int xmlXPathDebugObjTotalBool = 0;
1329 static int xmlXPathDebugObjTotalNumber = 0;
1330 static int xmlXPathDebugObjTotalString = 0;
1331 static int xmlXPathDebugObjTotalPoint = 0;
1332 static int xmlXPathDebugObjTotalRange = 0;
1333 static int xmlXPathDebugObjTotalLocset = 0;
1334 static int xmlXPathDebugObjTotalUsers = 0;
1335 static int xmlXPathDebugObjTotalXSLTTree = 0;
1336 static int xmlXPathDebugObjTotalAll = 0;
1337
1338 static int xmlXPathDebugObjMaxUndefined = 0;
1339 static int xmlXPathDebugObjMaxNodeset = 0;
1340 static int xmlXPathDebugObjMaxBool = 0;
1341 static int xmlXPathDebugObjMaxNumber = 0;
1342 static int xmlXPathDebugObjMaxString = 0;
1343 static int xmlXPathDebugObjMaxPoint = 0;
1344 static int xmlXPathDebugObjMaxRange = 0;
1345 static int xmlXPathDebugObjMaxLocset = 0;
1346 static int xmlXPathDebugObjMaxUsers = 0;
1347 static int xmlXPathDebugObjMaxXSLTTree = 0;
1348 static int xmlXPathDebugObjMaxAll = 0;
1349
1350 /* REVISIT TODO: Make this static when committing */
1351 static void
1352 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1353 {
1354     if (ctxt != NULL) {
1355         if (ctxt->cache != NULL) {
1356             xmlXPathContextCachePtr cache =
1357                 (xmlXPathContextCachePtr) ctxt->cache;
1358
1359             cache->dbgCachedAll = 0;
1360             cache->dbgCachedNodeset = 0;
1361             cache->dbgCachedString = 0;
1362             cache->dbgCachedBool = 0;
1363             cache->dbgCachedNumber = 0;
1364             cache->dbgCachedPoint = 0;
1365             cache->dbgCachedRange = 0;
1366             cache->dbgCachedLocset = 0;
1367             cache->dbgCachedUsers = 0;
1368             cache->dbgCachedXSLTTree = 0;
1369             cache->dbgCachedUndefined = 0;
1370
1371             cache->dbgReusedAll = 0;
1372             cache->dbgReusedNodeset = 0;
1373             cache->dbgReusedString = 0;
1374             cache->dbgReusedBool = 0;
1375             cache->dbgReusedNumber = 0;
1376             cache->dbgReusedPoint = 0;
1377             cache->dbgReusedRange = 0;
1378             cache->dbgReusedLocset = 0;
1379             cache->dbgReusedUsers = 0;
1380             cache->dbgReusedXSLTTree = 0;
1381             cache->dbgReusedUndefined = 0;
1382         }
1383     }
1384
1385     xmlXPathDebugObjCounterUndefined = 0;
1386     xmlXPathDebugObjCounterNodeset = 0;
1387     xmlXPathDebugObjCounterBool = 0;
1388     xmlXPathDebugObjCounterNumber = 0;
1389     xmlXPathDebugObjCounterString = 0;
1390     xmlXPathDebugObjCounterPoint = 0;
1391     xmlXPathDebugObjCounterRange = 0;
1392     xmlXPathDebugObjCounterLocset = 0;
1393     xmlXPathDebugObjCounterUsers = 0;
1394     xmlXPathDebugObjCounterXSLTTree = 0;
1395     xmlXPathDebugObjCounterAll = 0;
1396
1397     xmlXPathDebugObjTotalUndefined = 0;
1398     xmlXPathDebugObjTotalNodeset = 0;
1399     xmlXPathDebugObjTotalBool = 0;
1400     xmlXPathDebugObjTotalNumber = 0;
1401     xmlXPathDebugObjTotalString = 0;
1402     xmlXPathDebugObjTotalPoint = 0;
1403     xmlXPathDebugObjTotalRange = 0;
1404     xmlXPathDebugObjTotalLocset = 0;
1405     xmlXPathDebugObjTotalUsers = 0;
1406     xmlXPathDebugObjTotalXSLTTree = 0;
1407     xmlXPathDebugObjTotalAll = 0;
1408
1409     xmlXPathDebugObjMaxUndefined = 0;
1410     xmlXPathDebugObjMaxNodeset = 0;
1411     xmlXPathDebugObjMaxBool = 0;
1412     xmlXPathDebugObjMaxNumber = 0;
1413     xmlXPathDebugObjMaxString = 0;
1414     xmlXPathDebugObjMaxPoint = 0;
1415     xmlXPathDebugObjMaxRange = 0;
1416     xmlXPathDebugObjMaxLocset = 0;
1417     xmlXPathDebugObjMaxUsers = 0;
1418     xmlXPathDebugObjMaxXSLTTree = 0;
1419     xmlXPathDebugObjMaxAll = 0;
1420
1421 }
1422
1423 static void
1424 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1425                               xmlXPathObjectType objType)
1426 {
1427     int isCached = 0;
1428
1429     if (ctxt != NULL) {
1430         if (ctxt->cache != NULL) {
1431             xmlXPathContextCachePtr cache =
1432                 (xmlXPathContextCachePtr) ctxt->cache;
1433
1434             isCached = 1;
1435
1436             cache->dbgReusedAll++;
1437             switch (objType) {
1438                 case XPATH_UNDEFINED:
1439                     cache->dbgReusedUndefined++;
1440                     break;
1441                 case XPATH_NODESET:
1442                     cache->dbgReusedNodeset++;
1443                     break;
1444                 case XPATH_BOOLEAN:
1445                     cache->dbgReusedBool++;
1446                     break;
1447                 case XPATH_NUMBER:
1448                     cache->dbgReusedNumber++;
1449                     break;
1450                 case XPATH_STRING:
1451                     cache->dbgReusedString++;
1452                     break;
1453                 case XPATH_POINT:
1454                     cache->dbgReusedPoint++;
1455                     break;
1456                 case XPATH_RANGE:
1457                     cache->dbgReusedRange++;
1458                     break;
1459                 case XPATH_LOCATIONSET:
1460                     cache->dbgReusedLocset++;
1461                     break;
1462                 case XPATH_USERS:
1463                     cache->dbgReusedUsers++;
1464                     break;
1465                 case XPATH_XSLT_TREE:
1466                     cache->dbgReusedXSLTTree++;
1467                     break;
1468                 default:
1469                     break;
1470             }
1471         }
1472     }
1473
1474     switch (objType) {
1475         case XPATH_UNDEFINED:
1476             if (! isCached)
1477                 xmlXPathDebugObjTotalUndefined++;
1478             xmlXPathDebugObjCounterUndefined++;
1479             if (xmlXPathDebugObjCounterUndefined >
1480                 xmlXPathDebugObjMaxUndefined)
1481                 xmlXPathDebugObjMaxUndefined =
1482                     xmlXPathDebugObjCounterUndefined;
1483             break;
1484         case XPATH_NODESET:
1485             if (! isCached)
1486                 xmlXPathDebugObjTotalNodeset++;
1487             xmlXPathDebugObjCounterNodeset++;
1488             if (xmlXPathDebugObjCounterNodeset >
1489                 xmlXPathDebugObjMaxNodeset)
1490                 xmlXPathDebugObjMaxNodeset =
1491                     xmlXPathDebugObjCounterNodeset;
1492             break;
1493         case XPATH_BOOLEAN:
1494             if (! isCached)
1495                 xmlXPathDebugObjTotalBool++;
1496             xmlXPathDebugObjCounterBool++;
1497             if (xmlXPathDebugObjCounterBool >
1498                 xmlXPathDebugObjMaxBool)
1499                 xmlXPathDebugObjMaxBool =
1500                     xmlXPathDebugObjCounterBool;
1501             break;
1502         case XPATH_NUMBER:
1503             if (! isCached)
1504                 xmlXPathDebugObjTotalNumber++;
1505             xmlXPathDebugObjCounterNumber++;
1506             if (xmlXPathDebugObjCounterNumber >
1507                 xmlXPathDebugObjMaxNumber)
1508                 xmlXPathDebugObjMaxNumber =
1509                     xmlXPathDebugObjCounterNumber;
1510             break;
1511         case XPATH_STRING:
1512             if (! isCached)
1513                 xmlXPathDebugObjTotalString++;
1514             xmlXPathDebugObjCounterString++;
1515             if (xmlXPathDebugObjCounterString >
1516                 xmlXPathDebugObjMaxString)
1517                 xmlXPathDebugObjMaxString =
1518                     xmlXPathDebugObjCounterString;
1519             break;
1520         case XPATH_POINT:
1521             if (! isCached)
1522                 xmlXPathDebugObjTotalPoint++;
1523             xmlXPathDebugObjCounterPoint++;
1524             if (xmlXPathDebugObjCounterPoint >
1525                 xmlXPathDebugObjMaxPoint)
1526                 xmlXPathDebugObjMaxPoint =
1527                     xmlXPathDebugObjCounterPoint;
1528             break;
1529         case XPATH_RANGE:
1530             if (! isCached)
1531                 xmlXPathDebugObjTotalRange++;
1532             xmlXPathDebugObjCounterRange++;
1533             if (xmlXPathDebugObjCounterRange >
1534                 xmlXPathDebugObjMaxRange)
1535                 xmlXPathDebugObjMaxRange =
1536                     xmlXPathDebugObjCounterRange;
1537             break;
1538         case XPATH_LOCATIONSET:
1539             if (! isCached)
1540                 xmlXPathDebugObjTotalLocset++;
1541             xmlXPathDebugObjCounterLocset++;
1542             if (xmlXPathDebugObjCounterLocset >
1543                 xmlXPathDebugObjMaxLocset)
1544                 xmlXPathDebugObjMaxLocset =
1545                     xmlXPathDebugObjCounterLocset;
1546             break;
1547         case XPATH_USERS:
1548             if (! isCached)
1549                 xmlXPathDebugObjTotalUsers++;
1550             xmlXPathDebugObjCounterUsers++;
1551             if (xmlXPathDebugObjCounterUsers >
1552                 xmlXPathDebugObjMaxUsers)
1553                 xmlXPathDebugObjMaxUsers =
1554                     xmlXPathDebugObjCounterUsers;
1555             break;
1556         case XPATH_XSLT_TREE:
1557             if (! isCached)
1558                 xmlXPathDebugObjTotalXSLTTree++;
1559             xmlXPathDebugObjCounterXSLTTree++;
1560             if (xmlXPathDebugObjCounterXSLTTree >
1561                 xmlXPathDebugObjMaxXSLTTree)
1562                 xmlXPathDebugObjMaxXSLTTree =
1563                     xmlXPathDebugObjCounterXSLTTree;
1564             break;
1565         default:
1566             break;
1567     }
1568     if (! isCached)
1569         xmlXPathDebugObjTotalAll++;
1570     xmlXPathDebugObjCounterAll++;
1571     if (xmlXPathDebugObjCounterAll >
1572         xmlXPathDebugObjMaxAll)
1573         xmlXPathDebugObjMaxAll =
1574             xmlXPathDebugObjCounterAll;
1575 }
1576
1577 static void
1578 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1579                               xmlXPathObjectType objType)
1580 {
1581     int isCached = 0;
1582
1583     if (ctxt != NULL) {
1584         if (ctxt->cache != NULL) {
1585             xmlXPathContextCachePtr cache =
1586                 (xmlXPathContextCachePtr) ctxt->cache;
1587
1588             isCached = 1;
1589
1590             cache->dbgCachedAll++;
1591             switch (objType) {
1592                 case XPATH_UNDEFINED:
1593                     cache->dbgCachedUndefined++;
1594                     break;
1595                 case XPATH_NODESET:
1596                     cache->dbgCachedNodeset++;
1597                     break;
1598                 case XPATH_BOOLEAN:
1599                     cache->dbgCachedBool++;
1600                     break;
1601                 case XPATH_NUMBER:
1602                     cache->dbgCachedNumber++;
1603                     break;
1604                 case XPATH_STRING:
1605                     cache->dbgCachedString++;
1606                     break;
1607                 case XPATH_POINT:
1608                     cache->dbgCachedPoint++;
1609                     break;
1610                 case XPATH_RANGE:
1611                     cache->dbgCachedRange++;
1612                     break;
1613                 case XPATH_LOCATIONSET:
1614                     cache->dbgCachedLocset++;
1615                     break;
1616                 case XPATH_USERS:
1617                     cache->dbgCachedUsers++;
1618                     break;
1619                 case XPATH_XSLT_TREE:
1620                     cache->dbgCachedXSLTTree++;
1621                     break;
1622                 default:
1623                     break;
1624             }
1625
1626         }
1627     }
1628     switch (objType) {
1629         case XPATH_UNDEFINED:
1630             xmlXPathDebugObjCounterUndefined--;
1631             break;
1632         case XPATH_NODESET:
1633             xmlXPathDebugObjCounterNodeset--;
1634             break;
1635         case XPATH_BOOLEAN:
1636             xmlXPathDebugObjCounterBool--;
1637             break;
1638         case XPATH_NUMBER:
1639             xmlXPathDebugObjCounterNumber--;
1640             break;
1641         case XPATH_STRING:
1642             xmlXPathDebugObjCounterString--;
1643             break;
1644         case XPATH_POINT:
1645             xmlXPathDebugObjCounterPoint--;
1646             break;
1647         case XPATH_RANGE:
1648             xmlXPathDebugObjCounterRange--;
1649             break;
1650         case XPATH_LOCATIONSET:
1651             xmlXPathDebugObjCounterLocset--;
1652             break;
1653         case XPATH_USERS:
1654             xmlXPathDebugObjCounterUsers--;
1655             break;
1656         case XPATH_XSLT_TREE:
1657             xmlXPathDebugObjCounterXSLTTree--;
1658             break;
1659         default:
1660             break;
1661     }
1662     xmlXPathDebugObjCounterAll--;
1663 }
1664
1665 /* REVISIT TODO: Make this static when committing */
1666 static void
1667 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1668 {
1669     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1670         reqXSLTTree, reqUndefined;
1671     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1672         caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1673     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1674         reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1675     int leftObjs = xmlXPathDebugObjCounterAll;
1676
1677     reqAll = xmlXPathDebugObjTotalAll;
1678     reqNodeset = xmlXPathDebugObjTotalNodeset;
1679     reqString = xmlXPathDebugObjTotalString;
1680     reqBool = xmlXPathDebugObjTotalBool;
1681     reqNumber = xmlXPathDebugObjTotalNumber;
1682     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1683     reqUndefined = xmlXPathDebugObjTotalUndefined;
1684
1685     printf("# XPath object usage:\n");
1686
1687     if (ctxt != NULL) {
1688         if (ctxt->cache != NULL) {
1689             xmlXPathContextCachePtr cache =
1690                 (xmlXPathContextCachePtr) ctxt->cache;
1691
1692             reAll = cache->dbgReusedAll;
1693             reqAll += reAll;
1694             reNodeset = cache->dbgReusedNodeset;
1695             reqNodeset += reNodeset;
1696             reString = cache->dbgReusedString;
1697             reqString += reString;
1698             reBool = cache->dbgReusedBool;
1699             reqBool += reBool;
1700             reNumber = cache->dbgReusedNumber;
1701             reqNumber += reNumber;
1702             reXSLTTree = cache->dbgReusedXSLTTree;
1703             reqXSLTTree += reXSLTTree;
1704             reUndefined = cache->dbgReusedUndefined;
1705             reqUndefined += reUndefined;
1706
1707             caAll = cache->dbgCachedAll;
1708             caBool = cache->dbgCachedBool;
1709             caNodeset = cache->dbgCachedNodeset;
1710             caString = cache->dbgCachedString;
1711             caNumber = cache->dbgCachedNumber;
1712             caXSLTTree = cache->dbgCachedXSLTTree;
1713             caUndefined = cache->dbgCachedUndefined;
1714
1715             if (cache->nodesetObjs)
1716                 leftObjs -= cache->nodesetObjs->number;
1717             if (cache->stringObjs)
1718                 leftObjs -= cache->stringObjs->number;
1719             if (cache->booleanObjs)
1720                 leftObjs -= cache->booleanObjs->number;
1721             if (cache->numberObjs)
1722                 leftObjs -= cache->numberObjs->number;
1723             if (cache->miscObjs)
1724                 leftObjs -= cache->miscObjs->number;
1725         }
1726     }
1727
1728     printf("# all\n");
1729     printf("#   total  : %d\n", reqAll);
1730     printf("#   left  : %d\n", leftObjs);
1731     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
1732     printf("#   reused : %d\n", reAll);
1733     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
1734
1735     printf("# node-sets\n");
1736     printf("#   total  : %d\n", reqNodeset);
1737     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
1738     printf("#   reused : %d\n", reNodeset);
1739     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
1740
1741     printf("# strings\n");
1742     printf("#   total  : %d\n", reqString);
1743     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
1744     printf("#   reused : %d\n", reString);
1745     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
1746
1747     printf("# booleans\n");
1748     printf("#   total  : %d\n", reqBool);
1749     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
1750     printf("#   reused : %d\n", reBool);
1751     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
1752
1753     printf("# numbers\n");
1754     printf("#   total  : %d\n", reqNumber);
1755     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
1756     printf("#   reused : %d\n", reNumber);
1757     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
1758
1759     printf("# XSLT result tree fragments\n");
1760     printf("#   total  : %d\n", reqXSLTTree);
1761     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1762     printf("#   reused : %d\n", reXSLTTree);
1763     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
1764
1765     printf("# undefined\n");
1766     printf("#   total  : %d\n", reqUndefined);
1767     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
1768     printf("#   reused : %d\n", reUndefined);
1769     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
1770
1771 }
1772
1773 #endif /* XP_DEBUG_OBJ_USAGE */
1774
1775 #endif /* LIBXML_DEBUG_ENABLED */
1776
1777 /************************************************************************
1778  *                                                                      *
1779  *                      XPath object caching                            *
1780  *                                                                      *
1781  ************************************************************************/
1782
1783 /**
1784  * xmlXPathNewCache:
1785  *
1786  * Create a new object cache
1787  *
1788  * Returns the xmlXPathCache just allocated.
1789  */
1790 static xmlXPathContextCachePtr
1791 xmlXPathNewCache(void)
1792 {
1793     xmlXPathContextCachePtr ret;
1794
1795     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1796     if (ret == NULL) {
1797         xmlXPathErrMemory(NULL, "creating object cache\n");
1798         return(NULL);
1799     }
1800     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1801     ret->maxNodeset = 100;
1802     ret->maxString = 100;
1803     ret->maxBoolean = 100;
1804     ret->maxNumber = 100;
1805     ret->maxMisc = 100;
1806     return(ret);
1807 }
1808
1809 static void
1810 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1811 {
1812     int i;
1813     xmlXPathObjectPtr obj;
1814
1815     if (list == NULL)
1816         return;
1817
1818     for (i = 0; i < list->number; i++) {
1819         obj = list->items[i];
1820         /*
1821         * Note that it is already assured that we don't need to
1822         * look out for namespace nodes in the node-set.
1823         */
1824         if (obj->nodesetval != NULL) {
1825             if (obj->nodesetval->nodeTab != NULL)
1826                 xmlFree(obj->nodesetval->nodeTab);
1827             xmlFree(obj->nodesetval);
1828         }
1829         xmlFree(obj);
1830 #ifdef XP_DEBUG_OBJ_USAGE
1831         xmlXPathDebugObjCounterAll--;
1832 #endif
1833     }
1834     xmlPointerListFree(list);
1835 }
1836
1837 static void
1838 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1839 {
1840     if (cache == NULL)
1841         return;
1842     if (cache->nodesetObjs)
1843         xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1844     if (cache->stringObjs)
1845         xmlXPathCacheFreeObjectList(cache->stringObjs);
1846     if (cache->booleanObjs)
1847         xmlXPathCacheFreeObjectList(cache->booleanObjs);
1848     if (cache->numberObjs)
1849         xmlXPathCacheFreeObjectList(cache->numberObjs);
1850     if (cache->miscObjs)
1851         xmlXPathCacheFreeObjectList(cache->miscObjs);
1852     xmlFree(cache);
1853 }
1854
1855 /**
1856  * xmlXPathContextSetCache:
1857  *
1858  * @ctxt:  the XPath context
1859  * @active: enables/disables (creates/frees) the cache
1860  * @value: a value with semantics dependant on @options
1861  * @options: options (currently only the value 0 is used)
1862  *
1863  * Creates/frees an object cache on the XPath context.
1864  * If activates XPath objects (xmlXPathObject) will be cached internally
1865  * to be reused.
1866  * @options:
1867  *   0: This will set the XPath object caching:
1868  *      @value:
1869  *        This will set the maximum number of XPath objects
1870  *        to be cached per slot
1871  *        There are 5 slots for: node-set, string, number, boolean, and
1872  *        misc objects. Use <0 for the default number (100).
1873  *   Other values for @options have currently no effect.
1874  *
1875  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1876  */
1877 int
1878 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1879                         int active,
1880                         int value,
1881                         int options)
1882 {
1883     if (ctxt == NULL)
1884         return(-1);
1885     if (active) {
1886         xmlXPathContextCachePtr cache;
1887
1888         if (ctxt->cache == NULL) {
1889             ctxt->cache = xmlXPathNewCache();
1890             if (ctxt->cache == NULL)
1891                 return(-1);
1892         }
1893         cache = (xmlXPathContextCachePtr) ctxt->cache;
1894         if (options == 0) {
1895             if (value < 0)
1896                 value = 100;
1897             cache->maxNodeset = value;
1898             cache->maxString = value;
1899             cache->maxNumber = value;
1900             cache->maxBoolean = value;
1901             cache->maxMisc = value;
1902         }
1903     } else if (ctxt->cache != NULL) {
1904         xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1905         ctxt->cache = NULL;
1906     }
1907     return(0);
1908 }
1909
1910 /**
1911  * xmlXPathCacheWrapNodeSet:
1912  * @ctxt: the XPath context
1913  * @val:  the NodePtr value
1914  *
1915  * This is the cached version of xmlXPathWrapNodeSet().
1916  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1917  *
1918  * Returns the created or reused object.
1919  */
1920 static xmlXPathObjectPtr
1921 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1922 {
1923     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1924         xmlXPathContextCachePtr cache =
1925             (xmlXPathContextCachePtr) ctxt->cache;
1926
1927         if ((cache->miscObjs != NULL) &&
1928             (cache->miscObjs->number != 0))
1929         {
1930             xmlXPathObjectPtr ret;
1931
1932             ret = (xmlXPathObjectPtr)
1933                 cache->miscObjs->items[--cache->miscObjs->number];
1934             ret->type = XPATH_NODESET;
1935             ret->nodesetval = val;
1936 #ifdef XP_DEBUG_OBJ_USAGE
1937             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1938 #endif
1939             return(ret);
1940         }
1941     }
1942
1943     return(xmlXPathWrapNodeSet(val));
1944
1945 }
1946
1947 /**
1948  * xmlXPathCacheWrapString:
1949  * @ctxt: the XPath context
1950  * @val:  the xmlChar * value
1951  *
1952  * This is the cached version of xmlXPathWrapString().
1953  * Wraps the @val string into an XPath object.
1954  *
1955  * Returns the created or reused object.
1956  */
1957 static xmlXPathObjectPtr
1958 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1959 {
1960     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1961         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1962
1963         if ((cache->stringObjs != NULL) &&
1964             (cache->stringObjs->number != 0))
1965         {
1966
1967             xmlXPathObjectPtr ret;
1968
1969             ret = (xmlXPathObjectPtr)
1970                 cache->stringObjs->items[--cache->stringObjs->number];
1971             ret->type = XPATH_STRING;
1972             ret->stringval = val;
1973 #ifdef XP_DEBUG_OBJ_USAGE
1974             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1975 #endif
1976             return(ret);
1977         } else if ((cache->miscObjs != NULL) &&
1978             (cache->miscObjs->number != 0))
1979         {
1980             xmlXPathObjectPtr ret;
1981             /*
1982             * Fallback to misc-cache.
1983             */
1984             ret = (xmlXPathObjectPtr)
1985                 cache->miscObjs->items[--cache->miscObjs->number];
1986
1987             ret->type = XPATH_STRING;
1988             ret->stringval = val;
1989 #ifdef XP_DEBUG_OBJ_USAGE
1990             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1991 #endif
1992             return(ret);
1993         }
1994     }
1995     return(xmlXPathWrapString(val));
1996 }
1997
1998 /**
1999  * xmlXPathCacheNewNodeSet:
2000  * @ctxt: the XPath context
2001  * @val:  the NodePtr value
2002  *
2003  * This is the cached version of xmlXPathNewNodeSet().
2004  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2005  * it with the single Node @val
2006  *
2007  * Returns the created or reused object.
2008  */
2009 static xmlXPathObjectPtr
2010 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2011 {
2012     if ((ctxt != NULL) && (ctxt->cache)) {
2013         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2014
2015         if ((cache->nodesetObjs != NULL) &&
2016             (cache->nodesetObjs->number != 0))
2017         {
2018             xmlXPathObjectPtr ret;
2019             /*
2020             * Use the nodset-cache.
2021             */
2022             ret = (xmlXPathObjectPtr)
2023                 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2024             ret->type = XPATH_NODESET;
2025             ret->boolval = 0;
2026             if (val) {
2027                 if ((ret->nodesetval->nodeMax == 0) ||
2028                     (val->type == XML_NAMESPACE_DECL))
2029                 {
2030                     xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2031                 } else {
2032                     ret->nodesetval->nodeTab[0] = val;
2033                     ret->nodesetval->nodeNr = 1;
2034                 }
2035             }
2036 #ifdef XP_DEBUG_OBJ_USAGE
2037             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2038 #endif
2039             return(ret);
2040         } else if ((cache->miscObjs != NULL) &&
2041             (cache->miscObjs->number != 0))
2042         {
2043             xmlXPathObjectPtr ret;
2044             /*
2045             * Fallback to misc-cache.
2046             */
2047
2048             ret = (xmlXPathObjectPtr)
2049                 cache->miscObjs->items[--cache->miscObjs->number];
2050
2051             ret->type = XPATH_NODESET;
2052             ret->boolval = 0;
2053             ret->nodesetval = xmlXPathNodeSetCreate(val);
2054 #ifdef XP_DEBUG_OBJ_USAGE
2055             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2056 #endif
2057             return(ret);
2058         }
2059     }
2060     return(xmlXPathNewNodeSet(val));
2061 }
2062
2063 /**
2064  * xmlXPathCacheNewCString:
2065  * @ctxt: the XPath context
2066  * @val:  the char * value
2067  *
2068  * This is the cached version of xmlXPathNewCString().
2069  * Acquire an xmlXPathObjectPtr of type string and of value @val
2070  *
2071  * Returns the created or reused object.
2072  */
2073 static xmlXPathObjectPtr
2074 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2075 {
2076     if ((ctxt != NULL) && (ctxt->cache)) {
2077         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2078
2079         if ((cache->stringObjs != NULL) &&
2080             (cache->stringObjs->number != 0))
2081         {
2082             xmlXPathObjectPtr ret;
2083
2084             ret = (xmlXPathObjectPtr)
2085                 cache->stringObjs->items[--cache->stringObjs->number];
2086
2087             ret->type = XPATH_STRING;
2088             ret->stringval = xmlStrdup(BAD_CAST val);
2089 #ifdef XP_DEBUG_OBJ_USAGE
2090             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2091 #endif
2092             return(ret);
2093         } else if ((cache->miscObjs != NULL) &&
2094             (cache->miscObjs->number != 0))
2095         {
2096             xmlXPathObjectPtr ret;
2097
2098             ret = (xmlXPathObjectPtr)
2099                 cache->miscObjs->items[--cache->miscObjs->number];
2100
2101             ret->type = XPATH_STRING;
2102             ret->stringval = xmlStrdup(BAD_CAST val);
2103 #ifdef XP_DEBUG_OBJ_USAGE
2104             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2105 #endif
2106             return(ret);
2107         }
2108     }
2109     return(xmlXPathNewCString(val));
2110 }
2111
2112 /**
2113  * xmlXPathCacheNewString:
2114  * @ctxt: the XPath context
2115  * @val:  the xmlChar * value
2116  *
2117  * This is the cached version of xmlXPathNewString().
2118  * Acquire an xmlXPathObjectPtr of type string and of value @val
2119  *
2120  * Returns the created or reused object.
2121  */
2122 static xmlXPathObjectPtr
2123 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2124 {
2125     if ((ctxt != NULL) && (ctxt->cache)) {
2126         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2127
2128         if ((cache->stringObjs != NULL) &&
2129             (cache->stringObjs->number != 0))
2130         {
2131             xmlXPathObjectPtr ret;
2132
2133             ret = (xmlXPathObjectPtr)
2134                 cache->stringObjs->items[--cache->stringObjs->number];
2135             ret->type = XPATH_STRING;
2136             if (val != NULL)
2137                 ret->stringval = xmlStrdup(val);
2138             else
2139                 ret->stringval = xmlStrdup((const xmlChar *)"");
2140 #ifdef XP_DEBUG_OBJ_USAGE
2141             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2142 #endif
2143             return(ret);
2144         } else if ((cache->miscObjs != NULL) &&
2145             (cache->miscObjs->number != 0))
2146         {
2147             xmlXPathObjectPtr ret;
2148
2149             ret = (xmlXPathObjectPtr)
2150                 cache->miscObjs->items[--cache->miscObjs->number];
2151
2152             ret->type = XPATH_STRING;
2153             if (val != NULL)
2154                 ret->stringval = xmlStrdup(val);
2155             else
2156                 ret->stringval = xmlStrdup((const xmlChar *)"");
2157 #ifdef XP_DEBUG_OBJ_USAGE
2158             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2159 #endif
2160             return(ret);
2161         }
2162     }
2163     return(xmlXPathNewString(val));
2164 }
2165
2166 /**
2167  * xmlXPathCacheNewBoolean:
2168  * @ctxt: the XPath context
2169  * @val:  the boolean value
2170  *
2171  * This is the cached version of xmlXPathNewBoolean().
2172  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2173  *
2174  * Returns the created or reused object.
2175  */
2176 static xmlXPathObjectPtr
2177 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2178 {
2179     if ((ctxt != NULL) && (ctxt->cache)) {
2180         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2181
2182         if ((cache->booleanObjs != NULL) &&
2183             (cache->booleanObjs->number != 0))
2184         {
2185             xmlXPathObjectPtr ret;
2186
2187             ret = (xmlXPathObjectPtr)
2188                 cache->booleanObjs->items[--cache->booleanObjs->number];
2189             ret->type = XPATH_BOOLEAN;
2190             ret->boolval = (val != 0);
2191 #ifdef XP_DEBUG_OBJ_USAGE
2192             xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2193 #endif
2194             return(ret);
2195         } else if ((cache->miscObjs != NULL) &&
2196             (cache->miscObjs->number != 0))
2197         {
2198             xmlXPathObjectPtr ret;
2199
2200             ret = (xmlXPathObjectPtr)
2201                 cache->miscObjs->items[--cache->miscObjs->number];
2202
2203             ret->type = XPATH_BOOLEAN;
2204             ret->boolval = (val != 0);
2205 #ifdef XP_DEBUG_OBJ_USAGE
2206             xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2207 #endif
2208             return(ret);
2209         }
2210     }
2211     return(xmlXPathNewBoolean(val));
2212 }
2213
2214 /**
2215  * xmlXPathCacheNewFloat:
2216  * @ctxt: the XPath context
2217  * @val:  the double value
2218  *
2219  * This is the cached version of xmlXPathNewFloat().
2220  * Acquires an xmlXPathObjectPtr of type double and of value @val
2221  *
2222  * Returns the created or reused object.
2223  */
2224 static xmlXPathObjectPtr
2225 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2226 {
2227      if ((ctxt != NULL) && (ctxt->cache)) {
2228         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2229
2230         if ((cache->numberObjs != NULL) &&
2231             (cache->numberObjs->number != 0))
2232         {
2233             xmlXPathObjectPtr ret;
2234
2235             ret = (xmlXPathObjectPtr)
2236                 cache->numberObjs->items[--cache->numberObjs->number];
2237             ret->type = XPATH_NUMBER;
2238             ret->floatval = val;
2239 #ifdef XP_DEBUG_OBJ_USAGE
2240             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2241 #endif
2242             return(ret);
2243         } else if ((cache->miscObjs != NULL) &&
2244             (cache->miscObjs->number != 0))
2245         {
2246             xmlXPathObjectPtr ret;
2247
2248             ret = (xmlXPathObjectPtr)
2249                 cache->miscObjs->items[--cache->miscObjs->number];
2250
2251             ret->type = XPATH_NUMBER;
2252             ret->floatval = val;
2253 #ifdef XP_DEBUG_OBJ_USAGE
2254             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2255 #endif
2256             return(ret);
2257         }
2258     }
2259     return(xmlXPathNewFloat(val));
2260 }
2261
2262 /**
2263  * xmlXPathCacheConvertString:
2264  * @ctxt: the XPath context
2265  * @val:  an XPath object
2266  *
2267  * This is the cached version of xmlXPathConvertString().
2268  * Converts an existing object to its string() equivalent
2269  *
2270  * Returns a created or reused object, the old one is freed (cached)
2271  *         (or the operation is done directly on @val)
2272  */
2273
2274 static xmlXPathObjectPtr
2275 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2276     xmlChar *res = NULL;
2277
2278     if (val == NULL)
2279         return(xmlXPathCacheNewCString(ctxt, ""));
2280
2281     switch (val->type) {
2282     case XPATH_UNDEFINED:
2283 #ifdef DEBUG_EXPR
2284         xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2285 #endif
2286         break;
2287     case XPATH_NODESET:
2288     case XPATH_XSLT_TREE:
2289         res = xmlXPathCastNodeSetToString(val->nodesetval);
2290         break;
2291     case XPATH_STRING:
2292         return(val);
2293     case XPATH_BOOLEAN:
2294         res = xmlXPathCastBooleanToString(val->boolval);
2295         break;
2296     case XPATH_NUMBER:
2297         res = xmlXPathCastNumberToString(val->floatval);
2298         break;
2299     case XPATH_USERS:
2300     case XPATH_POINT:
2301     case XPATH_RANGE:
2302     case XPATH_LOCATIONSET:
2303         TODO;
2304         break;
2305     }
2306     xmlXPathReleaseObject(ctxt, val);
2307     if (res == NULL)
2308         return(xmlXPathCacheNewCString(ctxt, ""));
2309     return(xmlXPathCacheWrapString(ctxt, res));
2310 }
2311
2312 /**
2313  * xmlXPathCacheObjectCopy:
2314  * @ctxt: the XPath context
2315  * @val:  the original object
2316  *
2317  * This is the cached version of xmlXPathObjectCopy().
2318  * Acquire a copy of a given object
2319  *
2320  * Returns a created or reused created object.
2321  */
2322 static xmlXPathObjectPtr
2323 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2324 {
2325     if (val == NULL)
2326         return(NULL);
2327
2328     if (XP_HAS_CACHE(ctxt)) {
2329         switch (val->type) {
2330             case XPATH_NODESET:
2331                 return(xmlXPathCacheWrapNodeSet(ctxt,
2332                     xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2333             case XPATH_STRING:
2334                 return(xmlXPathCacheNewString(ctxt, val->stringval));
2335             case XPATH_BOOLEAN:
2336                 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2337             case XPATH_NUMBER:
2338                 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2339             default:
2340                 break;
2341         }
2342     }
2343     return(xmlXPathObjectCopy(val));
2344 }
2345
2346 /**
2347  * xmlXPathCacheConvertBoolean:
2348  * @ctxt: the XPath context
2349  * @val:  an XPath object
2350  *
2351  * This is the cached version of xmlXPathConvertBoolean().
2352  * Converts an existing object to its boolean() equivalent
2353  *
2354  * Returns a created or reused object, the old one is freed (or the operation
2355  *         is done directly on @val)
2356  */
2357 static xmlXPathObjectPtr
2358 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2359     xmlXPathObjectPtr ret;
2360
2361     if (val == NULL)
2362         return(xmlXPathCacheNewBoolean(ctxt, 0));
2363     if (val->type == XPATH_BOOLEAN)
2364         return(val);
2365     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2366     xmlXPathReleaseObject(ctxt, val);
2367     return(ret);
2368 }
2369
2370 /**
2371  * xmlXPathCacheConvertNumber:
2372  * @ctxt: the XPath context
2373  * @val:  an XPath object
2374  *
2375  * This is the cached version of xmlXPathConvertNumber().
2376  * Converts an existing object to its number() equivalent
2377  *
2378  * Returns a created or reused object, the old one is freed (or the operation
2379  *         is done directly on @val)
2380  */
2381 static xmlXPathObjectPtr
2382 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2383     xmlXPathObjectPtr ret;
2384
2385     if (val == NULL)
2386         return(xmlXPathCacheNewFloat(ctxt, 0.0));
2387     if (val->type == XPATH_NUMBER)
2388         return(val);
2389     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2390     xmlXPathReleaseObject(ctxt, val);
2391     return(ret);
2392 }
2393
2394 /************************************************************************
2395  *                                                                      *
2396  *              Parser stacks related functions and macros              *
2397  *                                                                      *
2398  ************************************************************************/
2399
2400 /**
2401  * valuePop:
2402  * @ctxt: an XPath evaluation context
2403  *
2404  * Pops the top XPath object from the value stack
2405  *
2406  * Returns the XPath object just removed
2407  */
2408 xmlXPathObjectPtr
2409 valuePop(xmlXPathParserContextPtr ctxt)
2410 {
2411     xmlXPathObjectPtr ret;
2412
2413     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2414         return (NULL);
2415     ctxt->valueNr--;
2416     if (ctxt->valueNr > 0)
2417         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2418     else
2419         ctxt->value = NULL;
2420     ret = ctxt->valueTab[ctxt->valueNr];
2421     ctxt->valueTab[ctxt->valueNr] = NULL;
2422     return (ret);
2423 }
2424 /**
2425  * valuePush:
2426  * @ctxt:  an XPath evaluation context
2427  * @value:  the XPath object
2428  *
2429  * Pushes a new XPath object on top of the value stack
2430  *
2431  * returns the number of items on the value stack
2432  */
2433 int
2434 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2435 {
2436     if ((ctxt == NULL) || (value == NULL)) return(-1);
2437     if (ctxt->valueNr >= ctxt->valueMax) {
2438         xmlXPathObjectPtr *tmp;
2439
2440         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2441                                              2 * ctxt->valueMax *
2442                                              sizeof(ctxt->valueTab[0]));
2443         if (tmp == NULL) {
2444             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2445             return (0);
2446         }
2447         ctxt->valueMax *= 2;
2448         ctxt->valueTab = tmp;
2449     }
2450     ctxt->valueTab[ctxt->valueNr] = value;
2451     ctxt->value = value;
2452     return (ctxt->valueNr++);
2453 }
2454
2455 /**
2456  * xmlXPathPopBoolean:
2457  * @ctxt:  an XPath parser context
2458  *
2459  * Pops a boolean from the stack, handling conversion if needed.
2460  * Check error with #xmlXPathCheckError.
2461  *
2462  * Returns the boolean
2463  */
2464 int
2465 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2466     xmlXPathObjectPtr obj;
2467     int ret;
2468
2469     obj = valuePop(ctxt);
2470     if (obj == NULL) {
2471         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2472         return(0);
2473     }
2474     if (obj->type != XPATH_BOOLEAN)
2475         ret = xmlXPathCastToBoolean(obj);
2476     else
2477         ret = obj->boolval;
2478     xmlXPathReleaseObject(ctxt->context, obj);
2479     return(ret);
2480 }
2481
2482 /**
2483  * xmlXPathPopNumber:
2484  * @ctxt:  an XPath parser context
2485  *
2486  * Pops a number from the stack, handling conversion if needed.
2487  * Check error with #xmlXPathCheckError.
2488  *
2489  * Returns the number
2490  */
2491 double
2492 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2493     xmlXPathObjectPtr obj;
2494     double ret;
2495
2496     obj = valuePop(ctxt);
2497     if (obj == NULL) {
2498         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2499         return(0);
2500     }
2501     if (obj->type != XPATH_NUMBER)
2502         ret = xmlXPathCastToNumber(obj);
2503     else
2504         ret = obj->floatval;
2505     xmlXPathReleaseObject(ctxt->context, obj);
2506     return(ret);
2507 }
2508
2509 /**
2510  * xmlXPathPopString:
2511  * @ctxt:  an XPath parser context
2512  *
2513  * Pops a string from the stack, handling conversion if needed.
2514  * Check error with #xmlXPathCheckError.
2515  *
2516  * Returns the string
2517  */
2518 xmlChar *
2519 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2520     xmlXPathObjectPtr obj;
2521     xmlChar * ret;
2522
2523     obj = valuePop(ctxt);
2524     if (obj == NULL) {
2525         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2526         return(NULL);
2527     }
2528     ret = xmlXPathCastToString(obj);    /* this does required strdup */
2529     /* TODO: needs refactoring somewhere else */
2530     if (obj->stringval == ret)
2531         obj->stringval = NULL;
2532     xmlXPathReleaseObject(ctxt->context, obj);
2533     return(ret);
2534 }
2535
2536 /**
2537  * xmlXPathPopNodeSet:
2538  * @ctxt:  an XPath parser context
2539  *
2540  * Pops a node-set from the stack, handling conversion if needed.
2541  * Check error with #xmlXPathCheckError.
2542  *
2543  * Returns the node-set
2544  */
2545 xmlNodeSetPtr
2546 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2547     xmlXPathObjectPtr obj;
2548     xmlNodeSetPtr ret;
2549
2550     if (ctxt == NULL) return(NULL);
2551     if (ctxt->value == NULL) {
2552         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2553         return(NULL);
2554     }
2555     if (!xmlXPathStackIsNodeSet(ctxt)) {
2556         xmlXPathSetTypeError(ctxt);
2557         return(NULL);
2558     }
2559     obj = valuePop(ctxt);
2560     ret = obj->nodesetval;
2561 #if 0
2562     /* to fix memory leak of not clearing obj->user */
2563     if (obj->boolval && obj->user != NULL)
2564         xmlFreeNodeList((xmlNodePtr) obj->user);
2565 #endif
2566     obj->nodesetval = NULL;
2567     xmlXPathReleaseObject(ctxt->context, obj);
2568     return(ret);
2569 }
2570
2571 /**
2572  * xmlXPathPopExternal:
2573  * @ctxt:  an XPath parser context
2574  *
2575  * Pops an external object from the stack, handling conversion if needed.
2576  * Check error with #xmlXPathCheckError.
2577  *
2578  * Returns the object
2579  */
2580 void *
2581 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2582     xmlXPathObjectPtr obj;
2583     void * ret;
2584
2585     if ((ctxt == NULL) || (ctxt->value == NULL)) {
2586         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2587         return(NULL);
2588     }
2589     if (ctxt->value->type != XPATH_USERS) {
2590         xmlXPathSetTypeError(ctxt);
2591         return(NULL);
2592     }
2593     obj = valuePop(ctxt);
2594     ret = obj->user;
2595     obj->user = NULL;
2596     xmlXPathReleaseObject(ctxt->context, obj);
2597     return(ret);
2598 }
2599
2600 /*
2601  * Macros for accessing the content. Those should be used only by the parser,
2602  * and not exported.
2603  *
2604  * Dirty macros, i.e. one need to make assumption on the context to use them
2605  *
2606  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2607  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2608  *           in ISO-Latin or UTF-8.
2609  *           This should be used internally by the parser
2610  *           only to compare to ASCII values otherwise it would break when
2611  *           running with UTF-8 encoding.
2612  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2613  *           to compare on ASCII based substring.
2614  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2615  *           strings within the parser.
2616  *   CURRENT Returns the current char value, with the full decoding of
2617  *           UTF-8 if we are using this mode. It returns an int.
2618  *   NEXT    Skip to the next character, this does the proper decoding
2619  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2620  *           It returns the pointer to the current xmlChar.
2621  */
2622
2623 #define CUR (*ctxt->cur)
2624 #define SKIP(val) ctxt->cur += (val)
2625 #define NXT(val) ctxt->cur[(val)]
2626 #define CUR_PTR ctxt->cur
2627 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2628
2629 #define COPY_BUF(l,b,i,v)                                              \
2630     if (l == 1) b[i++] = (xmlChar) v;                                  \
2631     else i += xmlCopyChar(l,&b[i],v)
2632
2633 #define NEXTL(l)  ctxt->cur += l
2634
2635 #define SKIP_BLANKS                                                     \
2636     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2637
2638 #define CURRENT (*ctxt->cur)
2639 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2640
2641
2642 #ifndef DBL_DIG
2643 #define DBL_DIG 16
2644 #endif
2645 #ifndef DBL_EPSILON
2646 #define DBL_EPSILON 1E-9
2647 #endif
2648
2649 #define UPPER_DOUBLE 1E9
2650 #define LOWER_DOUBLE 1E-5
2651 #define LOWER_DOUBLE_EXP 5
2652
2653 #define INTEGER_DIGITS DBL_DIG
2654 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2655 #define EXPONENT_DIGITS (3 + 2)
2656
2657 /**
2658  * xmlXPathFormatNumber:
2659  * @number:     number to format
2660  * @buffer:     output buffer
2661  * @buffersize: size of output buffer
2662  *
2663  * Convert the number into a string representation.
2664  */
2665 static void
2666 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2667 {
2668     switch (xmlXPathIsInf(number)) {
2669     case 1:
2670         if (buffersize > (int)sizeof("Infinity"))
2671             snprintf(buffer, buffersize, "Infinity");
2672         break;
2673     case -1:
2674         if (buffersize > (int)sizeof("-Infinity"))
2675             snprintf(buffer, buffersize, "-Infinity");
2676         break;
2677     default:
2678         if (xmlXPathIsNaN(number)) {
2679             if (buffersize > (int)sizeof("NaN"))
2680                 snprintf(buffer, buffersize, "NaN");
2681         } else if (number == 0 && xmlXPathGetSign(number) != 0) {
2682             snprintf(buffer, buffersize, "0");
2683         } else if (number == ((int) number)) {
2684             char work[30];
2685             char *ptr, *cur;
2686             int value = (int) number;
2687
2688             ptr = &buffer[0];
2689             if (value == 0) {
2690                 *ptr++ = '0';
2691             } else {
2692                 snprintf(work, 29, "%d", value);
2693                 cur = &work[0];
2694                 while ((*cur) && (ptr - buffer < buffersize)) {
2695                     *ptr++ = *cur++;
2696                 }
2697             }
2698             if (ptr - buffer < buffersize) {
2699                 *ptr = 0;
2700             } else if (buffersize > 0) {
2701                 ptr--;
2702                 *ptr = 0;
2703             }
2704         } else {
2705             /*
2706               For the dimension of work,
2707                   DBL_DIG is number of significant digits
2708                   EXPONENT is only needed for "scientific notation"
2709                   3 is sign, decimal point, and terminating zero
2710                   LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2711               Note that this dimension is slightly (a few characters)
2712               larger than actually necessary.
2713             */
2714             char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2715             int integer_place, fraction_place;
2716             char *ptr;
2717             char *after_fraction;
2718             double absolute_value;
2719             int size;
2720
2721             absolute_value = fabs(number);
2722
2723             /*
2724              * First choose format - scientific or regular floating point.
2725              * In either case, result is in work, and after_fraction points
2726              * just past the fractional part.
2727             */
2728             if ( ((absolute_value > UPPER_DOUBLE) ||
2729                   (absolute_value < LOWER_DOUBLE)) &&
2730                  (absolute_value != 0.0) ) {
2731                 /* Use scientific notation */
2732                 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2733                 fraction_place = DBL_DIG - 1;
2734                 size = snprintf(work, sizeof(work),"%*.*e",
2735                          integer_place, fraction_place, number);
2736                 while ((size > 0) && (work[size] != 'e')) size--;
2737
2738             }
2739             else {
2740                 /* Use regular notation */
2741                 if (absolute_value > 0.0) {
2742                     integer_place = (int)log10(absolute_value);
2743                     if (integer_place > 0)
2744                         fraction_place = DBL_DIG - integer_place - 1;
2745                     else
2746                         fraction_place = DBL_DIG - integer_place;
2747                 } else {
2748                     fraction_place = 1;
2749                 }
2750                 size = snprintf(work, sizeof(work), "%0.*f",
2751                                 fraction_place, number);
2752             }
2753
2754             /* Remove fractional trailing zeroes */
2755             after_fraction = work + size;
2756             ptr = after_fraction;
2757             while (*(--ptr) == '0')
2758                 ;
2759             if (*ptr != '.')
2760                 ptr++;
2761             while ((*ptr++ = *after_fraction++) != 0);
2762
2763             /* Finally copy result back to caller */
2764             size = strlen(work) + 1;
2765             if (size > buffersize) {
2766                 work[buffersize - 1] = 0;
2767                 size = buffersize;
2768             }
2769             memmove(buffer, work, size);
2770         }
2771         break;
2772     }
2773 }
2774
2775
2776 /************************************************************************
2777  *                                                                      *
2778  *                      Routines to handle NodeSets                     *
2779  *                                                                      *
2780  ************************************************************************/
2781
2782 /**
2783  * xmlXPathOrderDocElems:
2784  * @doc:  an input document
2785  *
2786  * Call this routine to speed up XPath computation on static documents.
2787  * This stamps all the element nodes with the document order
2788  * Like for line information, the order is kept in the element->content
2789  * field, the value stored is actually - the node number (starting at -1)
2790  * to be able to differentiate from line numbers.
2791  *
2792  * Returns the number of elements found in the document or -1 in case
2793  *    of error.
2794  */
2795 long
2796 xmlXPathOrderDocElems(xmlDocPtr doc) {
2797     long count = 0;
2798     xmlNodePtr cur;
2799
2800     if (doc == NULL)
2801         return(-1);
2802     cur = doc->children;
2803     while (cur != NULL) {
2804         if (cur->type == XML_ELEMENT_NODE) {
2805             cur->content = (void *) (-(++count));
2806             if (cur->children != NULL) {
2807                 cur = cur->children;
2808                 continue;
2809             }
2810         }
2811         if (cur->next != NULL) {
2812             cur = cur->next;
2813             continue;
2814         }
2815         do {
2816             cur = cur->parent;
2817             if (cur == NULL)
2818                 break;
2819             if (cur == (xmlNodePtr) doc) {
2820                 cur = NULL;
2821                 break;
2822             }
2823             if (cur->next != NULL) {
2824                 cur = cur->next;
2825                 break;
2826             }
2827         } while (cur != NULL);
2828     }
2829     return(count);
2830 }
2831
2832 /**
2833  * xmlXPathCmpNodes:
2834  * @node1:  the first node
2835  * @node2:  the second node
2836  *
2837  * Compare two nodes w.r.t document order
2838  *
2839  * Returns -2 in case of error 1 if first point < second point, 0 if
2840  *         it's the same node, -1 otherwise
2841  */
2842 int
2843 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2844     int depth1, depth2;
2845     int attr1 = 0, attr2 = 0;
2846     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2847     xmlNodePtr cur, root;
2848
2849     if ((node1 == NULL) || (node2 == NULL))
2850         return(-2);
2851     /*
2852      * a couple of optimizations which will avoid computations in most cases
2853      */
2854     if (node1 == node2)         /* trivial case */
2855         return(0);
2856     if (node1->type == XML_ATTRIBUTE_NODE) {
2857         attr1 = 1;
2858         attrNode1 = node1;
2859         node1 = node1->parent;
2860     }
2861     if (node2->type == XML_ATTRIBUTE_NODE) {
2862         attr2 = 1;
2863         attrNode2 = node2;
2864         node2 = node2->parent;
2865     }
2866     if (node1 == node2) {
2867         if (attr1 == attr2) {
2868             /* not required, but we keep attributes in order */
2869             if (attr1 != 0) {
2870                 cur = attrNode2->prev;
2871                 while (cur != NULL) {
2872                     if (cur == attrNode1)
2873                         return (1);
2874                     cur = cur->prev;
2875                 }
2876                 return (-1);
2877             }
2878             return(0);
2879         }
2880         if (attr2 == 1)
2881             return(1);
2882         return(-1);
2883     }
2884     if ((node1->type == XML_NAMESPACE_DECL) ||
2885         (node2->type == XML_NAMESPACE_DECL))
2886         return(1);
2887     if (node1 == node2->prev)
2888         return(1);
2889     if (node1 == node2->next)
2890         return(-1);
2891
2892     /*
2893      * Speedup using document order if availble.
2894      */
2895     if ((node1->type == XML_ELEMENT_NODE) &&
2896         (node2->type == XML_ELEMENT_NODE) &&
2897         (0 > (long) node1->content) &&
2898         (0 > (long) node2->content) &&
2899         (node1->doc == node2->doc)) {
2900         long l1, l2;
2901
2902         l1 = -((long) node1->content);
2903         l2 = -((long) node2->content);
2904         if (l1 < l2)
2905             return(1);
2906         if (l1 > l2)
2907             return(-1);
2908     }
2909
2910     /*
2911      * compute depth to root
2912      */
2913     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2914         if (cur == node1)
2915             return(1);
2916         depth2++;
2917     }
2918     root = cur;
2919     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2920         if (cur == node2)
2921             return(-1);
2922         depth1++;
2923     }
2924     /*
2925      * Distinct document (or distinct entities :-( ) case.
2926      */
2927     if (root != cur) {
2928         return(-2);
2929     }
2930     /*
2931      * get the nearest common ancestor.
2932      */
2933     while (depth1 > depth2) {
2934         depth1--;
2935         node1 = node1->parent;
2936     }
2937     while (depth2 > depth1) {
2938         depth2--;
2939         node2 = node2->parent;
2940     }
2941     while (node1->parent != node2->parent) {
2942         node1 = node1->parent;
2943         node2 = node2->parent;
2944         /* should not happen but just in case ... */
2945         if ((node1 == NULL) || (node2 == NULL))
2946             return(-2);
2947     }
2948     /*
2949      * Find who's first.
2950      */
2951     if (node1 == node2->prev)
2952         return(1);
2953     if (node1 == node2->next)
2954         return(-1);
2955     /*
2956      * Speedup using document order if availble.
2957      */
2958     if ((node1->type == XML_ELEMENT_NODE) &&
2959         (node2->type == XML_ELEMENT_NODE) &&
2960         (0 > (long) node1->content) &&
2961         (0 > (long) node2->content) &&
2962         (node1->doc == node2->doc)) {
2963         long l1, l2;
2964
2965         l1 = -((long) node1->content);
2966         l2 = -((long) node2->content);
2967         if (l1 < l2)
2968             return(1);
2969         if (l1 > l2)
2970             return(-1);
2971     }
2972
2973     for (cur = node1->next;cur != NULL;cur = cur->next)
2974         if (cur == node2)
2975             return(1);
2976     return(-1); /* assume there is no sibling list corruption */
2977 }
2978
2979 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2980 /**
2981  * xmlXPathCmpNodesExt:
2982  * @node1:  the first node
2983  * @node2:  the second node
2984  *
2985  * Compare two nodes w.r.t document order.
2986  * This one is optimized for handling of non-element nodes.
2987  *
2988  * Returns -2 in case of error 1 if first point < second point, 0 if
2989  *         it's the same node, -1 otherwise
2990  */
2991 static int
2992 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2993     int depth1, depth2;
2994     int misc = 0, precedence1 = 0, precedence2 = 0;
2995     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2996     xmlNodePtr cur, root;
2997     long l1, l2;
2998
2999     if ((node1 == NULL) || (node2 == NULL))
3000         return(-2);
3001
3002     if (node1 == node2)
3003         return(0);
3004
3005     /*
3006      * a couple of optimizations which will avoid computations in most cases
3007      */
3008     switch (node1->type) {
3009         case XML_ELEMENT_NODE:
3010             if (node2->type == XML_ELEMENT_NODE) {
3011                 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3012                     (0 > (long) node2->content) &&
3013                     (node1->doc == node2->doc))
3014                 {
3015                     l1 = -((long) node1->content);
3016                     l2 = -((long) node2->content);
3017                     if (l1 < l2)
3018                         return(1);
3019                     if (l1 > l2)
3020                         return(-1);
3021                 } else
3022                     goto turtle_comparison;
3023             }
3024             break;
3025         case XML_ATTRIBUTE_NODE:
3026             precedence1 = 1; /* element is owner */
3027             miscNode1 = node1;
3028             node1 = node1->parent;
3029             misc = 1;
3030             break;
3031         case XML_TEXT_NODE:
3032         case XML_CDATA_SECTION_NODE:
3033         case XML_COMMENT_NODE:
3034         case XML_PI_NODE: {
3035             miscNode1 = node1;
3036             /*
3037             * Find nearest element node.
3038             */
3039             if (node1->prev != NULL) {
3040                 do {
3041                     node1 = node1->prev;
3042                     if (node1->type == XML_ELEMENT_NODE) {
3043                         precedence1 = 3; /* element in prev-sibl axis */
3044                         break;
3045                     }
3046                     if (node1->prev == NULL) {
3047                         precedence1 = 2; /* element is parent */
3048                         /*
3049                         * URGENT TODO: Are there any cases, where the
3050                         * parent of such a node is not an element node?
3051                         */
3052                         node1 = node1->parent;
3053                         break;
3054                     }
3055                 } while (1);
3056             } else {
3057                 precedence1 = 2; /* element is parent */
3058                 node1 = node1->parent;
3059             }
3060             if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3061                 (0 <= (long) node1->content)) {
3062                 /*
3063                 * Fallback for whatever case.
3064                 */
3065                 node1 = miscNode1;
3066                 precedence1 = 0;
3067             } else
3068                 misc = 1;
3069         }
3070             break;
3071         case XML_NAMESPACE_DECL:
3072             /*
3073             * TODO: why do we return 1 for namespace nodes?
3074             */
3075             return(1);
3076         default:
3077             break;
3078     }
3079     switch (node2->type) {
3080         case XML_ELEMENT_NODE:
3081             break;
3082         case XML_ATTRIBUTE_NODE:
3083             precedence2 = 1; /* element is owner */
3084             miscNode2 = node2;
3085             node2 = node2->parent;
3086             misc = 1;
3087             break;
3088         case XML_TEXT_NODE:
3089         case XML_CDATA_SECTION_NODE:
3090         case XML_COMMENT_NODE:
3091         case XML_PI_NODE: {
3092             miscNode2 = node2;
3093             if (node2->prev != NULL) {
3094                 do {
3095                     node2 = node2->prev;
3096                     if (node2->type == XML_ELEMENT_NODE) {
3097                         precedence2 = 3; /* element in prev-sibl axis */
3098                         break;
3099                     }
3100                     if (node2->prev == NULL) {
3101                         precedence2 = 2; /* element is parent */
3102                         node2 = node2->parent;
3103                         break;
3104                     }
3105                 } while (1);
3106             } else {
3107                 precedence2 = 2; /* element is parent */
3108                 node2 = node2->parent;
3109             }
3110             if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3111                 (0 <= (long) node1->content))
3112             {
3113                 node2 = miscNode2;
3114                 precedence2 = 0;
3115             } else
3116                 misc = 1;
3117         }
3118             break;
3119         case XML_NAMESPACE_DECL:
3120             return(1);
3121         default:
3122             break;
3123     }
3124     if (misc) {
3125         if (node1 == node2) {
3126             if (precedence1 == precedence2) {
3127                 /*
3128                 * The ugly case; but normally there aren't many
3129                 * adjacent non-element nodes around.
3130                 */
3131                 cur = miscNode2->prev;
3132                 while (cur != NULL) {
3133                     if (cur == miscNode1)
3134                         return(1);
3135                     if (cur->type == XML_ELEMENT_NODE)
3136                         return(-1);
3137                     cur = cur->prev;
3138                 }
3139                 return (-1);
3140             } else {
3141                 /*
3142                 * Evaluate based on higher precedence wrt to the element.
3143                 * TODO: This assumes attributes are sorted before content.
3144                 *   Is this 100% correct?
3145                 */
3146                 if (precedence1 < precedence2)
3147                     return(1);
3148                 else
3149                     return(-1);
3150             }
3151         }
3152         /*
3153         * Special case: One of the helper-elements is contained by the other.
3154         * <foo>
3155         *   <node2>
3156         *     <node1>Text-1(precedence1 == 2)</node1>
3157         *   </node2>
3158         *   Text-6(precedence2 == 3)
3159         * </foo>
3160         */
3161         if ((precedence2 == 3) && (precedence1 > 1)) {
3162             cur = node1->parent;
3163             while (cur) {
3164                 if (cur == node2)
3165                     return(1);
3166                 cur = cur->parent;
3167             }
3168         }
3169         if ((precedence1 == 3) && (precedence2 > 1)) {
3170             cur = node2->parent;
3171             while (cur) {
3172                 if (cur == node1)
3173                     return(-1);
3174                 cur = cur->parent;
3175             }
3176         }
3177     }
3178
3179     /*
3180      * Speedup using document order if availble.
3181      */
3182     if ((node1->type == XML_ELEMENT_NODE) &&
3183         (node2->type == XML_ELEMENT_NODE) &&
3184         (0 > (long) node1->content) &&
3185         (0 > (long) node2->content) &&
3186         (node1->doc == node2->doc)) {
3187
3188         l1 = -((long) node1->content);
3189         l2 = -((long) node2->content);
3190         if (l1 < l2)
3191             return(1);
3192         if (l1 > l2)
3193             return(-1);
3194     }
3195
3196 turtle_comparison:
3197
3198     if (node1 == node2->prev)
3199         return(1);
3200     if (node1 == node2->next)
3201         return(-1);
3202     /*
3203      * compute depth to root
3204      */
3205     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3206         if (cur == node1)
3207             return(1);
3208         depth2++;
3209     }
3210     root = cur;
3211     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3212         if (cur == node2)
3213             return(-1);
3214         depth1++;
3215     }
3216     /*
3217      * Distinct document (or distinct entities :-( ) case.
3218      */
3219     if (root != cur) {
3220         return(-2);
3221     }
3222     /*
3223      * get the nearest common ancestor.
3224      */
3225     while (depth1 > depth2) {
3226         depth1--;
3227         node1 = node1->parent;
3228     }
3229     while (depth2 > depth1) {
3230         depth2--;
3231         node2 = node2->parent;
3232     }
3233     while (node1->parent != node2->parent) {
3234         node1 = node1->parent;
3235         node2 = node2->parent;
3236         /* should not happen but just in case ... */
3237         if ((node1 == NULL) || (node2 == NULL))
3238             return(-2);
3239     }
3240     /*
3241      * Find who's first.
3242      */
3243     if (node1 == node2->prev)
3244         return(1);
3245     if (node1 == node2->next)
3246         return(-1);
3247     /*
3248      * Speedup using document order if availble.
3249      */
3250     if ((node1->type == XML_ELEMENT_NODE) &&
3251         (node2->type == XML_ELEMENT_NODE) &&
3252         (0 > (long) node1->content) &&
3253         (0 > (long) node2->content) &&
3254         (node1->doc == node2->doc)) {
3255
3256         l1 = -((long) node1->content);
3257         l2 = -((long) node2->content);
3258         if (l1 < l2)
3259             return(1);
3260         if (l1 > l2)
3261             return(-1);
3262     }
3263
3264     for (cur = node1->next;cur != NULL;cur = cur->next)
3265         if (cur == node2)
3266             return(1);
3267     return(-1); /* assume there is no sibling list corruption */
3268 }
3269 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3270
3271 /**
3272  * xmlXPathNodeSetSort:
3273  * @set:  the node set
3274  *
3275  * Sort the node set in document order
3276  */
3277 void
3278 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3279     int i, j, incr, len;
3280     xmlNodePtr tmp;
3281
3282     if (set == NULL)
3283         return;
3284
3285     /* Use Shell's sort to sort the node-set */
3286     len = set->nodeNr;
3287     for (incr = len / 2; incr > 0; incr /= 2) {
3288         for (i = incr; i < len; i++) {
3289             j = i - incr;
3290             while (j >= 0) {
3291 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3292                 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3293                         set->nodeTab[j + incr]) == -1)
3294 #else
3295                 if (xmlXPathCmpNodes(set->nodeTab[j],
3296                         set->nodeTab[j + incr]) == -1)
3297 #endif
3298                 {
3299                     tmp = set->nodeTab[j];
3300                     set->nodeTab[j] = set->nodeTab[j + incr];
3301                     set->nodeTab[j + incr] = tmp;
3302                     j -= incr;
3303                 } else
3304                     break;
3305             }
3306         }
3307     }
3308 }
3309
3310 #define XML_NODESET_DEFAULT     10
3311 /**
3312  * xmlXPathNodeSetDupNs:
3313  * @node:  the parent node of the namespace XPath node
3314  * @ns:  the libxml namespace declaration node.
3315  *
3316  * Namespace node in libxml don't match the XPath semantic. In a node set
3317  * the namespace nodes are duplicated and the next pointer is set to the
3318  * parent node in the XPath semantic.
3319  *
3320  * Returns the newly created object.
3321  */
3322 static xmlNodePtr
3323 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3324     xmlNsPtr cur;
3325
3326     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3327         return(NULL);
3328     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3329         return((xmlNodePtr) ns);
3330
3331     /*
3332      * Allocate a new Namespace and fill the fields.
3333      */
3334     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3335     if (cur == NULL) {
3336         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3337         return(NULL);
3338     }
3339     memset(cur, 0, sizeof(xmlNs));
3340     cur->type = XML_NAMESPACE_DECL;
3341     if (ns->href != NULL)
3342         cur->href = xmlStrdup(ns->href);
3343     if (ns->prefix != NULL)
3344         cur->prefix = xmlStrdup(ns->prefix);
3345     cur->next = (xmlNsPtr) node;
3346     return((xmlNodePtr) cur);
3347 }
3348
3349 /**
3350  * xmlXPathNodeSetFreeNs:
3351  * @ns:  the XPath namespace node found in a nodeset.
3352  *
3353  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3354  * the namespace nodes are duplicated and the next pointer is set to the
3355  * parent node in the XPath semantic. Check if such a node needs to be freed
3356  */
3357 void
3358 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3359     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3360         return;
3361
3362     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3363         if (ns->href != NULL)
3364             xmlFree((xmlChar *)ns->href);
3365         if (ns->prefix != NULL)
3366             xmlFree((xmlChar *)ns->prefix);
3367         xmlFree(ns);
3368     }
3369 }
3370
3371 /**
3372  * xmlXPathNodeSetCreate:
3373  * @val:  an initial xmlNodePtr, or NULL
3374  *
3375  * Create a new xmlNodeSetPtr of type double and of value @val
3376  *
3377  * Returns the newly created object.
3378  */
3379 xmlNodeSetPtr
3380 xmlXPathNodeSetCreate(xmlNodePtr val) {
3381     xmlNodeSetPtr ret;
3382
3383     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3384     if (ret == NULL) {
3385         xmlXPathErrMemory(NULL, "creating nodeset\n");
3386         return(NULL);
3387     }
3388     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3389     if (val != NULL) {
3390         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3391                                              sizeof(xmlNodePtr));
3392         if (ret->nodeTab == NULL) {
3393             xmlXPathErrMemory(NULL, "creating nodeset\n");
3394             xmlFree(ret);
3395             return(NULL);
3396         }
3397         memset(ret->nodeTab, 0 ,
3398                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3399         ret->nodeMax = XML_NODESET_DEFAULT;
3400         if (val->type == XML_NAMESPACE_DECL) {
3401             xmlNsPtr ns = (xmlNsPtr) val;
3402
3403             ret->nodeTab[ret->nodeNr++] =
3404                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3405         } else
3406             ret->nodeTab[ret->nodeNr++] = val;
3407     }
3408     return(ret);
3409 }
3410
3411 /**
3412  * xmlXPathNodeSetCreateSize:
3413  * @size:  the initial size of the set
3414  *
3415  * Create a new xmlNodeSetPtr of type double and of value @val
3416  *
3417  * Returns the newly created object.
3418  */
3419 static xmlNodeSetPtr
3420 xmlXPathNodeSetCreateSize(int size) {
3421     xmlNodeSetPtr ret;
3422
3423     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3424     if (ret == NULL) {
3425         xmlXPathErrMemory(NULL, "creating nodeset\n");
3426         return(NULL);
3427     }
3428     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3429     if (size < XML_NODESET_DEFAULT)
3430         size = XML_NODESET_DEFAULT;
3431     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3432     if (ret->nodeTab == NULL) {
3433         xmlXPathErrMemory(NULL, "creating nodeset\n");
3434         xmlFree(ret);
3435         return(NULL);
3436     }
3437     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3438     ret->nodeMax = size;
3439     return(ret);
3440 }
3441
3442 /**
3443  * xmlXPathNodeSetContains:
3444  * @cur:  the node-set
3445  * @val:  the node
3446  *
3447  * checks whether @cur contains @val
3448  *
3449  * Returns true (1) if @cur contains @val, false (0) otherwise
3450  */
3451 int
3452 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3453     int i;
3454
3455     if ((cur == NULL) || (val == NULL)) return(0);
3456     if (val->type == XML_NAMESPACE_DECL) {
3457         for (i = 0; i < cur->nodeNr; i++) {
3458             if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3459                 xmlNsPtr ns1, ns2;
3460
3461                 ns1 = (xmlNsPtr) val;
3462                 ns2 = (xmlNsPtr) cur->nodeTab[i];
3463                 if (ns1 == ns2)
3464                     return(1);
3465                 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3466                     (xmlStrEqual(ns1->prefix, ns2->prefix)))
3467                     return(1);
3468             }
3469         }
3470     } else {
3471         for (i = 0; i < cur->nodeNr; i++) {
3472             if (cur->nodeTab[i] == val)
3473                 return(1);
3474         }
3475     }
3476     return(0);
3477 }
3478
3479 /**
3480  * xmlXPathNodeSetAddNs:
3481  * @cur:  the initial node set
3482  * @node:  the hosting node
3483  * @ns:  a the namespace node
3484  *
3485  * add a new namespace node to an existing NodeSet
3486  */
3487 void
3488 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3489     int i;
3490
3491
3492     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3493         (ns->type != XML_NAMESPACE_DECL) ||
3494         (node->type != XML_ELEMENT_NODE))
3495         return;
3496
3497     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3498     /*
3499      * prevent duplicates
3500      */
3501     for (i = 0;i < cur->nodeNr;i++) {
3502         if ((cur->nodeTab[i] != NULL) &&
3503             (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3504             (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3505             (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3506             return;
3507     }
3508
3509     /*
3510      * grow the nodeTab if needed
3511      */
3512     if (cur->nodeMax == 0) {
3513         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3514                                              sizeof(xmlNodePtr));
3515         if (cur->nodeTab == NULL) {
3516             xmlXPathErrMemory(NULL, "growing nodeset\n");
3517             return;
3518         }
3519         memset(cur->nodeTab, 0 ,
3520                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3521         cur->nodeMax = XML_NODESET_DEFAULT;
3522     } else if (cur->nodeNr == cur->nodeMax) {
3523         xmlNodePtr *temp;
3524
3525         cur->nodeMax *= 2;
3526         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3527                                       sizeof(xmlNodePtr));
3528         if (temp == NULL) {
3529             xmlXPathErrMemory(NULL, "growing nodeset\n");
3530             return;
3531         }
3532         cur->nodeTab = temp;
3533     }
3534     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3535 }
3536
3537 /**
3538  * xmlXPathNodeSetAdd:
3539  * @cur:  the initial node set
3540  * @val:  a new xmlNodePtr
3541  *
3542  * add a new xmlNodePtr to an existing NodeSet
3543  */
3544 void
3545 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3546     int i;
3547
3548     if ((cur == NULL) || (val == NULL)) return;
3549
3550 #if 0
3551     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3552         return; /* an XSLT fake node */
3553 #endif
3554
3555     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3556     /*
3557      * prevent duplcates
3558      */
3559     for (i = 0;i < cur->nodeNr;i++)
3560         if (cur->nodeTab[i] == val) return;
3561
3562     /*
3563      * grow the nodeTab if needed
3564      */
3565     if (cur->nodeMax == 0) {
3566         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3567                                              sizeof(xmlNodePtr));
3568         if (cur->nodeTab == NULL) {
3569             xmlXPathErrMemory(NULL, "growing nodeset\n");
3570             return;
3571         }
3572         memset(cur->nodeTab, 0 ,
3573                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3574         cur->nodeMax = XML_NODESET_DEFAULT;
3575     } else if (cur->nodeNr == cur->nodeMax) {
3576         xmlNodePtr *temp;
3577
3578         cur->nodeMax *= 2;
3579         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3580                                       sizeof(xmlNodePtr));
3581         if (temp == NULL) {
3582             xmlXPathErrMemory(NULL, "growing nodeset\n");
3583             return;
3584         }
3585         cur->nodeTab = temp;
3586     }
3587     if (val->type == XML_NAMESPACE_DECL) {
3588         xmlNsPtr ns = (xmlNsPtr) val;
3589
3590         cur->nodeTab[cur->nodeNr++] =
3591             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3592     } else
3593         cur->nodeTab[cur->nodeNr++] = val;
3594 }
3595
3596 /**
3597  * xmlXPathNodeSetAddUnique:
3598  * @cur:  the initial node set
3599  * @val:  a new xmlNodePtr
3600  *
3601  * add a new xmlNodePtr to an existing NodeSet, optimized version
3602  * when we are sure the node is not already in the set.
3603  */
3604 void
3605 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3606     if ((cur == NULL) || (val == NULL)) return;
3607
3608 #if 0
3609     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3610         return; /* an XSLT fake node */
3611 #endif
3612
3613     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3614     /*
3615      * grow the nodeTab if needed
3616      */
3617     if (cur->nodeMax == 0) {
3618         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3619                                              sizeof(xmlNodePtr));
3620         if (cur->nodeTab == NULL) {
3621             xmlXPathErrMemory(NULL, "growing nodeset\n");
3622             return;
3623         }
3624         memset(cur->nodeTab, 0 ,
3625                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3626         cur->nodeMax = XML_NODESET_DEFAULT;
3627     } else if (cur->nodeNr == cur->nodeMax) {
3628         xmlNodePtr *temp;
3629
3630         cur->nodeMax *= 2;
3631         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3632                                       sizeof(xmlNodePtr));
3633         if (temp == NULL) {
3634             xmlXPathErrMemory(NULL, "growing nodeset\n");
3635             return;
3636         }
3637         cur->nodeTab = temp;
3638     }
3639     if (val->type == XML_NAMESPACE_DECL) {
3640         xmlNsPtr ns = (xmlNsPtr) val;
3641
3642         cur->nodeTab[cur->nodeNr++] =
3643             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3644     } else
3645         cur->nodeTab[cur->nodeNr++] = val;
3646 }
3647
3648 /**
3649  * xmlXPathNodeSetMerge:
3650  * @val1:  the first NodeSet or NULL
3651  * @val2:  the second NodeSet
3652  *
3653  * Merges two nodesets, all nodes from @val2 are added to @val1
3654  * if @val1 is NULL, a new set is created and copied from @val2
3655  *
3656  * Returns @val1 once extended or NULL in case of error.
3657  */
3658 xmlNodeSetPtr
3659 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3660     int i, j, initNr, skip;
3661     xmlNodePtr n1, n2;
3662
3663     if (val2 == NULL) return(val1);
3664     if (val1 == NULL) {
3665         val1 = xmlXPathNodeSetCreate(NULL);
3666     if (val1 == NULL)
3667         return (NULL);
3668 #if 0
3669         /*
3670         * TODO: The optimization won't work in every case, since
3671         *  those nasty namespace nodes need to be added with
3672         *  xmlXPathNodeSetDupNs() to the set; thus a pure
3673         *  memcpy is not possible.
3674         *  If there was a flag on the nodesetval, indicating that
3675         *  some temporary nodes are in, that would be helpfull.
3676         */
3677         /*
3678         * Optimization: Create an equally sized node-set
3679         * and memcpy the content.
3680         */
3681         val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3682         if (val1 == NULL)
3683             return(NULL);
3684         if (val2->nodeNr != 0) {
3685             if (val2->nodeNr == 1)
3686                 *(val1->nodeTab) = *(val2->nodeTab);
3687             else {
3688                 memcpy(val1->nodeTab, val2->nodeTab,
3689                     val2->nodeNr * sizeof(xmlNodePtr));
3690             }
3691             val1->nodeNr = val2->nodeNr;
3692         }
3693         return(val1);
3694 #endif
3695     }
3696
3697     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3698     initNr = val1->nodeNr;
3699
3700     for (i = 0;i < val2->nodeNr;i++) {
3701         n2 = val2->nodeTab[i];
3702         /*
3703          * check against duplicates
3704          */
3705         skip = 0;
3706         for (j = 0; j < initNr; j++) {
3707             n1 = val1->nodeTab[j];
3708             if (n1 == n2) {
3709                 skip = 1;
3710                 break;
3711             } else if ((n1->type == XML_NAMESPACE_DECL) &&
3712                        (n2->type == XML_NAMESPACE_DECL)) {
3713                 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3714                     (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3715                         ((xmlNsPtr) n2)->prefix)))
3716                 {
3717                     skip = 1;
3718                     break;
3719                 }
3720             }
3721         }
3722         if (skip)
3723             continue;
3724
3725         /*
3726          * grow the nodeTab if needed
3727          */
3728         if (val1->nodeMax == 0) {
3729             val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3730                                                     sizeof(xmlNodePtr));
3731             if (val1->nodeTab == NULL) {
3732                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3733                 return(NULL);
3734             }
3735             memset(val1->nodeTab, 0 ,
3736                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3737             val1->nodeMax = XML_NODESET_DEFAULT;
3738         } else if (val1->nodeNr == val1->nodeMax) {
3739             xmlNodePtr *temp;
3740
3741             val1->nodeMax *= 2;
3742             temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3743                                              sizeof(xmlNodePtr));
3744             if (temp == NULL) {
3745                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3746                 return(NULL);
3747             }
3748             val1->nodeTab = temp;
3749         }
3750         if (n2->type == XML_NAMESPACE_DECL) {
3751             xmlNsPtr ns = (xmlNsPtr) n2;
3752
3753             val1->nodeTab[val1->nodeNr++] =
3754                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3755         } else
3756             val1->nodeTab[val1->nodeNr++] = n2;
3757     }
3758
3759     return(val1);
3760 }
3761
3762 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3763 /**
3764  * xmlXPathNodeSetMergeUnique:
3765  * @val1:  the first NodeSet or NULL
3766  * @val2:  the second NodeSet
3767  *
3768  * Merges two nodesets, all nodes from @val2 are added to @val1
3769  * if @val1 is NULL, a new set is created and copied from @val2
3770  *
3771  * Returns @val1 once extended or NULL in case of error.
3772  */
3773 static xmlNodeSetPtr
3774 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3775     int i;
3776
3777     if (val2 == NULL) return(val1);
3778     if (val1 == NULL) {
3779         val1 = xmlXPathNodeSetCreate(NULL);
3780     }
3781     if (val1 == NULL)
3782         return (NULL);
3783
3784     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3785
3786     for (i = 0;i < val2->nodeNr;i++) {
3787         /*
3788          * grow the nodeTab if needed
3789          */
3790         if (val1->nodeMax == 0) {
3791             val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3792                                                     sizeof(xmlNodePtr));
3793             if (val1->nodeTab == NULL) {
3794                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3795                 return(NULL);
3796             }
3797             memset(val1->nodeTab, 0 ,
3798                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3799             val1->nodeMax = XML_NODESET_DEFAULT;
3800         } else if (val1->nodeNr == val1->nodeMax) {
3801             xmlNodePtr *temp;
3802
3803             val1->nodeMax *= 2;
3804             temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3805                                              sizeof(xmlNodePtr));
3806             if (temp == NULL) {
3807                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3808                 return(NULL);
3809             }
3810             val1->nodeTab = temp;
3811         }
3812         if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3813             xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3814
3815             val1->nodeTab[val1->nodeNr++] =
3816                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3817         } else
3818             val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3819     }
3820
3821     return(val1);
3822 }
3823 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3824
3825 /**
3826  * xmlXPathNodeSetMergeAndClear:
3827  * @set1:  the first NodeSet or NULL
3828  * @set2:  the second NodeSet
3829  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3830  *
3831  * Merges two nodesets, all nodes from @set2 are added to @set1
3832  * if @set1 is NULL, a new set is created and copied from @set2.
3833  * Checks for duplicate nodes. Clears set2.
3834  *
3835  * Returns @set1 once extended or NULL in case of error.
3836  */
3837 static xmlNodeSetPtr
3838 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3839                              int hasNullEntries)
3840 {
3841     if ((set1 == NULL) && (hasNullEntries == 0)) {
3842         /*
3843         * Note that doing a memcpy of the list, namespace nodes are
3844         * just assigned to set1, since set2 is cleared anyway.
3845         */
3846         set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3847         if (set1 == NULL)
3848             return(NULL);
3849         if (set2->nodeNr != 0) {
3850             memcpy(set1->nodeTab, set2->nodeTab,
3851                 set2->nodeNr * sizeof(xmlNodePtr));
3852             set1->nodeNr = set2->nodeNr;
3853         }
3854     } else {
3855         int i, j, initNbSet1;
3856         xmlNodePtr n1, n2;
3857
3858         if (set1 == NULL)
3859             set1 = xmlXPathNodeSetCreate(NULL);
3860         if (set1 == NULL)
3861             return (NULL);
3862
3863         initNbSet1 = set1->nodeNr;
3864         for (i = 0;i < set2->nodeNr;i++) {
3865             n2 = set2->nodeTab[i];
3866             /*
3867             * Skip NULLed entries.
3868             */
3869             if (n2 == NULL)
3870                 continue;
3871             /*
3872             * Skip duplicates.
3873             */
3874             for (j = 0; j < initNbSet1; j++) {
3875                 n1 = set1->nodeTab[j];
3876                 if (n1 == n2) {
3877                     goto skip_node;
3878                 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3879                     (n2->type == XML_NAMESPACE_DECL))
3880                 {
3881                     if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3882                         (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3883                         ((xmlNsPtr) n2)->prefix)))
3884                     {
3885                         /*
3886                         * Free the namespace node.
3887                         */
3888                         set2->nodeTab[i] = NULL;
3889                         xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3890                         goto skip_node;
3891                     }
3892                 }
3893             }
3894             /*
3895             * grow the nodeTab if needed
3896             */
3897             if (set1->nodeMax == 0) {
3898                 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3899                     XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3900                 if (set1->nodeTab == NULL) {
3901                     xmlXPathErrMemory(NULL, "merging nodeset\n");
3902                     return(NULL);
3903                 }
3904                 memset(set1->nodeTab, 0,
3905                     XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3906                 set1->nodeMax = XML_NODESET_DEFAULT;
3907             } else if (set1->nodeNr >= set1->nodeMax) {
3908                 xmlNodePtr *temp;
3909
3910                 set1->nodeMax *= 2;
3911                 temp = (xmlNodePtr *) xmlRealloc(
3912                     set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3913                 if (temp == NULL) {
3914                     xmlXPathErrMemory(NULL, "merging nodeset\n");
3915                     return(NULL);
3916                 }
3917                 set1->nodeTab = temp;
3918             }
3919             if (n2->type == XML_NAMESPACE_DECL) {
3920                 xmlNsPtr ns = (xmlNsPtr) n2;
3921
3922                 set1->nodeTab[set1->nodeNr++] =
3923                     xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3924             } else
3925                 set1->nodeTab[set1->nodeNr++] = n2;
3926 skip_node:
3927             {}
3928         }
3929     }
3930     set2->nodeNr = 0;
3931     return(set1);
3932 }
3933
3934 /**
3935  * xmlXPathNodeSetMergeAndClearNoDupls:
3936  * @set1:  the first NodeSet or NULL
3937  * @set2:  the second NodeSet
3938  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3939  *
3940  * Merges two nodesets, all nodes from @set2 are added to @set1
3941  * if @set1 is NULL, a new set is created and copied from @set2.
3942  * Doesn't chack for duplicate nodes. Clears set2.
3943  *
3944  * Returns @set1 once extended or NULL in case of error.
3945  */
3946 static xmlNodeSetPtr
3947 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3948                                     int hasNullEntries)
3949 {
3950     if (set2 == NULL)
3951         return(set1);
3952     if ((set1 == NULL) && (hasNullEntries == 0)) {
3953         /*
3954         * Note that doing a memcpy of the list, namespace nodes are
3955         * just assigned to set1, since set2 is cleared anyway.
3956         */
3957         set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3958         if (set1 == NULL)
3959             return(NULL);
3960         if (set2->nodeNr != 0) {
3961             memcpy(set1->nodeTab, set2->nodeTab,
3962                 set2->nodeNr * sizeof(xmlNodePtr));
3963             set1->nodeNr = set2->nodeNr;
3964         }
3965     } else {
3966         int i;
3967         xmlNodePtr n2;
3968
3969         if (set1 == NULL)
3970             set1 = xmlXPathNodeSetCreate(NULL);
3971         if (set1 == NULL)
3972             return (NULL);
3973
3974         for (i = 0;i < set2->nodeNr;i++) {
3975             n2 = set2->nodeTab[i];
3976             /*
3977             * Skip NULLed entries.
3978             */
3979             if (n2 == NULL)
3980                 continue;
3981             if (set1->nodeMax == 0) {
3982                 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3983                     XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3984                 if (set1->nodeTab == NULL) {
3985                     xmlXPathErrMemory(NULL, "merging nodeset\n");
3986                     return(NULL);
3987                 }
3988                 memset(set1->nodeTab, 0,
3989                     XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3990                 set1->nodeMax = XML_NODESET_DEFAULT;
3991             } else if (set1->nodeNr >= set1->nodeMax) {
3992                 xmlNodePtr *temp;
3993
3994                 set1->nodeMax *= 2;
3995                 temp = (xmlNodePtr *) xmlRealloc(
3996                     set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3997                 if (temp == NULL) {
3998                     xmlXPathErrMemory(NULL, "merging nodeset\n");
3999                     return(NULL);
4000                 }
4001                 set1->nodeTab = temp;
4002             }
4003             set1->nodeTab[set1->nodeNr++] = n2;
4004         }
4005     }
4006     set2->nodeNr = 0;
4007     return(set1);
4008 }
4009
4010 /**
4011  * xmlXPathNodeSetDel:
4012  * @cur:  the initial node set
4013  * @val:  an xmlNodePtr
4014  *
4015  * Removes an xmlNodePtr from an existing NodeSet
4016  */
4017 void
4018 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4019     int i;
4020
4021     if (cur == NULL) return;
4022     if (val == NULL) return;
4023
4024     /*
4025      * find node in nodeTab
4026      */
4027     for (i = 0;i < cur->nodeNr;i++)
4028         if (cur->nodeTab[i] == val) break;
4029
4030     if (i >= cur->nodeNr) {     /* not found */
4031 #ifdef DEBUG
4032         xmlGenericError(xmlGenericErrorContext,
4033                 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4034                 val->name);
4035 #endif
4036         return;
4037     }
4038     if ((cur->nodeTab[i] != NULL) &&
4039         (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4040         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4041     cur->nodeNr--;
4042     for (;i < cur->nodeNr;i++)
4043         cur->nodeTab[i] = cur->nodeTab[i + 1];
4044     cur->nodeTab[cur->nodeNr] = NULL;
4045 }
4046
4047 /**
4048  * xmlXPathNodeSetRemove:
4049  * @cur:  the initial node set
4050  * @val:  the index to remove
4051  *
4052  * Removes an entry from an existing NodeSet list.
4053  */
4054 void
4055 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4056     if (cur == NULL) return;
4057     if (val >= cur->nodeNr) return;
4058     if ((cur->nodeTab[val] != NULL) &&
4059         (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4060         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4061     cur->nodeNr--;
4062     for (;val < cur->nodeNr;val++)
4063         cur->nodeTab[val] = cur->nodeTab[val + 1];
4064     cur->nodeTab[cur->nodeNr] = NULL;
4065 }
4066
4067 /**
4068  * xmlXPathFreeNodeSet:
4069  * @obj:  the xmlNodeSetPtr to free
4070  *
4071  * Free the NodeSet compound (not the actual nodes !).
4072  */
4073 void
4074 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4075     if (obj == NULL) return;
4076     if (obj->nodeTab != NULL) {
4077         int i;
4078
4079         /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4080         for (i = 0;i < obj->nodeNr;i++)
4081             if ((obj->nodeTab[i] != NULL) &&
4082                 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4083                 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4084         xmlFree(obj->nodeTab);
4085     }
4086     xmlFree(obj);
4087 }
4088
4089 /**
4090  * xmlXPathNodeSetClear:
4091  * @set:  the node set to clear
4092  *
4093  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4094  * are feed), but does *not* free the list itself. Sets the length of the
4095  * list to 0.
4096  */
4097 static void
4098 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4099 {
4100     if ((set == NULL) || (set->nodeNr <= 0))
4101         return;
4102     else if (hasNsNodes) {
4103         int i;
4104         xmlNodePtr node;
4105
4106         for (i = 0; i < set->nodeNr; i++) {
4107             node = set->nodeTab[i];
4108             if ((node != NULL) &&
4109                 (node->type == XML_NAMESPACE_DECL))
4110                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4111         }
4112     }
4113     set->nodeNr = 0;
4114 }
4115
4116 /**
4117  * xmlXPathNodeSetClearFromPos:
4118  * @set: the node set to be cleared
4119  * @pos: the start position to clear from
4120  *
4121  * Clears the list from temporary XPath objects (e.g. namespace nodes
4122  * are feed) starting with the entry at @pos, but does *not* free the list
4123  * itself. Sets the length of the list to @pos.
4124  */
4125 static void
4126 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4127 {
4128     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4129         return;
4130     else if ((hasNsNodes)) {
4131         int i;
4132         xmlNodePtr node;
4133
4134         for (i = pos; i < set->nodeNr; i++) {
4135             node = set->nodeTab[i];
4136             if ((node != NULL) &&
4137                 (node->type == XML_NAMESPACE_DECL))
4138                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4139         }
4140     }
4141     set->nodeNr = pos;
4142 }
4143
4144 /**
4145  * xmlXPathFreeValueTree:
4146  * @obj:  the xmlNodeSetPtr to free
4147  *
4148  * Free the NodeSet compound and the actual tree, this is different
4149  * from xmlXPathFreeNodeSet()
4150  */
4151 static void
4152 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4153     int i;
4154
4155     if (obj == NULL) return;
4156
4157     if (obj->nodeTab != NULL) {
4158         for (i = 0;i < obj->nodeNr;i++) {
4159             if (obj->nodeTab[i] != NULL) {
4160                 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4161                     xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4162                 } else {
4163                     xmlFreeNodeList(obj->nodeTab[i]);
4164                 }
4165             }
4166         }
4167         xmlFree(obj->nodeTab);
4168     }
4169     xmlFree(obj);
4170 }
4171
4172 #if defined(DEBUG) || defined(DEBUG_STEP)
4173 /**
4174  * xmlGenericErrorContextNodeSet:
4175  * @output:  a FILE * for the output
4176  * @obj:  the xmlNodeSetPtr to display
4177  *
4178  * Quick display of a NodeSet
4179  */
4180 void
4181 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4182     int i;
4183
4184     if (output == NULL) output = xmlGenericErrorContext;
4185     if (obj == NULL)  {
4186         fprintf(output, "NodeSet == NULL !\n");
4187         return;
4188     }
4189     if (obj->nodeNr == 0) {
4190         fprintf(output, "NodeSet is empty\n");
4191         return;
4192     }
4193     if (obj->nodeTab == NULL) {
4194         fprintf(output, " nodeTab == NULL !\n");
4195         return;
4196     }
4197     for (i = 0; i < obj->nodeNr; i++) {
4198         if (obj->nodeTab[i] == NULL) {
4199             fprintf(output, " NULL !\n");
4200             return;
4201         }
4202         if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4203             (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4204             fprintf(output, " /");
4205         else if (obj->nodeTab[i]->name == NULL)
4206             fprintf(output, " noname!");
4207         else fprintf(output, " %s", obj->nodeTab[i]->name);
4208     }
4209     fprintf(output, "\n");
4210 }
4211 #endif
4212
4213 /**
4214  * xmlXPathNewNodeSet:
4215  * @val:  the NodePtr value
4216  *
4217  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4218  * it with the single Node @val
4219  *
4220  * Returns the newly created object.
4221  */
4222 xmlXPathObjectPtr
4223 xmlXPathNewNodeSet(xmlNodePtr val) {
4224     xmlXPathObjectPtr ret;
4225
4226     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4227     if (ret == NULL) {
4228         xmlXPathErrMemory(NULL, "creating nodeset\n");
4229         return(NULL);
4230     }
4231     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4232     ret->type = XPATH_NODESET;
4233     ret->boolval = 0;
4234     ret->nodesetval = xmlXPathNodeSetCreate(val);
4235     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4236 #ifdef XP_DEBUG_OBJ_USAGE
4237     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4238 #endif
4239     return(ret);
4240 }
4241
4242 /**
4243  * xmlXPathNewValueTree:
4244  * @val:  the NodePtr value
4245  *
4246  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4247  * it with the tree root @val
4248  *
4249  * Returns the newly created object.
4250  */
4251 xmlXPathObjectPtr
4252 xmlXPathNewValueTree(xmlNodePtr val) {
4253     xmlXPathObjectPtr ret;
4254
4255     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4256     if (ret == NULL) {
4257         xmlXPathErrMemory(NULL, "creating result value tree\n");
4258         return(NULL);
4259     }
4260     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4261     ret->type = XPATH_XSLT_TREE;
4262     ret->boolval = 1;
4263     ret->user = (void *) val;
4264     ret->nodesetval = xmlXPathNodeSetCreate(val);
4265 #ifdef XP_DEBUG_OBJ_USAGE
4266     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4267 #endif
4268     return(ret);
4269 }
4270
4271 /**
4272  * xmlXPathNewNodeSetList:
4273  * @val:  an existing NodeSet
4274  *
4275  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4276  * it with the Nodeset @val
4277  *
4278  * Returns the newly created object.
4279  */
4280 xmlXPathObjectPtr
4281 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4282 {
4283     xmlXPathObjectPtr ret;
4284     int i;
4285
4286     if (val == NULL)
4287         ret = NULL;
4288     else if (val->nodeTab == NULL)
4289         ret = xmlXPathNewNodeSet(NULL);
4290     else {
4291         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4292         if (ret)
4293             for (i = 1; i < val->nodeNr; ++i)
4294                 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4295     }
4296
4297     return (ret);
4298 }
4299
4300 /**
4301  * xmlXPathWrapNodeSet:
4302  * @val:  the NodePtr value
4303  *
4304  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4305  *
4306  * Returns the newly created object.
4307  */
4308 xmlXPathObjectPtr
4309 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4310     xmlXPathObjectPtr ret;
4311
4312     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4313     if (ret == NULL) {
4314         xmlXPathErrMemory(NULL, "creating node set object\n");
4315         return(NULL);
4316     }
4317     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4318     ret->type = XPATH_NODESET;
4319     ret->nodesetval = val;
4320 #ifdef XP_DEBUG_OBJ_USAGE
4321     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4322 #endif
4323     return(ret);
4324 }
4325
4326 /**
4327  * xmlXPathFreeNodeSetList:
4328  * @obj:  an existing NodeSetList object
4329  *
4330  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4331  * the list contrary to xmlXPathFreeObject().
4332  */
4333 void
4334 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4335     if (obj == NULL) return;
4336 #ifdef XP_DEBUG_OBJ_USAGE
4337     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4338 #endif
4339     xmlFree(obj);
4340 }
4341
4342 /**
4343  * xmlXPathDifference:
4344  * @nodes1:  a node-set
4345  * @nodes2:  a node-set
4346  *
4347  * Implements the EXSLT - Sets difference() function:
4348  *    node-set set:difference (node-set, node-set)
4349  *
4350  * Returns the difference between the two node sets, or nodes1 if
4351  *         nodes2 is empty
4352  */
4353 xmlNodeSetPtr
4354 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4355     xmlNodeSetPtr ret;
4356     int i, l1;
4357     xmlNodePtr cur;
4358
4359     if (xmlXPathNodeSetIsEmpty(nodes2))
4360         return(nodes1);
4361
4362     ret = xmlXPathNodeSetCreate(NULL);
4363     if (xmlXPathNodeSetIsEmpty(nodes1))
4364         return(ret);
4365
4366     l1 = xmlXPathNodeSetGetLength(nodes1);
4367
4368     for (i = 0; i < l1; i++) {
4369         cur = xmlXPathNodeSetItem(nodes1, i);
4370         if (!xmlXPathNodeSetContains(nodes2, cur))
4371             xmlXPathNodeSetAddUnique(ret, cur);
4372     }
4373     return(ret);
4374 }
4375
4376 /**
4377  * xmlXPathIntersection:
4378  * @nodes1:  a node-set
4379  * @nodes2:  a node-set
4380  *
4381  * Implements the EXSLT - Sets intersection() function:
4382  *    node-set set:intersection (node-set, node-set)
4383  *
4384  * Returns a node set comprising the nodes that are within both the
4385  *         node sets passed as arguments
4386  */
4387 xmlNodeSetPtr
4388 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4389     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4390     int i, l1;
4391     xmlNodePtr cur;
4392
4393     if (ret == NULL)
4394         return(ret);
4395     if (xmlXPathNodeSetIsEmpty(nodes1))
4396         return(ret);
4397     if (xmlXPathNodeSetIsEmpty(nodes2))
4398         return(ret);
4399
4400     l1 = xmlXPathNodeSetGetLength(nodes1);
4401
4402     for (i = 0; i < l1; i++) {
4403         cur = xmlXPathNodeSetItem(nodes1, i);
4404         if (xmlXPathNodeSetContains(nodes2, cur))
4405             xmlXPathNodeSetAddUnique(ret, cur);
4406     }
4407     return(ret);
4408 }
4409
4410 /**
4411  * xmlXPathDistinctSorted:
4412  * @nodes:  a node-set, sorted by document order
4413  *
4414  * Implements the EXSLT - Sets distinct() function:
4415  *    node-set set:distinct (node-set)
4416  *
4417  * Returns a subset of the nodes contained in @nodes, or @nodes if
4418  *         it is empty
4419  */
4420 xmlNodeSetPtr
4421 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4422     xmlNodeSetPtr ret;
4423     xmlHashTablePtr hash;
4424     int i, l;
4425     xmlChar * strval;
4426     xmlNodePtr cur;
4427
4428     if (xmlXPathNodeSetIsEmpty(nodes))
4429         return(nodes);
4430
4431     ret = xmlXPathNodeSetCreate(NULL);
4432     if (ret == NULL)
4433         return(ret);
4434     l = xmlXPathNodeSetGetLength(nodes);
4435     hash = xmlHashCreate (l);
4436     for (i = 0; i < l; i++) {
4437         cur = xmlXPathNodeSetItem(nodes, i);
4438         strval = xmlXPathCastNodeToString(cur);
4439         if (xmlHashLookup(hash, strval) == NULL) {
4440             xmlHashAddEntry(hash, strval, strval);
4441             xmlXPathNodeSetAddUnique(ret, cur);
4442         } else {
4443             xmlFree(strval);
4444         }
4445     }
4446     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4447     return(ret);
4448 }
4449
4450 /**
4451  * xmlXPathDistinct:
4452  * @nodes:  a node-set
4453  *
4454  * Implements the EXSLT - Sets distinct() function:
4455  *    node-set set:distinct (node-set)
4456  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4457  * is called with the sorted node-set
4458  *
4459  * Returns a subset of the nodes contained in @nodes, or @nodes if
4460  *         it is empty
4461  */
4462 xmlNodeSetPtr
4463 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4464     if (xmlXPathNodeSetIsEmpty(nodes))
4465         return(nodes);
4466
4467     xmlXPathNodeSetSort(nodes);
4468     return(xmlXPathDistinctSorted(nodes));
4469 }
4470
4471 /**
4472  * xmlXPathHasSameNodes:
4473  * @nodes1:  a node-set
4474  * @nodes2:  a node-set
4475  *
4476  * Implements the EXSLT - Sets has-same-nodes function:
4477  *    boolean set:has-same-node(node-set, node-set)
4478  *
4479  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4480  *         otherwise
4481  */
4482 int
4483 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4484     int i, l;
4485     xmlNodePtr cur;
4486
4487     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4488         xmlXPathNodeSetIsEmpty(nodes2))
4489         return(0);
4490
4491     l = xmlXPathNodeSetGetLength(nodes1);
4492     for (i = 0; i < l; i++) {
4493         cur = xmlXPathNodeSetItem(nodes1, i);
4494         if (xmlXPathNodeSetContains(nodes2, cur))
4495             return(1);
4496     }
4497     return(0);
4498 }
4499
4500 /**
4501  * xmlXPathNodeLeadingSorted:
4502  * @nodes: a node-set, sorted by document order
4503  * @node: a node
4504  *
4505  * Implements the EXSLT - Sets leading() function:
4506  *    node-set set:leading (node-set, node-set)
4507  *
4508  * Returns the nodes in @nodes that precede @node in document order,
4509  *         @nodes if @node is NULL or an empty node-set if @nodes
4510  *         doesn't contain @node
4511  */
4512 xmlNodeSetPtr
4513 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4514     int i, l;
4515     xmlNodePtr cur;
4516     xmlNodeSetPtr ret;
4517
4518     if (node == NULL)
4519         return(nodes);
4520
4521     ret = xmlXPathNodeSetCreate(NULL);
4522     if (ret == NULL)
4523         return(ret);
4524     if (xmlXPathNodeSetIsEmpty(nodes) ||
4525         (!xmlXPathNodeSetContains(nodes, node)))
4526         return(ret);
4527
4528     l = xmlXPathNodeSetGetLength(nodes);
4529     for (i = 0; i < l; i++) {
4530         cur = xmlXPathNodeSetItem(nodes, i);
4531         if (cur == node)
4532             break;
4533         xmlXPathNodeSetAddUnique(ret, cur);
4534     }
4535     return(ret);
4536 }
4537
4538 /**
4539  * xmlXPathNodeLeading:
4540  * @nodes:  a node-set
4541  * @node:  a node
4542  *
4543  * Implements the EXSLT - Sets leading() function:
4544  *    node-set set:leading (node-set, node-set)
4545  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4546  * is called.
4547  *
4548  * Returns the nodes in @nodes that precede @node in document order,
4549  *         @nodes if @node is NULL or an empty node-set if @nodes
4550  *         doesn't contain @node
4551  */
4552 xmlNodeSetPtr
4553 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4554     xmlXPathNodeSetSort(nodes);
4555     return(xmlXPathNodeLeadingSorted(nodes, node));
4556 }
4557
4558 /**
4559  * xmlXPathLeadingSorted:
4560  * @nodes1:  a node-set, sorted by document order
4561  * @nodes2:  a node-set, sorted by document order
4562  *
4563  * Implements the EXSLT - Sets leading() function:
4564  *    node-set set:leading (node-set, node-set)
4565  *
4566  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4567  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4568  *         an empty node-set if @nodes1 doesn't contain @nodes2
4569  */
4570 xmlNodeSetPtr
4571 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4572     if (xmlXPathNodeSetIsEmpty(nodes2))
4573         return(nodes1);
4574     return(xmlXPathNodeLeadingSorted(nodes1,
4575                                      xmlXPathNodeSetItem(nodes2, 1)));
4576 }
4577
4578 /**
4579  * xmlXPathLeading:
4580  * @nodes1:  a node-set
4581  * @nodes2:  a node-set
4582  *
4583  * Implements the EXSLT - Sets leading() function:
4584  *    node-set set:leading (node-set, node-set)
4585  * @nodes1 and @nodes2 are sorted by document order, then
4586  * #exslSetsLeadingSorted is called.
4587  *
4588  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4589  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4590  *         an empty node-set if @nodes1 doesn't contain @nodes2
4591  */
4592 xmlNodeSetPtr
4593 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4594     if (xmlXPathNodeSetIsEmpty(nodes2))
4595         return(nodes1);
4596     if (xmlXPathNodeSetIsEmpty(nodes1))
4597         return(xmlXPathNodeSetCreate(NULL));
4598     xmlXPathNodeSetSort(nodes1);
4599     xmlXPathNodeSetSort(nodes2);
4600     return(xmlXPathNodeLeadingSorted(nodes1,
4601                                      xmlXPathNodeSetItem(nodes2, 1)));
4602 }
4603
4604 /**
4605  * xmlXPathNodeTrailingSorted:
4606  * @nodes: a node-set, sorted by document order
4607  * @node: a node
4608  *
4609  * Implements the EXSLT - Sets trailing() function:
4610  *    node-set set:trailing (node-set, node-set)
4611  *
4612  * Returns the nodes in @nodes that follow @node in document order,
4613  *         @nodes if @node is NULL or an empty node-set if @nodes
4614  *         doesn't contain @node
4615  */
4616 xmlNodeSetPtr
4617 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4618     int i, l;
4619     xmlNodePtr cur;
4620     xmlNodeSetPtr ret;
4621
4622     if (node == NULL)
4623         return(nodes);
4624
4625     ret = xmlXPathNodeSetCreate(NULL);
4626     if (ret == NULL)
4627         return(ret);
4628     if (xmlXPathNodeSetIsEmpty(nodes) ||
4629         (!xmlXPathNodeSetContains(nodes, node)))
4630         return(ret);
4631
4632     l = xmlXPathNodeSetGetLength(nodes);
4633     for (i = l - 1; i >= 0; i--) {
4634         cur = xmlXPathNodeSetItem(nodes, i);
4635         if (cur == node)
4636             break;
4637         xmlXPathNodeSetAddUnique(ret, cur);
4638     }
4639     xmlXPathNodeSetSort(ret);   /* bug 413451 */
4640     return(ret);
4641 }
4642
4643 /**
4644  * xmlXPathNodeTrailing:
4645  * @nodes:  a node-set
4646  * @node:  a node
4647  *
4648  * Implements the EXSLT - Sets trailing() function:
4649  *    node-set set:trailing (node-set, node-set)
4650  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4651  * is called.
4652  *
4653  * Returns the nodes in @nodes that follow @node in document order,
4654  *         @nodes if @node is NULL or an empty node-set if @nodes
4655  *         doesn't contain @node
4656  */
4657 xmlNodeSetPtr
4658 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4659     xmlXPathNodeSetSort(nodes);
4660     return(xmlXPathNodeTrailingSorted(nodes, node));
4661 }
4662
4663 /**
4664  * xmlXPathTrailingSorted:
4665  * @nodes1:  a node-set, sorted by document order
4666  * @nodes2:  a node-set, sorted by document order
4667  *
4668  * Implements the EXSLT - Sets trailing() function:
4669  *    node-set set:trailing (node-set, node-set)
4670  *
4671  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4672  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4673  *         an empty node-set if @nodes1 doesn't contain @nodes2
4674  */
4675 xmlNodeSetPtr
4676 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4677     if (xmlXPathNodeSetIsEmpty(nodes2))
4678         return(nodes1);
4679     return(xmlXPathNodeTrailingSorted(nodes1,
4680                                       xmlXPathNodeSetItem(nodes2, 0)));
4681 }
4682
4683 /**
4684  * xmlXPathTrailing:
4685  * @nodes1:  a node-set
4686  * @nodes2:  a node-set
4687  *
4688  * Implements the EXSLT - Sets trailing() function:
4689  *    node-set set:trailing (node-set, node-set)
4690  * @nodes1 and @nodes2 are sorted by document order, then
4691  * #xmlXPathTrailingSorted is called.
4692  *
4693  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4694  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4695  *         an empty node-set if @nodes1 doesn't contain @nodes2
4696  */
4697 xmlNodeSetPtr
4698 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4699     if (xmlXPathNodeSetIsEmpty(nodes2))
4700         return(nodes1);
4701     if (xmlXPathNodeSetIsEmpty(nodes1))
4702         return(xmlXPathNodeSetCreate(NULL));
4703     xmlXPathNodeSetSort(nodes1);
4704     xmlXPathNodeSetSort(nodes2);
4705     return(xmlXPathNodeTrailingSorted(nodes1,
4706                                       xmlXPathNodeSetItem(nodes2, 0)));
4707 }
4708
4709 /************************************************************************
4710  *                                                                      *
4711  *              Routines to handle extra functions                      *
4712  *                                                                      *
4713  ************************************************************************/
4714
4715 /**
4716  * xmlXPathRegisterFunc:
4717  * @ctxt:  the XPath context
4718  * @name:  the function name
4719  * @f:  the function implementation or NULL
4720  *
4721  * Register a new function. If @f is NULL it unregisters the function
4722  *
4723  * Returns 0 in case of success, -1 in case of error
4724  */
4725 int
4726 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4727                      xmlXPathFunction f) {
4728     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4729 }
4730
4731 /**
4732  * xmlXPathRegisterFuncNS:
4733  * @ctxt:  the XPath context
4734  * @name:  the function name
4735  * @ns_uri:  the function namespace URI
4736  * @f:  the function implementation or NULL
4737  *
4738  * Register a new function. If @f is NULL it unregisters the function
4739  *
4740  * Returns 0 in case of success, -1 in case of error
4741  */
4742 int
4743 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4744                        const xmlChar *ns_uri, xmlXPathFunction f) {
4745     if (ctxt == NULL)
4746         return(-1);
4747     if (name == NULL)
4748         return(-1);
4749
4750     if (ctxt->funcHash == NULL)
4751         ctxt->funcHash = xmlHashCreate(0);
4752     if (ctxt->funcHash == NULL)
4753         return(-1);
4754     if (f == NULL)
4755         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4756     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4757 }
4758
4759 /**
4760  * xmlXPathRegisterFuncLookup:
4761  * @ctxt:  the XPath context
4762  * @f:  the lookup function
4763  * @funcCtxt:  the lookup data
4764  *
4765  * Registers an external mechanism to do function lookup.
4766  */
4767 void
4768 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4769                             xmlXPathFuncLookupFunc f,
4770                             void *funcCtxt) {
4771     if (ctxt == NULL)
4772         return;
4773     ctxt->funcLookupFunc = f;
4774     ctxt->funcLookupData = funcCtxt;
4775 }
4776
4777 /**
4778  * xmlXPathFunctionLookup:
4779  * @ctxt:  the XPath context
4780  * @name:  the function name
4781  *
4782  * Search in the Function array of the context for the given
4783  * function.
4784  *
4785  * Returns the xmlXPathFunction or NULL if not found
4786  */
4787 xmlXPathFunction
4788 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4789     if (ctxt == NULL)
4790         return (NULL);
4791
4792     if (ctxt->funcLookupFunc != NULL) {
4793         xmlXPathFunction ret;
4794         xmlXPathFuncLookupFunc f;
4795
4796         f = ctxt->funcLookupFunc;
4797         ret = f(ctxt->funcLookupData, name, NULL);
4798         if (ret != NULL)
4799             return(ret);
4800     }
4801     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4802 }
4803
4804 /**
4805  * xmlXPathFunctionLookupNS:
4806  * @ctxt:  the XPath context
4807  * @name:  the function name
4808  * @ns_uri:  the function namespace URI
4809  *
4810  * Search in the Function array of the context for the given
4811  * function.
4812  *
4813  * Returns the xmlXPathFunction or NULL if not found
4814  */
4815 xmlXPathFunction
4816 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4817                          const xmlChar *ns_uri) {
4818     xmlXPathFunction ret;
4819
4820     if (ctxt == NULL)
4821         return(NULL);
4822     if (name == NULL)
4823         return(NULL);
4824
4825     if (ctxt->funcLookupFunc != NULL) {
4826         xmlXPathFuncLookupFunc f;
4827
4828         f = ctxt->funcLookupFunc;
4829         ret = f(ctxt->funcLookupData, name, ns_uri);
4830         if (ret != NULL)
4831             return(ret);
4832     }
4833
4834     if (ctxt->funcHash == NULL)
4835         return(NULL);
4836
4837     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4838     return(ret);
4839 }
4840
4841 /**
4842  * xmlXPathRegisteredFuncsCleanup:
4843  * @ctxt:  the XPath context
4844  *
4845  * Cleanup the XPath context data associated to registered functions
4846  */
4847 void
4848 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4849     if (ctxt == NULL)
4850         return;
4851
4852     xmlHashFree(ctxt->funcHash, NULL);
4853     ctxt->funcHash = NULL;
4854 }
4855
4856 /************************************************************************
4857  *                                                                      *
4858  *                      Routines to handle Variables                    *
4859  *                                                                      *
4860  ************************************************************************/
4861
4862 /**
4863  * xmlXPathRegisterVariable:
4864  * @ctxt:  the XPath context
4865  * @name:  the variable name
4866  * @value:  the variable value or NULL
4867  *
4868  * Register a new variable value. If @value is NULL it unregisters
4869  * the variable
4870  *
4871  * Returns 0 in case of success, -1 in case of error
4872  */
4873 int
4874 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4875                          xmlXPathObjectPtr value) {
4876     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4877 }
4878
4879 /**
4880  * xmlXPathRegisterVariableNS:
4881  * @ctxt:  the XPath context
4882  * @name:  the variable name
4883  * @ns_uri:  the variable namespace URI
4884  * @value:  the variable value or NULL
4885  *
4886  * Register a new variable value. If @value is NULL it unregisters
4887  * the variable
4888  *
4889  * Returns 0 in case of success, -1 in case of error
4890  */
4891 int
4892 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4893                            const xmlChar *ns_uri,
4894                            xmlXPathObjectPtr value) {
4895     if (ctxt == NULL)
4896         return(-1);
4897     if (name == NULL)
4898         return(-1);
4899
4900     if (ctxt->varHash == NULL)
4901         ctxt->varHash = xmlHashCreate(0);
4902     if (ctxt->varHash == NULL)
4903         return(-1);
4904     if (value == NULL)
4905         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4906                                    (xmlHashDeallocator)xmlXPathFreeObject));
4907     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4908                                (void *) value,
4909                                (xmlHashDeallocator)xmlXPathFreeObject));
4910 }
4911
4912 /**
4913  * xmlXPathRegisterVariableLookup:
4914  * @ctxt:  the XPath context
4915  * @f:  the lookup function
4916  * @data:  the lookup data
4917  *
4918  * register an external mechanism to do variable lookup
4919  */
4920 void
4921 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4922          xmlXPathVariableLookupFunc f, void *data) {
4923     if (ctxt == NULL)
4924         return;
4925     ctxt->varLookupFunc = f;
4926     ctxt->varLookupData = data;
4927 }
4928
4929 /**
4930  * xmlXPathVariableLookup:
4931  * @ctxt:  the XPath context
4932  * @name:  the variable name
4933  *
4934  * Search in the Variable array of the context for the given
4935  * variable value.
4936  *
4937  * Returns a copy of the value or NULL if not found
4938  */
4939 xmlXPathObjectPtr
4940 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4941     if (ctxt == NULL)
4942         return(NULL);
4943
4944     if (ctxt->varLookupFunc != NULL) {
4945         xmlXPathObjectPtr ret;
4946
4947         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4948                 (ctxt->varLookupData, name, NULL);
4949         return(ret);
4950     }
4951     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4952 }
4953
4954 /**
4955  * xmlXPathVariableLookupNS:
4956  * @ctxt:  the XPath context
4957  * @name:  the variable name
4958  * @ns_uri:  the variable namespace URI
4959  *
4960  * Search in the Variable array of the context for the given
4961  * variable value.
4962  *
4963  * Returns the a copy of the value or NULL if not found
4964  */
4965 xmlXPathObjectPtr
4966 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4967                          const xmlChar *ns_uri) {
4968     if (ctxt == NULL)
4969         return(NULL);
4970
4971     if (ctxt->varLookupFunc != NULL) {
4972         xmlXPathObjectPtr ret;
4973
4974         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4975                 (ctxt->varLookupData, name, ns_uri);
4976         if (ret != NULL) return(ret);
4977     }
4978
4979     if (ctxt->varHash == NULL)
4980         return(NULL);
4981     if (name == NULL)
4982         return(NULL);
4983
4984     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
4985                 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4986 }
4987
4988 /**
4989  * xmlXPathRegisteredVariablesCleanup:
4990  * @ctxt:  the XPath context
4991  *
4992  * Cleanup the XPath context data associated to registered variables
4993  */
4994 void
4995 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4996     if (ctxt == NULL)
4997         return;
4998
4999     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5000     ctxt->varHash = NULL;
5001 }
5002
5003 /**
5004  * xmlXPathRegisterNs:
5005  * @ctxt:  the XPath context
5006  * @prefix:  the namespace prefix cannot be NULL or empty string
5007  * @ns_uri:  the namespace name
5008  *
5009  * Register a new namespace. If @ns_uri is NULL it unregisters
5010  * the namespace
5011  *
5012  * Returns 0 in case of success, -1 in case of error
5013  */
5014 int
5015 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5016                            const xmlChar *ns_uri) {
5017     if (ctxt == NULL)
5018         return(-1);
5019     if (prefix == NULL)
5020         return(-1);
5021     if (prefix[0] == 0)
5022         return(-1);
5023
5024     if (ctxt->nsHash == NULL)
5025         ctxt->nsHash = xmlHashCreate(10);
5026     if (ctxt->nsHash == NULL)
5027         return(-1);
5028     if (ns_uri == NULL)
5029         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5030                                   (xmlHashDeallocator)xmlFree));
5031     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5032                               (xmlHashDeallocator)xmlFree));
5033 }
5034
5035 /**
5036  * xmlXPathNsLookup:
5037  * @ctxt:  the XPath context
5038  * @prefix:  the namespace prefix value
5039  *
5040  * Search in the namespace declaration array of the context for the given
5041  * namespace name associated to the given prefix
5042  *
5043  * Returns the value or NULL if not found
5044  */
5045 const xmlChar *
5046 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5047     if (ctxt == NULL)
5048         return(NULL);
5049     if (prefix == NULL)
5050         return(NULL);
5051
5052 #ifdef XML_XML_NAMESPACE
5053     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5054         return(XML_XML_NAMESPACE);
5055 #endif
5056
5057     if (ctxt->namespaces != NULL) {
5058         int i;
5059
5060         for (i = 0;i < ctxt->nsNr;i++) {
5061             if ((ctxt->namespaces[i] != NULL) &&
5062                 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5063                 return(ctxt->namespaces[i]->href);
5064         }
5065     }
5066
5067     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5068 }
5069
5070 /**
5071  * xmlXPathRegisteredNsCleanup:
5072  * @ctxt:  the XPath context
5073  *
5074  * Cleanup the XPath context data associated to registered variables
5075  */
5076 void
5077 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5078     if (ctxt == NULL)
5079         return;
5080
5081     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5082     ctxt->nsHash = NULL;
5083 }
5084
5085 /************************************************************************
5086  *                                                                      *
5087  *                      Routines to handle Values                       *
5088  *                                                                      *
5089  ************************************************************************/
5090
5091 /* Allocations are terrible, one needs to optimize all this !!! */
5092
5093 /**
5094  * xmlXPathNewFloat:
5095  * @val:  the double value
5096  *
5097  * Create a new xmlXPathObjectPtr of type double and of value @val
5098  *
5099  * Returns the newly created object.
5100  */
5101 xmlXPathObjectPtr
5102 xmlXPathNewFloat(double val) {
5103     xmlXPathObjectPtr ret;
5104
5105     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5106     if (ret == NULL) {
5107         xmlXPathErrMemory(NULL, "creating float object\n");
5108         return(NULL);
5109     }
5110     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5111     ret->type = XPATH_NUMBER;
5112     ret->floatval = val;
5113 #ifdef XP_DEBUG_OBJ_USAGE
5114     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5115 #endif
5116     return(ret);
5117 }
5118
5119 /**
5120  * xmlXPathNewBoolean:
5121  * @val:  the boolean value
5122  *
5123  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5124  *
5125  * Returns the newly created object.
5126  */
5127 xmlXPathObjectPtr
5128 xmlXPathNewBoolean(int val) {
5129     xmlXPathObjectPtr ret;
5130
5131     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5132     if (ret == NULL) {
5133         xmlXPathErrMemory(NULL, "creating boolean object\n");
5134         return(NULL);
5135     }
5136     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5137     ret->type = XPATH_BOOLEAN;
5138     ret->boolval = (val != 0);
5139 #ifdef XP_DEBUG_OBJ_USAGE
5140     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5141 #endif
5142     return(ret);
5143 }
5144
5145 /**
5146  * xmlXPathNewString:
5147  * @val:  the xmlChar * value
5148  *
5149  * Create a new xmlXPathObjectPtr of type string and of value @val
5150  *
5151  * Returns the newly created object.
5152  */
5153 xmlXPathObjectPtr
5154 xmlXPathNewString(const xmlChar *val) {
5155     xmlXPathObjectPtr ret;
5156
5157     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5158     if (ret == NULL) {
5159         xmlXPathErrMemory(NULL, "creating string object\n");
5160         return(NULL);
5161     }
5162     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5163     ret->type = XPATH_STRING;
5164     if (val != NULL)
5165         ret->stringval = xmlStrdup(val);
5166     else
5167         ret->stringval = xmlStrdup((const xmlChar *)"");
5168 #ifdef XP_DEBUG_OBJ_USAGE
5169     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5170 #endif
5171     return(ret);
5172 }
5173
5174 /**
5175  * xmlXPathWrapString:
5176  * @val:  the xmlChar * value
5177  *
5178  * Wraps the @val string into an XPath object.
5179  *
5180  * Returns the newly created object.
5181  */
5182 xmlXPathObjectPtr
5183 xmlXPathWrapString (xmlChar *val) {
5184     xmlXPathObjectPtr ret;
5185
5186     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5187     if (ret == NULL) {
5188         xmlXPathErrMemory(NULL, "creating string object\n");
5189         return(NULL);
5190     }
5191     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5192     ret->type = XPATH_STRING;
5193     ret->stringval = val;
5194 #ifdef XP_DEBUG_OBJ_USAGE
5195     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5196 #endif
5197     return(ret);
5198 }
5199
5200 /**
5201  * xmlXPathNewCString:
5202  * @val:  the char * value
5203  *
5204  * Create a new xmlXPathObjectPtr of type string and of value @val
5205  *
5206  * Returns the newly created object.
5207  */
5208 xmlXPathObjectPtr
5209 xmlXPathNewCString(const char *val) {
5210     xmlXPathObjectPtr ret;
5211
5212     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5213     if (ret == NULL) {
5214         xmlXPathErrMemory(NULL, "creating string object\n");
5215         return(NULL);
5216     }
5217     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5218     ret->type = XPATH_STRING;
5219     ret->stringval = xmlStrdup(BAD_CAST val);
5220 #ifdef XP_DEBUG_OBJ_USAGE
5221     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5222 #endif
5223     return(ret);
5224 }
5225
5226 /**
5227  * xmlXPathWrapCString:
5228  * @val:  the char * value
5229  *
5230  * Wraps a string into an XPath object.
5231  *
5232  * Returns the newly created object.
5233  */
5234 xmlXPathObjectPtr
5235 xmlXPathWrapCString (char * val) {
5236     return(xmlXPathWrapString((xmlChar *)(val)));
5237 }
5238
5239 /**
5240  * xmlXPathWrapExternal:
5241  * @val:  the user data
5242  *
5243  * Wraps the @val data into an XPath object.
5244  *
5245  * Returns the newly created object.
5246  */
5247 xmlXPathObjectPtr
5248 xmlXPathWrapExternal (void *val) {
5249     xmlXPathObjectPtr ret;
5250
5251     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5252     if (ret == NULL) {
5253         xmlXPathErrMemory(NULL, "creating user object\n");
5254         return(NULL);
5255     }
5256     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5257     ret->type = XPATH_USERS;
5258     ret->user = val;
5259 #ifdef XP_DEBUG_OBJ_USAGE
5260     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5261 #endif
5262     return(ret);
5263 }
5264
5265 /**
5266  * xmlXPathObjectCopy:
5267  * @val:  the original object
5268  *
5269  * allocate a new copy of a given object
5270  *
5271  * Returns the newly created object.
5272  */
5273 xmlXPathObjectPtr
5274 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5275     xmlXPathObjectPtr ret;
5276
5277     if (val == NULL)
5278         return(NULL);
5279
5280     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5281     if (ret == NULL) {
5282         xmlXPathErrMemory(NULL, "copying object\n");
5283         return(NULL);
5284     }
5285     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5286 #ifdef XP_DEBUG_OBJ_USAGE
5287     xmlXPathDebugObjUsageRequested(NULL, val->type);
5288 #endif
5289     switch (val->type) {
5290         case XPATH_BOOLEAN:
5291         case XPATH_NUMBER:
5292         case XPATH_POINT:
5293         case XPATH_RANGE:
5294             break;
5295         case XPATH_STRING:
5296             ret->stringval = xmlStrdup(val->stringval);
5297             break;
5298         case XPATH_XSLT_TREE:
5299 #if 0
5300 /*
5301   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5302   this previous handling is no longer correct, and can cause some serious
5303   problems (ref. bug 145547)
5304 */
5305             if ((val->nodesetval != NULL) &&
5306                 (val->nodesetval->nodeTab != NULL)) {
5307                 xmlNodePtr cur, tmp;
5308                 xmlDocPtr top;
5309
5310                 ret->boolval = 1;
5311                 top =  xmlNewDoc(NULL);
5312                 top->name = (char *)
5313                     xmlStrdup(val->nodesetval->nodeTab[0]->name);
5314                 ret->user = top;
5315                 if (top != NULL) {
5316                     top->doc = top;
5317                     cur = val->nodesetval->nodeTab[0]->children;
5318                     while (cur != NULL) {
5319                         tmp = xmlDocCopyNode(cur, top, 1);
5320                         xmlAddChild((xmlNodePtr) top, tmp);
5321                         cur = cur->next;
5322                     }
5323                 }
5324
5325                 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5326             } else
5327                 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5328             /* Deallocate the copied tree value */
5329             break;
5330 #endif
5331         case XPATH_NODESET:
5332             ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5333             /* Do not deallocate the copied tree value */
5334             ret->boolval = 0;
5335             break;
5336         case XPATH_LOCATIONSET:
5337 #ifdef LIBXML_XPTR_ENABLED
5338         {
5339             xmlLocationSetPtr loc = val->user;
5340             ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5341             break;
5342         }
5343 #endif
5344         case XPATH_USERS:
5345             ret->user = val->user;
5346             break;
5347         case XPATH_UNDEFINED:
5348             xmlGenericError(xmlGenericErrorContext,
5349                     "xmlXPathObjectCopy: unsupported type %d\n",
5350                     val->type);
5351             break;
5352     }
5353     return(ret);
5354 }
5355
5356 /**
5357  * xmlXPathFreeObject:
5358  * @obj:  the object to free
5359  *
5360  * Free up an xmlXPathObjectPtr object.
5361  */
5362 void
5363 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5364     if (obj == NULL) return;
5365     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5366         if (obj->boolval) {
5367 #if 0
5368             if (obj->user != NULL) {
5369                 xmlXPathFreeNodeSet(obj->nodesetval);
5370                 xmlFreeNodeList((xmlNodePtr) obj->user);
5371             } else
5372 #endif
5373             obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5374             if (obj->nodesetval != NULL)
5375                 xmlXPathFreeValueTree(obj->nodesetval);
5376         } else {
5377             if (obj->nodesetval != NULL)
5378                 xmlXPathFreeNodeSet(obj->nodesetval);
5379         }
5380 #ifdef LIBXML_XPTR_ENABLED
5381     } else if (obj->type == XPATH_LOCATIONSET) {
5382         if (obj->user != NULL)
5383             xmlXPtrFreeLocationSet(obj->user);
5384 #endif
5385     } else if (obj->type == XPATH_STRING) {
5386         if (obj->stringval != NULL)
5387             xmlFree(obj->stringval);
5388     }
5389 #ifdef XP_DEBUG_OBJ_USAGE
5390     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5391 #endif
5392     xmlFree(obj);
5393 }
5394
5395 /**
5396  * xmlXPathReleaseObject:
5397  * @obj:  the xmlXPathObjectPtr to free or to cache
5398  *
5399  * Depending on the state of the cache this frees the given
5400  * XPath object or stores it in the cache.
5401  */
5402 static void
5403 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5404 {
5405 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5406         sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5407     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5408
5409 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5410
5411     if (obj == NULL)
5412         return;
5413     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5414          xmlXPathFreeObject(obj);
5415     } else {
5416         xmlXPathContextCachePtr cache =
5417             (xmlXPathContextCachePtr) ctxt->cache;
5418
5419         switch (obj->type) {
5420             case XPATH_NODESET:
5421             case XPATH_XSLT_TREE:
5422                 if (obj->nodesetval != NULL) {
5423                     if (obj->boolval) {
5424                         /*
5425                         * It looks like the @boolval is used for
5426                         * evaluation if this an XSLT Result Tree Fragment.
5427                         * TODO: Check if this assumption is correct.
5428                         */
5429                         obj->type = XPATH_XSLT_TREE; /* just for debugging */
5430                         xmlXPathFreeValueTree(obj->nodesetval);
5431                         obj->nodesetval = NULL;
5432                     } else if ((obj->nodesetval->nodeMax <= 40) &&
5433                         (XP_CACHE_WANTS(cache->nodesetObjs,
5434                                         cache->maxNodeset)))
5435                     {
5436                         XP_CACHE_ADD(cache->nodesetObjs, obj);
5437                         goto obj_cached;
5438                     } else {
5439                         xmlXPathFreeNodeSet(obj->nodesetval);
5440                         obj->nodesetval = NULL;
5441                     }
5442                 }
5443                 break;
5444             case XPATH_STRING:
5445                 if (obj->stringval != NULL)
5446                     xmlFree(obj->stringval);
5447
5448                 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5449                     XP_CACHE_ADD(cache->stringObjs, obj);
5450                     goto obj_cached;
5451                 }
5452                 break;
5453             case XPATH_BOOLEAN:
5454                 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5455                     XP_CACHE_ADD(cache->booleanObjs, obj);
5456                     goto obj_cached;
5457                 }
5458                 break;
5459             case XPATH_NUMBER:
5460                 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5461                     XP_CACHE_ADD(cache->numberObjs, obj);
5462                     goto obj_cached;
5463                 }
5464                 break;
5465 #ifdef LIBXML_XPTR_ENABLED
5466             case XPATH_LOCATIONSET:
5467                 if (obj->user != NULL) {
5468                     xmlXPtrFreeLocationSet(obj->user);
5469                 }
5470                 goto free_obj;
5471 #endif
5472             default:
5473                 goto free_obj;
5474         }
5475
5476         /*
5477         * Fallback to adding to the misc-objects slot.
5478         */
5479         if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5480             XP_CACHE_ADD(cache->miscObjs, obj);
5481         } else
5482             goto free_obj;
5483
5484 obj_cached:
5485
5486 #ifdef XP_DEBUG_OBJ_USAGE
5487         xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5488 #endif
5489
5490         if (obj->nodesetval != NULL) {
5491             xmlNodeSetPtr tmpset = obj->nodesetval;
5492
5493             /*
5494             * TODO: Due to those nasty ns-nodes, we need to traverse
5495             *  the list and free the ns-nodes.
5496             * URGENT TODO: Check if it's actually slowing things down.
5497             *  Maybe we shouldn't try to preserve the list.
5498             */
5499             if (tmpset->nodeNr > 1) {
5500                 int i;
5501                 xmlNodePtr node;
5502
5503                 for (i = 0; i < tmpset->nodeNr; i++) {
5504                     node = tmpset->nodeTab[i];
5505                     if ((node != NULL) &&
5506                         (node->type == XML_NAMESPACE_DECL))
5507                     {
5508                         xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5509                     }
5510                 }
5511             } else if (tmpset->nodeNr == 1) {
5512                 if ((tmpset->nodeTab[0] != NULL) &&
5513                     (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5514                     xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5515             }
5516             tmpset->nodeNr = 0;
5517             memset(obj, 0, sizeof(xmlXPathObject));
5518             obj->nodesetval = tmpset;
5519         } else
5520             memset(obj, 0, sizeof(xmlXPathObject));
5521
5522         return;
5523
5524 free_obj:
5525         /*
5526         * Cache is full; free the object.
5527         */
5528         if (obj->nodesetval != NULL)
5529             xmlXPathFreeNodeSet(obj->nodesetval);
5530 #ifdef XP_DEBUG_OBJ_USAGE
5531         xmlXPathDebugObjUsageReleased(NULL, obj->type);
5532 #endif
5533         xmlFree(obj);
5534     }
5535     return;
5536 }
5537
5538
5539 /************************************************************************
5540  *                                                                      *
5541  *                      Type Casting Routines                           *
5542  *                                                                      *
5543  ************************************************************************/
5544
5545 /**
5546  * xmlXPathCastBooleanToString:
5547  * @val:  a boolean
5548  *
5549  * Converts a boolean to its string value.
5550  *
5551  * Returns a newly allocated string.
5552  */
5553 xmlChar *
5554 xmlXPathCastBooleanToString (int val) {
5555     xmlChar *ret;
5556     if (val)
5557         ret = xmlStrdup((const xmlChar *) "true");
5558     else
5559         ret = xmlStrdup((const xmlChar *) "false");
5560     return(ret);
5561 }
5562
5563 /**
5564  * xmlXPathCastNumberToString:
5565  * @val:  a number
5566  *
5567  * Converts a number to its string value.
5568  *
5569  * Returns a newly allocated string.
5570  */
5571 xmlChar *
5572 xmlXPathCastNumberToString (double val) {
5573     xmlChar *ret;
5574     switch (xmlXPathIsInf(val)) {
5575     case 1:
5576         ret = xmlStrdup((const xmlChar *) "Infinity");
5577         break;
5578     case -1:
5579         ret = xmlStrdup((const xmlChar *) "-Infinity");
5580         break;
5581     default:
5582         if (xmlXPathIsNaN(val)) {
5583             ret = xmlStrdup((const xmlChar *) "NaN");
5584         } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5585             ret = xmlStrdup((const xmlChar *) "0");
5586         } else {
5587             /* could be improved */
5588             char buf[100];
5589             xmlXPathFormatNumber(val, buf, 99);
5590             buf[99] = 0;
5591             ret = xmlStrdup((const xmlChar *) buf);
5592         }
5593     }
5594     return(ret);
5595 }
5596
5597 /**
5598  * xmlXPathCastNodeToString:
5599  * @node:  a node
5600  *
5601  * Converts a node to its string value.
5602  *
5603  * Returns a newly allocated string.
5604  */
5605 xmlChar *
5606 xmlXPathCastNodeToString (xmlNodePtr node) {
5607 xmlChar *ret;
5608     if ((ret = xmlNodeGetContent(node)) == NULL)
5609         ret = xmlStrdup((const xmlChar *) "");
5610     return(ret);
5611 }
5612
5613 /**
5614  * xmlXPathCastNodeSetToString:
5615  * @ns:  a node-set
5616  *
5617  * Converts a node-set to its string value.
5618  *
5619  * Returns a newly allocated string.
5620  */
5621 xmlChar *
5622 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5623     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5624         return(xmlStrdup((const xmlChar *) ""));
5625
5626     if (ns->nodeNr > 1)
5627         xmlXPathNodeSetSort(ns);
5628     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5629 }
5630
5631 /**
5632  * xmlXPathCastToString:
5633  * @val:  an XPath object
5634  *
5635  * Converts an existing object to its string() equivalent
5636  *
5637  * Returns the allocated string value of the object, NULL in case of error.
5638  *         It's up to the caller to free the string memory with xmlFree().
5639  */
5640 xmlChar *
5641 xmlXPathCastToString(xmlXPathObjectPtr val) {
5642     xmlChar *ret = NULL;
5643
5644     if (val == NULL)
5645         return(xmlStrdup((const xmlChar *) ""));
5646     switch (val->type) {
5647         case XPATH_UNDEFINED:
5648 #ifdef DEBUG_EXPR
5649             xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5650 #endif
5651             ret = xmlStrdup((const xmlChar *) "");
5652             break;
5653         case XPATH_NODESET:
5654         case XPATH_XSLT_TREE:
5655             ret = xmlXPathCastNodeSetToString(val->nodesetval);
5656             break;
5657         case XPATH_STRING:
5658             return(xmlStrdup(val->stringval));
5659         case XPATH_BOOLEAN:
5660             ret = xmlXPathCastBooleanToString(val->boolval);
5661             break;
5662         case XPATH_NUMBER: {
5663             ret = xmlXPathCastNumberToString(val->floatval);
5664             break;
5665         }
5666         case XPATH_USERS:
5667         case XPATH_POINT:
5668         case XPATH_RANGE:
5669         case XPATH_LOCATIONSET:
5670             TODO
5671             ret = xmlStrdup((const xmlChar *) "");
5672             break;
5673     }
5674     return(ret);
5675 }
5676
5677 /**
5678  * xmlXPathConvertString:
5679  * @val:  an XPath object
5680  *
5681  * Converts an existing object to its string() equivalent
5682  *
5683  * Returns the new object, the old one is freed (or the operation
5684  *         is done directly on @val)
5685  */
5686 xmlXPathObjectPtr
5687 xmlXPathConvertString(xmlXPathObjectPtr val) {
5688     xmlChar *res = NULL;
5689
5690     if (val == NULL)
5691         return(xmlXPathNewCString(""));
5692
5693     switch (val->type) {
5694     case XPATH_UNDEFINED:
5695 #ifdef DEBUG_EXPR
5696         xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5697 #endif
5698         break;
5699     case XPATH_NODESET:
5700     case XPATH_XSLT_TREE:
5701         res = xmlXPathCastNodeSetToString(val->nodesetval);
5702         break;
5703     case XPATH_STRING:
5704         return(val);
5705     case XPATH_BOOLEAN:
5706         res = xmlXPathCastBooleanToString(val->boolval);
5707         break;
5708     case XPATH_NUMBER:
5709         res = xmlXPathCastNumberToString(val->floatval);
5710         break;
5711     case XPATH_USERS:
5712     case XPATH_POINT:
5713     case XPATH_RANGE:
5714     case XPATH_LOCATIONSET:
5715         TODO;
5716         break;
5717     }
5718     xmlXPathFreeObject(val);
5719     if (res == NULL)
5720         return(xmlXPathNewCString(""));
5721     return(xmlXPathWrapString(res));
5722 }
5723
5724 /**
5725  * xmlXPathCastBooleanToNumber:
5726  * @val:  a boolean
5727  *
5728  * Converts a boolean to its number value
5729  *
5730  * Returns the number value
5731  */
5732 double
5733 xmlXPathCastBooleanToNumber(int val) {
5734     if (val)
5735         return(1.0);
5736     return(0.0);
5737 }
5738
5739 /**
5740  * xmlXPathCastStringToNumber:
5741  * @val:  a string
5742  *
5743  * Converts a string to its number value
5744  *
5745  * Returns the number value
5746  */
5747 double
5748 xmlXPathCastStringToNumber(const xmlChar * val) {
5749     return(xmlXPathStringEvalNumber(val));
5750 }
5751
5752 /**
5753  * xmlXPathCastNodeToNumber:
5754  * @node:  a node
5755  *
5756  * Converts a node to its number value
5757  *
5758  * Returns the number value
5759  */
5760 double
5761 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5762     xmlChar *strval;
5763     double ret;
5764
5765     if (node == NULL)
5766         return(xmlXPathNAN);
5767     strval = xmlXPathCastNodeToString(node);
5768     if (strval == NULL)
5769         return(xmlXPathNAN);
5770     ret = xmlXPathCastStringToNumber(strval);
5771     xmlFree(strval);
5772
5773     return(ret);
5774 }
5775
5776 /**
5777  * xmlXPathCastNodeSetToNumber:
5778  * @ns:  a node-set
5779  *
5780  * Converts a node-set to its number value
5781  *
5782  * Returns the number value
5783  */
5784 double
5785 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5786     xmlChar *str;
5787     double ret;
5788
5789     if (ns == NULL)
5790         return(xmlXPathNAN);
5791     str = xmlXPathCastNodeSetToString(ns);
5792     ret = xmlXPathCastStringToNumber(str);
5793     xmlFree(str);
5794     return(ret);
5795 }
5796
5797 /**
5798  * xmlXPathCastToNumber:
5799  * @val:  an XPath object
5800  *
5801  * Converts an XPath object to its number value
5802  *
5803  * Returns the number value
5804  */
5805 double
5806 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5807     double ret = 0.0;
5808
5809     if (val == NULL)
5810         return(xmlXPathNAN);
5811     switch (val->type) {
5812     case XPATH_UNDEFINED:
5813 #ifdef DEGUB_EXPR
5814         xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5815 #endif
5816         ret = xmlXPathNAN;
5817         break;
5818     case XPATH_NODESET:
5819     case XPATH_XSLT_TREE:
5820         ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5821         break;
5822     case XPATH_STRING:
5823         ret = xmlXPathCastStringToNumber(val->stringval);
5824         break;
5825     case XPATH_NUMBER:
5826         ret = val->floatval;
5827         break;
5828     case XPATH_BOOLEAN:
5829         ret = xmlXPathCastBooleanToNumber(val->boolval);
5830         break;
5831     case XPATH_USERS:
5832     case XPATH_POINT:
5833     case XPATH_RANGE:
5834     case XPATH_LOCATIONSET:
5835         TODO;
5836         ret = xmlXPathNAN;
5837         break;
5838     }
5839     return(ret);
5840 }
5841
5842 /**
5843  * xmlXPathConvertNumber:
5844  * @val:  an XPath object
5845  *
5846  * Converts an existing object to its number() equivalent
5847  *
5848  * Returns the new object, the old one is freed (or the operation
5849  *         is done directly on @val)
5850  */
5851 xmlXPathObjectPtr
5852 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5853     xmlXPathObjectPtr ret;
5854
5855     if (val == NULL)
5856         return(xmlXPathNewFloat(0.0));
5857     if (val->type == XPATH_NUMBER)
5858         return(val);
5859     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5860     xmlXPathFreeObject(val);
5861     return(ret);
5862 }
5863
5864 /**
5865  * xmlXPathCastNumberToBoolean:
5866  * @val:  a number
5867  *
5868  * Converts a number to its boolean value
5869  *
5870  * Returns the boolean value
5871  */
5872 int
5873 xmlXPathCastNumberToBoolean (double val) {
5874      if (xmlXPathIsNaN(val) || (val == 0.0))
5875          return(0);
5876      return(1);
5877 }
5878
5879 /**
5880  * xmlXPathCastStringToBoolean:
5881  * @val:  a string
5882  *
5883  * Converts a string to its boolean value
5884  *
5885  * Returns the boolean value
5886  */
5887 int
5888 xmlXPathCastStringToBoolean (const xmlChar *val) {
5889     if ((val == NULL) || (xmlStrlen(val) == 0))
5890         return(0);
5891     return(1);
5892 }
5893
5894 /**
5895  * xmlXPathCastNodeSetToBoolean:
5896  * @ns:  a node-set
5897  *
5898  * Converts a node-set to its boolean value
5899  *
5900  * Returns the boolean value
5901  */
5902 int
5903 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5904     if ((ns == NULL) || (ns->nodeNr == 0))
5905         return(0);
5906     return(1);
5907 }
5908
5909 /**
5910  * xmlXPathCastToBoolean:
5911  * @val:  an XPath object
5912  *
5913  * Converts an XPath object to its boolean value
5914  *
5915  * Returns the boolean value
5916  */
5917 int
5918 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5919     int ret = 0;
5920
5921     if (val == NULL)
5922         return(0);
5923     switch (val->type) {
5924     case XPATH_UNDEFINED:
5925 #ifdef DEBUG_EXPR
5926         xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5927 #endif
5928         ret = 0;
5929         break;
5930     case XPATH_NODESET:
5931     case XPATH_XSLT_TREE:
5932         ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5933         break;
5934     case XPATH_STRING:
5935         ret = xmlXPathCastStringToBoolean(val->stringval);
5936         break;
5937     case XPATH_NUMBER:
5938         ret = xmlXPathCastNumberToBoolean(val->floatval);
5939         break;
5940     case XPATH_BOOLEAN:
5941         ret = val->boolval;
5942         break;
5943     case XPATH_USERS:
5944     case XPATH_POINT:
5945     case XPATH_RANGE:
5946     case XPATH_LOCATIONSET:
5947         TODO;
5948         ret = 0;
5949         break;
5950     }
5951     return(ret);
5952 }
5953
5954
5955 /**
5956  * xmlXPathConvertBoolean:
5957  * @val:  an XPath object
5958  *
5959  * Converts an existing object to its boolean() equivalent
5960  *
5961  * Returns the new object, the old one is freed (or the operation
5962  *         is done directly on @val)
5963  */
5964 xmlXPathObjectPtr
5965 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5966     xmlXPathObjectPtr ret;
5967
5968     if (val == NULL)
5969         return(xmlXPathNewBoolean(0));
5970     if (val->type == XPATH_BOOLEAN)
5971         return(val);
5972     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5973     xmlXPathFreeObject(val);
5974     return(ret);
5975 }
5976
5977 /************************************************************************
5978  *                                                                      *
5979  *              Routines to handle XPath contexts                       *
5980  *                                                                      *
5981  ************************************************************************/
5982
5983 /**
5984  * xmlXPathNewContext:
5985  * @doc:  the XML document
5986  *
5987  * Create a new xmlXPathContext
5988  *
5989  * Returns the xmlXPathContext just allocated. The caller will need to free it.
5990  */
5991 xmlXPathContextPtr
5992 xmlXPathNewContext(xmlDocPtr doc) {
5993     xmlXPathContextPtr ret;
5994
5995     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5996     if (ret == NULL) {
5997         xmlXPathErrMemory(NULL, "creating context\n");
5998         return(NULL);
5999     }
6000     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6001     ret->doc = doc;
6002     ret->node = NULL;
6003
6004     ret->varHash = NULL;
6005
6006     ret->nb_types = 0;
6007     ret->max_types = 0;
6008     ret->types = NULL;
6009
6010     ret->funcHash = xmlHashCreate(0);
6011
6012     ret->nb_axis = 0;
6013     ret->max_axis = 0;
6014     ret->axis = NULL;
6015
6016     ret->nsHash = NULL;
6017     ret->user = NULL;
6018
6019     ret->contextSize = -1;
6020     ret->proximityPosition = -1;
6021
6022 #ifdef XP_DEFAULT_CACHE_ON
6023     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6024         xmlXPathFreeContext(ret);
6025         return(NULL);
6026     }
6027 #endif
6028
6029     xmlXPathRegisterAllFunctions(ret);
6030
6031     return(ret);
6032 }
6033
6034 /**
6035  * xmlXPathFreeContext:
6036  * @ctxt:  the context to free
6037  *
6038  * Free up an xmlXPathContext
6039  */
6040 void
6041 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6042     if (ctxt == NULL) return;
6043
6044     if (ctxt->cache != NULL)
6045         xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6046     xmlXPathRegisteredNsCleanup(ctxt);
6047     xmlXPathRegisteredFuncsCleanup(ctxt);
6048     xmlXPathRegisteredVariablesCleanup(ctxt);
6049     xmlResetError(&ctxt->lastError);
6050     xmlFree(ctxt);
6051 }
6052
6053 /************************************************************************
6054  *                                                                      *
6055  *              Routines to handle XPath parser contexts                *
6056  *                                                                      *
6057  ************************************************************************/
6058
6059 #define CHECK_CTXT(ctxt)                                                \
6060     if (ctxt == NULL) {                                         \
6061         __xmlRaiseError(NULL, NULL, NULL,                               \
6062                 NULL, NULL, XML_FROM_XPATH,                             \
6063                 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6064                 __FILE__, __LINE__,                                     \
6065                 NULL, NULL, NULL, 0, 0,                                 \
6066                 "NULL context pointer\n");                              \
6067         return(NULL);                                                   \
6068     }                                                                   \
6069
6070 #define CHECK_CTXT_NEG(ctxt)                                            \
6071     if (ctxt == NULL) {                                         \
6072         __xmlRaiseError(NULL, NULL, NULL,                               \
6073                 NULL, NULL, XML_FROM_XPATH,                             \
6074                 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6075                 __FILE__, __LINE__,                                     \
6076                 NULL, NULL, NULL, 0, 0,                                 \
6077                 "NULL context pointer\n");                              \
6078         return(-1);                                                     \
6079     }                                                                   \
6080
6081
6082 #define CHECK_CONTEXT(ctxt)                                             \
6083     if ((ctxt == NULL) || (ctxt->doc == NULL) ||                        \
6084         (ctxt->doc->children == NULL)) {                                \
6085         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);    \
6086         return(NULL);                                                   \
6087     }
6088
6089
6090 /**
6091  * xmlXPathNewParserContext:
6092  * @str:  the XPath expression
6093  * @ctxt:  the XPath context
6094  *
6095  * Create a new xmlXPathParserContext
6096  *
6097  * Returns the xmlXPathParserContext just allocated.
6098  */
6099 xmlXPathParserContextPtr
6100 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6101     xmlXPathParserContextPtr ret;
6102
6103     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6104     if (ret == NULL) {
6105         xmlXPathErrMemory(ctxt, "creating parser context\n");
6106         return(NULL);
6107     }
6108     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6109     ret->cur = ret->base = str;
6110     ret->context = ctxt;
6111
6112     ret->comp = xmlXPathNewCompExpr();
6113     if (ret->comp == NULL) {
6114         xmlFree(ret->valueTab);
6115         xmlFree(ret);
6116         return(NULL);
6117     }
6118     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6119         ret->comp->dict = ctxt->dict;
6120         xmlDictReference(ret->comp->dict);
6121     }
6122
6123     return(ret);
6124 }
6125
6126 /**
6127  * xmlXPathCompParserContext:
6128  * @comp:  the XPath compiled expression
6129  * @ctxt:  the XPath context
6130  *
6131  * Create a new xmlXPathParserContext when processing a compiled expression
6132  *
6133  * Returns the xmlXPathParserContext just allocated.
6134  */
6135 static xmlXPathParserContextPtr
6136 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6137     xmlXPathParserContextPtr ret;
6138
6139     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6140     if (ret == NULL) {
6141         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6142         return(NULL);
6143     }
6144     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6145
6146     /* Allocate the value stack */
6147     ret->valueTab = (xmlXPathObjectPtr *)
6148                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6149     if (ret->valueTab == NULL) {
6150         xmlFree(ret);
6151         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6152         return(NULL);
6153     }
6154     ret->valueNr = 0;
6155     ret->valueMax = 10;
6156     ret->value = NULL;
6157
6158     ret->context = ctxt;
6159     ret->comp = comp;
6160
6161     return(ret);
6162 }
6163
6164 /**
6165  * xmlXPathFreeParserContext:
6166  * @ctxt:  the context to free
6167  *
6168  * Free up an xmlXPathParserContext
6169  */
6170 void
6171 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6172     if (ctxt->valueTab != NULL) {
6173         xmlFree(ctxt->valueTab);
6174     }
6175     if (ctxt->comp != NULL) {
6176 #ifdef XPATH_STREAMING
6177         if (ctxt->comp->stream != NULL) {
6178             xmlFreePatternList(ctxt->comp->stream);
6179             ctxt->comp->stream = NULL;
6180         }
6181 #endif
6182         xmlXPathFreeCompExpr(ctxt->comp);
6183     }
6184     xmlFree(ctxt);
6185 }
6186
6187 /************************************************************************
6188  *                                                                      *
6189  *              The implicit core function library                      *
6190  *                                                                      *
6191  ************************************************************************/
6192
6193 /**
6194  * xmlXPathNodeValHash:
6195  * @node:  a node pointer
6196  *
6197  * Function computing the beginning of the string value of the node,
6198  * used to speed up comparisons
6199  *
6200  * Returns an int usable as a hash
6201  */
6202 static unsigned int
6203 xmlXPathNodeValHash(xmlNodePtr node) {
6204     int len = 2;
6205     const xmlChar * string = NULL;
6206     xmlNodePtr tmp = NULL;
6207     unsigned int ret = 0;
6208
6209     if (node == NULL)
6210         return(0);
6211
6212     if (node->type == XML_DOCUMENT_NODE) {
6213         tmp = xmlDocGetRootElement((xmlDocPtr) node);
6214         if (tmp == NULL)
6215             node = node->children;
6216         else
6217             node = tmp;
6218
6219         if (node == NULL)
6220             return(0);
6221     }
6222
6223     switch (node->type) {
6224         case XML_COMMENT_NODE:
6225         case XML_PI_NODE:
6226         case XML_CDATA_SECTION_NODE:
6227         case XML_TEXT_NODE:
6228             string = node->content;
6229             if (string == NULL)
6230                 return(0);
6231             if (string[0] == 0)
6232                 return(0);
6233             return(((unsigned int) string[0]) +
6234                    (((unsigned int) string[1]) << 8));
6235         case XML_NAMESPACE_DECL:
6236             string = ((xmlNsPtr)node)->href;
6237             if (string == NULL)
6238                 return(0);
6239             if (string[0] == 0)
6240                 return(0);
6241             return(((unsigned int) string[0]) +
6242                    (((unsigned int) string[1]) << 8));
6243         case XML_ATTRIBUTE_NODE:
6244             tmp = ((xmlAttrPtr) node)->children;
6245             break;
6246         case XML_ELEMENT_NODE:
6247             tmp = node->children;
6248             break;
6249         default:
6250             return(0);
6251     }
6252     while (tmp != NULL) {
6253         switch (tmp->type) {
6254             case XML_COMMENT_NODE:
6255             case XML_PI_NODE:
6256             case XML_CDATA_SECTION_NODE:
6257             case XML_TEXT_NODE:
6258                 string = tmp->content;
6259                 break;
6260             case XML_NAMESPACE_DECL:
6261                 string = ((xmlNsPtr)tmp)->href;
6262                 break;
6263             default:
6264                 break;
6265         }
6266         if ((string != NULL) && (string[0] != 0)) {
6267             if (len == 1) {
6268                 return(ret + (((unsigned int) string[0]) << 8));
6269             }
6270             if (string[1] == 0) {
6271                 len = 1;
6272                 ret = (unsigned int) string[0];
6273             } else {
6274                 return(((unsigned int) string[0]) +
6275                        (((unsigned int) string[1]) << 8));
6276             }
6277         }
6278         /*
6279          * Skip to next node
6280          */
6281         if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6282             if (tmp->children->type != XML_ENTITY_DECL) {
6283                 tmp = tmp->children;
6284                 continue;
6285             }
6286         }
6287         if (tmp == node)
6288             break;
6289
6290         if (tmp->next != NULL) {
6291             tmp = tmp->next;
6292             continue;
6293         }
6294
6295         do {
6296             tmp = tmp->parent;
6297             if (tmp == NULL)
6298                 break;
6299             if (tmp == node) {
6300                 tmp = NULL;
6301                 break;
6302             }
6303             if (tmp->next != NULL) {
6304                 tmp = tmp->next;
6305                 break;
6306             }
6307         } while (tmp != NULL);
6308     }
6309     return(ret);
6310 }
6311
6312 /**
6313  * xmlXPathStringHash:
6314  * @string:  a string
6315  *
6316  * Function computing the beginning of the string value of the node,
6317  * used to speed up comparisons
6318  *
6319  * Returns an int usable as a hash
6320  */
6321 static unsigned int
6322 xmlXPathStringHash(const xmlChar * string) {
6323     if (string == NULL)
6324         return((unsigned int) 0);
6325     if (string[0] == 0)
6326         return(0);
6327     return(((unsigned int) string[0]) +
6328            (((unsigned int) string[1]) << 8));
6329 }
6330
6331 /**
6332  * xmlXPathCompareNodeSetFloat:
6333  * @ctxt:  the XPath Parser context
6334  * @inf:  less than (1) or greater than (0)
6335  * @strict:  is the comparison strict
6336  * @arg:  the node set
6337  * @f:  the value
6338  *
6339  * Implement the compare operation between a nodeset and a number
6340  *     @ns < @val    (1, 1, ...
6341  *     @ns <= @val   (1, 0, ...
6342  *     @ns > @val    (0, 1, ...
6343  *     @ns >= @val   (0, 0, ...
6344  *
6345  * If one object to be compared is a node-set and the other is a number,
6346  * then the comparison will be true if and only if there is a node in the
6347  * node-set such that the result of performing the comparison on the number
6348  * to be compared and on the result of converting the string-value of that
6349  * node to a number using the number function is true.
6350  *
6351  * Returns 0 or 1 depending on the results of the test.
6352  */
6353 static int
6354 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6355                             xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6356     int i, ret = 0;
6357     xmlNodeSetPtr ns;
6358     xmlChar *str2;
6359
6360     if ((f == NULL) || (arg == NULL) ||
6361         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6362         xmlXPathReleaseObject(ctxt->context, arg);
6363         xmlXPathReleaseObject(ctxt->context, f);
6364         return(0);
6365     }
6366     ns = arg->nodesetval;
6367     if (ns != NULL) {
6368         for (i = 0;i < ns->nodeNr;i++) {
6369              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6370              if (str2 != NULL) {
6371                  valuePush(ctxt,
6372                            xmlXPathCacheNewString(ctxt->context, str2));
6373                  xmlFree(str2);
6374                  xmlXPathNumberFunction(ctxt, 1);
6375                  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6376                  ret = xmlXPathCompareValues(ctxt, inf, strict);
6377                  if (ret)
6378                      break;
6379              }
6380         }
6381     }
6382     xmlXPathReleaseObject(ctxt->context, arg);
6383     xmlXPathReleaseObject(ctxt->context, f);
6384     return(ret);
6385 }
6386
6387 /**
6388  * xmlXPathCompareNodeSetString:
6389  * @ctxt:  the XPath Parser context
6390  * @inf:  less than (1) or greater than (0)
6391  * @strict:  is the comparison strict
6392  * @arg:  the node set
6393  * @s:  the value
6394  *
6395  * Implement the compare operation between a nodeset and a string
6396  *     @ns < @val    (1, 1, ...
6397  *     @ns <= @val   (1, 0, ...
6398  *     @ns > @val    (0, 1, ...
6399  *     @ns >= @val   (0, 0, ...
6400  *
6401  * If one object to be compared is a node-set and the other is a string,
6402  * then the comparison will be true if and only if there is a node in
6403  * the node-set such that the result of performing the comparison on the
6404  * string-value of the node and the other string is true.
6405  *
6406  * Returns 0 or 1 depending on the results of the test.
6407  */
6408 static int
6409 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6410                             xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6411     int i, ret = 0;
6412     xmlNodeSetPtr ns;
6413     xmlChar *str2;
6414
6415     if ((s == NULL) || (arg == NULL) ||
6416         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6417         xmlXPathReleaseObject(ctxt->context, arg);
6418         xmlXPathReleaseObject(ctxt->context, s);
6419         return(0);
6420     }
6421     ns = arg->nodesetval;
6422     if (ns != NULL) {
6423         for (i = 0;i < ns->nodeNr;i++) {
6424              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6425              if (str2 != NULL) {
6426                  valuePush(ctxt,
6427                            xmlXPathCacheNewString(ctxt->context, str2));
6428                  xmlFree(str2);
6429                  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6430                  ret = xmlXPathCompareValues(ctxt, inf, strict);
6431                  if (ret)
6432                      break;
6433              }
6434         }
6435     }
6436     xmlXPathReleaseObject(ctxt->context, arg);
6437     xmlXPathReleaseObject(ctxt->context, s);
6438     return(ret);
6439 }
6440
6441 /**
6442  * xmlXPathCompareNodeSets:
6443  * @inf:  less than (1) or greater than (0)
6444  * @strict:  is the comparison strict
6445  * @arg1:  the first node set object
6446  * @arg2:  the second node set object
6447  *
6448  * Implement the compare operation on nodesets:
6449  *
6450  * If both objects to be compared are node-sets, then the comparison
6451  * will be true if and only if there is a node in the first node-set
6452  * and a node in the second node-set such that the result of performing
6453  * the comparison on the string-values of the two nodes is true.
6454  * ....
6455  * When neither object to be compared is a node-set and the operator
6456  * is <=, <, >= or >, then the objects are compared by converting both
6457  * objects to numbers and comparing the numbers according to IEEE 754.
6458  * ....
6459  * The number function converts its argument to a number as follows:
6460  *  - a string that consists of optional whitespace followed by an
6461  *    optional minus sign followed by a Number followed by whitespace
6462  *    is converted to the IEEE 754 number that is nearest (according
6463  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6464  *    represented by the string; any other string is converted to NaN
6465  *
6466  * Conclusion all nodes need to be converted first to their string value
6467  * and then the comparison must be done when possible
6468  */
6469 static int
6470 xmlXPathCompareNodeSets(int inf, int strict,
6471                         xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6472     int i, j, init = 0;
6473     double val1;
6474     double *values2;
6475     int ret = 0;
6476     xmlNodeSetPtr ns1;
6477     xmlNodeSetPtr ns2;
6478
6479     if ((arg1 == NULL) ||
6480         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6481         xmlXPathFreeObject(arg2);
6482         return(0);
6483     }
6484     if ((arg2 == NULL) ||
6485         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6486         xmlXPathFreeObject(arg1);
6487         xmlXPathFreeObject(arg2);
6488         return(0);
6489     }
6490
6491     ns1 = arg1->nodesetval;
6492     ns2 = arg2->nodesetval;
6493
6494     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6495         xmlXPathFreeObject(arg1);
6496         xmlXPathFreeObject(arg2);
6497         return(0);
6498     }
6499     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6500         xmlXPathFreeObject(arg1);
6501         xmlXPathFreeObject(arg2);
6502         return(0);
6503     }
6504
6505     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6506     if (values2 == NULL) {
6507         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6508         xmlXPathFreeObject(arg1);
6509         xmlXPathFreeObject(arg2);
6510         return(0);
6511     }
6512     for (i = 0;i < ns1->nodeNr;i++) {
6513         val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6514         if (xmlXPathIsNaN(val1))
6515             continue;
6516         for (j = 0;j < ns2->nodeNr;j++) {
6517             if (init == 0) {
6518                 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6519             }
6520             if (xmlXPathIsNaN(values2[j]))
6521                 continue;
6522             if (inf && strict)
6523                 ret = (val1 < values2[j]);
6524             else if (inf && !strict)
6525                 ret = (val1 <= values2[j]);
6526             else if (!inf && strict)
6527                 ret = (val1 > values2[j]);
6528             else if (!inf && !strict)
6529                 ret = (val1 >= values2[j]);
6530             if (ret)
6531                 break;
6532         }
6533         if (ret)
6534             break;
6535         init = 1;
6536     }
6537     xmlFree(values2);
6538     xmlXPathFreeObject(arg1);
6539     xmlXPathFreeObject(arg2);
6540     return(ret);
6541 }
6542
6543 /**
6544  * xmlXPathCompareNodeSetValue:
6545  * @ctxt:  the XPath Parser context
6546  * @inf:  less than (1) or greater than (0)
6547  * @strict:  is the comparison strict
6548  * @arg:  the node set
6549  * @val:  the value
6550  *
6551  * Implement the compare operation between a nodeset and a value
6552  *     @ns < @val    (1, 1, ...
6553  *     @ns <= @val   (1, 0, ...
6554  *     @ns > @val    (0, 1, ...
6555  *     @ns >= @val   (0, 0, ...
6556  *
6557  * If one object to be compared is a node-set and the other is a boolean,
6558  * then the comparison will be true if and only if the result of performing
6559  * the comparison on the boolean and on the result of converting
6560  * the node-set to a boolean using the boolean function is true.
6561  *
6562  * Returns 0 or 1 depending on the results of the test.
6563  */
6564 static int
6565 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6566                             xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6567     if ((val == NULL) || (arg == NULL) ||
6568         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6569         return(0);
6570
6571     switch(val->type) {
6572         case XPATH_NUMBER:
6573             return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6574         case XPATH_NODESET:
6575         case XPATH_XSLT_TREE:
6576             return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6577         case XPATH_STRING:
6578             return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6579         case XPATH_BOOLEAN:
6580             valuePush(ctxt, arg);
6581             xmlXPathBooleanFunction(ctxt, 1);
6582             valuePush(ctxt, val);
6583             return(xmlXPathCompareValues(ctxt, inf, strict));
6584         default:
6585             TODO
6586     }
6587     return(0);
6588 }
6589
6590 /**
6591  * xmlXPathEqualNodeSetString:
6592  * @arg:  the nodeset object argument
6593  * @str:  the string to compare to.
6594  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6595  *
6596  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6597  * If one object to be compared is a node-set and the other is a string,
6598  * then the comparison will be true if and only if there is a node in
6599  * the node-set such that the result of performing the comparison on the
6600  * string-value of the node and the other string is true.
6601  *
6602  * Returns 0 or 1 depending on the results of the test.
6603  */
6604 static int
6605 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6606 {
6607     int i;
6608     xmlNodeSetPtr ns;
6609     xmlChar *str2;
6610     unsigned int hash;
6611
6612     if ((str == NULL) || (arg == NULL) ||
6613         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6614         return (0);
6615     ns = arg->nodesetval;
6616     /*
6617      * A NULL nodeset compared with a string is always false
6618      * (since there is no node equal, and no node not equal)
6619      */
6620     if ((ns == NULL) || (ns->nodeNr <= 0) )
6621         return (0);
6622     hash = xmlXPathStringHash(str);
6623     for (i = 0; i < ns->nodeNr; i++) {
6624         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6625             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6626             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6627                 xmlFree(str2);
6628                 if (neq)
6629                     continue;
6630                 return (1);
6631             } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6632                 if (neq)
6633                     continue;
6634                 return (1);
6635             } else if (neq) {
6636                 if (str2 != NULL)
6637                     xmlFree(str2);
6638                 return (1);
6639             }
6640             if (str2 != NULL)
6641                 xmlFree(str2);
6642         } else if (neq)
6643             return (1);
6644     }
6645     return (0);
6646 }
6647
6648 /**
6649  * xmlXPathEqualNodeSetFloat:
6650  * @arg:  the nodeset object argument
6651  * @f:  the float to compare to
6652  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6653  *
6654  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6655  * If one object to be compared is a node-set and the other is a number,
6656  * then the comparison will be true if and only if there is a node in
6657  * the node-set such that the result of performing the comparison on the
6658  * number to be compared and on the result of converting the string-value
6659  * of that node to a number using the number function is true.
6660  *
6661  * Returns 0 or 1 depending on the results of the test.
6662  */
6663 static int
6664 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6665     xmlXPathObjectPtr arg, double f, int neq) {
6666   int i, ret=0;
6667   xmlNodeSetPtr ns;
6668   xmlChar *str2;
6669   xmlXPathObjectPtr val;
6670   double v;
6671
6672     if ((arg == NULL) ||
6673         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6674         return(0);
6675
6676     ns = arg->nodesetval;
6677     if (ns != NULL) {
6678         for (i=0;i<ns->nodeNr;i++) {
6679             str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6680             if (str2 != NULL) {
6681                 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6682                 xmlFree(str2);
6683                 xmlXPathNumberFunction(ctxt, 1);
6684                 val = valuePop(ctxt);
6685                 v = val->floatval;
6686                 xmlXPathReleaseObject(ctxt->context, val);
6687                 if (!xmlXPathIsNaN(v)) {
6688                     if ((!neq) && (v==f)) {
6689                         ret = 1;
6690                         break;
6691                     } else if ((neq) && (v!=f)) {
6692                         ret = 1;
6693                         break;
6694                     }
6695                 } else {        /* NaN is unequal to any value */
6696                     if (neq)
6697                         ret = 1;
6698                 }
6699             }
6700         }
6701     }
6702
6703     return(ret);
6704 }
6705
6706
6707 /**
6708  * xmlXPathEqualNodeSets:
6709  * @arg1:  first nodeset object argument
6710  * @arg2:  second nodeset object argument
6711  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6712  *
6713  * Implement the equal / not equal operation on XPath nodesets:
6714  * @arg1 == @arg2  or  @arg1 != @arg2
6715  * If both objects to be compared are node-sets, then the comparison
6716  * will be true if and only if there is a node in the first node-set and
6717  * a node in the second node-set such that the result of performing the
6718  * comparison on the string-values of the two nodes is true.
6719  *
6720  * (needless to say, this is a costly operation)
6721  *
6722  * Returns 0 or 1 depending on the results of the test.
6723  */
6724 static int
6725 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6726     int i, j;
6727     unsigned int *hashs1;
6728     unsigned int *hashs2;
6729     xmlChar **values1;
6730     xmlChar **values2;
6731     int ret = 0;
6732     xmlNodeSetPtr ns1;
6733     xmlNodeSetPtr ns2;
6734
6735     if ((arg1 == NULL) ||
6736         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6737         return(0);
6738     if ((arg2 == NULL) ||
6739         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6740         return(0);
6741
6742     ns1 = arg1->nodesetval;
6743     ns2 = arg2->nodesetval;
6744
6745     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6746         return(0);
6747     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6748         return(0);
6749
6750     /*
6751      * for equal, check if there is a node pertaining to both sets
6752      */
6753     if (neq == 0)
6754         for (i = 0;i < ns1->nodeNr;i++)
6755             for (j = 0;j < ns2->nodeNr;j++)
6756                 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6757                     return(1);
6758
6759     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6760     if (values1 == NULL) {
6761         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6762         return(0);
6763     }
6764     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6765     if (hashs1 == NULL) {
6766         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6767         xmlFree(values1);
6768         return(0);
6769     }
6770     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6771     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6772     if (values2 == NULL) {
6773         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6774         xmlFree(hashs1);
6775         xmlFree(values1);
6776         return(0);
6777     }
6778     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6779     if (hashs2 == NULL) {
6780         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6781         xmlFree(hashs1);
6782         xmlFree(values1);
6783         xmlFree(values2);
6784         return(0);
6785     }
6786     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6787     for (i = 0;i < ns1->nodeNr;i++) {
6788         hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6789         for (j = 0;j < ns2->nodeNr;j++) {
6790             if (i == 0)
6791                 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6792             if (hashs1[i] != hashs2[j]) {
6793                 if (neq) {
6794                     ret = 1;
6795                     break;
6796                 }
6797             }
6798             else {
6799                 if (values1[i] == NULL)
6800                     values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6801                 if (values2[j] == NULL)
6802                     values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6803                 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6804                 if (ret)
6805                     break;
6806             }
6807         }
6808         if (ret)
6809             break;
6810     }
6811     for (i = 0;i < ns1->nodeNr;i++)
6812         if (values1[i] != NULL)
6813             xmlFree(values1[i]);
6814     for (j = 0;j < ns2->nodeNr;j++)
6815         if (values2[j] != NULL)
6816             xmlFree(values2[j]);
6817     xmlFree(values1);
6818     xmlFree(values2);
6819     xmlFree(hashs1);
6820     xmlFree(hashs2);
6821     return(ret);
6822 }
6823
6824 static int
6825 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6826   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6827     int ret = 0;
6828     /*
6829      *At this point we are assured neither arg1 nor arg2
6830      *is a nodeset, so we can just pick the appropriate routine.
6831      */
6832     switch (arg1->type) {
6833         case XPATH_UNDEFINED:
6834 #ifdef DEBUG_EXPR
6835             xmlGenericError(xmlGenericErrorContext,
6836                     "Equal: undefined\n");
6837 #endif
6838             break;
6839         case XPATH_BOOLEAN:
6840             switch (arg2->type) {
6841                 case XPATH_UNDEFINED:
6842 #ifdef DEBUG_EXPR
6843                     xmlGenericError(xmlGenericErrorContext,
6844                             "Equal: undefined\n");
6845 #endif
6846                     break;
6847                 case XPATH_BOOLEAN:
6848 #ifdef DEBUG_EXPR
6849                     xmlGenericError(xmlGenericErrorContext,
6850                             "Equal: %d boolean %d \n",
6851                             arg1->boolval, arg2->boolval);
6852 #endif
6853                     ret = (arg1->boolval == arg2->boolval);
6854                     break;
6855                 case XPATH_NUMBER:
6856                     ret = (arg1->boolval ==
6857                            xmlXPathCastNumberToBoolean(arg2->floatval));
6858                     break;
6859                 case XPATH_STRING:
6860                     if ((arg2->stringval == NULL) ||
6861                         (arg2->stringval[0] == 0)) ret = 0;
6862                     else
6863                         ret = 1;
6864                     ret = (arg1->boolval == ret);
6865                     break;
6866                 case XPATH_USERS:
6867                 case XPATH_POINT:
6868                 case XPATH_RANGE:
6869                 case XPATH_LOCATIONSET:
6870                     TODO
6871                     break;
6872                 case XPATH_NODESET:
6873                 case XPATH_XSLT_TREE:
6874                     break;
6875             }
6876             break;
6877         case XPATH_NUMBER:
6878             switch (arg2->type) {
6879                 case XPATH_UNDEFINED:
6880 #ifdef DEBUG_EXPR
6881                     xmlGenericError(xmlGenericErrorContext,
6882                             "Equal: undefined\n");
6883 #endif
6884                     break;
6885                 case XPATH_BOOLEAN:
6886                     ret = (arg2->boolval==
6887                            xmlXPathCastNumberToBoolean(arg1->floatval));
6888                     break;
6889                 case XPATH_STRING:
6890                     valuePush(ctxt, arg2);
6891                     xmlXPathNumberFunction(ctxt, 1);
6892                     arg2 = valuePop(ctxt);
6893                     /* no break on purpose */
6894                 case XPATH_NUMBER:
6895                     /* Hand check NaN and Infinity equalities */
6896                     if (xmlXPathIsNaN(arg1->floatval) ||
6897                             xmlXPathIsNaN(arg2->floatval)) {
6898                         ret = 0;
6899                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6900                         if (xmlXPathIsInf(arg2->floatval) == 1)
6901                             ret = 1;
6902                         else
6903                             ret = 0;
6904                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6905                         if (xmlXPathIsInf(arg2->floatval) == -1)
6906                             ret = 1;
6907                         else
6908                             ret = 0;
6909                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6910                         if (xmlXPathIsInf(arg1->floatval) == 1)
6911                             ret = 1;
6912                         else
6913                             ret = 0;
6914                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6915                         if (xmlXPathIsInf(arg1->floatval) == -1)
6916                             ret = 1;
6917                         else
6918                             ret = 0;
6919                     } else {
6920                         ret = (arg1->floatval == arg2->floatval);
6921                     }
6922                     break;
6923                 case XPATH_USERS:
6924                 case XPATH_POINT:
6925                 case XPATH_RANGE:
6926                 case XPATH_LOCATIONSET:
6927                     TODO
6928                     break;
6929                 case XPATH_NODESET:
6930                 case XPATH_XSLT_TREE:
6931                     break;
6932             }
6933             break;
6934         case XPATH_STRING:
6935             switch (arg2->type) {
6936                 case XPATH_UNDEFINED:
6937 #ifdef DEBUG_EXPR
6938                     xmlGenericError(xmlGenericErrorContext,
6939                             "Equal: undefined\n");
6940 #endif
6941                     break;
6942                 case XPATH_BOOLEAN:
6943                     if ((arg1->stringval == NULL) ||
6944                         (arg1->stringval[0] == 0)) ret = 0;
6945                     else
6946                         ret = 1;
6947                     ret = (arg2->boolval == ret);
6948                     break;
6949                 case XPATH_STRING:
6950                     ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6951                     break;
6952                 case XPATH_NUMBER:
6953                     valuePush(ctxt, arg1);
6954                     xmlXPathNumberFunction(ctxt, 1);
6955                     arg1 = valuePop(ctxt);
6956                     /* Hand check NaN and Infinity equalities */
6957                     if (xmlXPathIsNaN(arg1->floatval) ||
6958                             xmlXPathIsNaN(arg2->floatval)) {
6959                         ret = 0;
6960                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6961                         if (xmlXPathIsInf(arg2->floatval) == 1)
6962                             ret = 1;
6963                         else
6964                             ret = 0;
6965                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6966                         if (xmlXPathIsInf(arg2->floatval) == -1)
6967                             ret = 1;
6968                         else
6969                             ret = 0;
6970                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6971                         if (xmlXPathIsInf(arg1->floatval) == 1)
6972                             ret = 1;
6973                         else
6974                             ret = 0;
6975                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6976                         if (xmlXPathIsInf(arg1->floatval) == -1)
6977                             ret = 1;
6978                         else
6979                             ret = 0;
6980                     } else {
6981                         ret = (arg1->floatval == arg2->floatval);
6982                     }
6983                     break;
6984                 case XPATH_USERS:
6985                 case XPATH_POINT:
6986                 case XPATH_RANGE:
6987                 case XPATH_LOCATIONSET:
6988                     TODO
6989                     break;
6990                 case XPATH_NODESET:
6991                 case XPATH_XSLT_TREE:
6992                     break;
6993             }
6994             break;
6995         case XPATH_USERS:
6996         case XPATH_POINT:
6997         case XPATH_RANGE:
6998         case XPATH_LOCATIONSET:
6999             TODO
7000             break;
7001         case XPATH_NODESET:
7002         case XPATH_XSLT_TREE:
7003             break;
7004     }
7005     xmlXPathReleaseObject(ctxt->context, arg1);
7006     xmlXPathReleaseObject(ctxt->context, arg2);
7007     return(ret);
7008 }
7009
7010 /**
7011  * xmlXPathEqualValues:
7012  * @ctxt:  the XPath Parser context
7013  *
7014  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7015  *
7016  * Returns 0 or 1 depending on the results of the test.
7017  */
7018 int
7019 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7020     xmlXPathObjectPtr arg1, arg2, argtmp;
7021     int ret = 0;
7022
7023     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7024     arg2 = valuePop(ctxt);
7025     arg1 = valuePop(ctxt);
7026     if ((arg1 == NULL) || (arg2 == NULL)) {
7027         if (arg1 != NULL)
7028             xmlXPathReleaseObject(ctxt->context, arg1);
7029         else
7030             xmlXPathReleaseObject(ctxt->context, arg2);
7031         XP_ERROR0(XPATH_INVALID_OPERAND);
7032     }
7033
7034     if (arg1 == arg2) {
7035 #ifdef DEBUG_EXPR
7036         xmlGenericError(xmlGenericErrorContext,
7037                 "Equal: by pointer\n");
7038 #endif
7039         xmlXPathFreeObject(arg1);
7040         return(1);
7041     }
7042
7043     /*
7044      *If either argument is a nodeset, it's a 'special case'
7045      */
7046     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7047       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7048         /*
7049          *Hack it to assure arg1 is the nodeset
7050          */
7051         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7052                 argtmp = arg2;
7053                 arg2 = arg1;
7054                 arg1 = argtmp;
7055         }
7056         switch (arg2->type) {
7057             case XPATH_UNDEFINED:
7058 #ifdef DEBUG_EXPR
7059                 xmlGenericError(xmlGenericErrorContext,
7060                         "Equal: undefined\n");
7061 #endif
7062                 break;
7063             case XPATH_NODESET:
7064             case XPATH_XSLT_TREE:
7065                 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7066                 break;
7067             case XPATH_BOOLEAN:
7068                 if ((arg1->nodesetval == NULL) ||
7069                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
7070                 else
7071                     ret = 1;
7072                 ret = (ret == arg2->boolval);
7073                 break;
7074             case XPATH_NUMBER:
7075                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7076                 break;
7077             case XPATH_STRING:
7078                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7079                 break;
7080             case XPATH_USERS:
7081             case XPATH_POINT:
7082             case XPATH_RANGE:
7083             case XPATH_LOCATIONSET:
7084                 TODO
7085                 break;
7086         }
7087         xmlXPathReleaseObject(ctxt->context, arg1);
7088         xmlXPathReleaseObject(ctxt->context, arg2);
7089         return(ret);
7090     }
7091
7092     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7093 }
7094
7095 /**
7096  * xmlXPathNotEqualValues:
7097  * @ctxt:  the XPath Parser context
7098  *
7099  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7100  *
7101  * Returns 0 or 1 depending on the results of the test.
7102  */
7103 int
7104 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7105     xmlXPathObjectPtr arg1, arg2, argtmp;
7106     int ret = 0;
7107
7108     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7109     arg2 = valuePop(ctxt);
7110     arg1 = valuePop(ctxt);
7111     if ((arg1 == NULL) || (arg2 == NULL)) {
7112         if (arg1 != NULL)
7113             xmlXPathReleaseObject(ctxt->context, arg1);
7114         else
7115             xmlXPathReleaseObject(ctxt->context, arg2);
7116         XP_ERROR0(XPATH_INVALID_OPERAND);
7117     }
7118
7119     if (arg1 == arg2) {
7120 #ifdef DEBUG_EXPR
7121         xmlGenericError(xmlGenericErrorContext,
7122                 "NotEqual: by pointer\n");
7123 #endif
7124         xmlXPathReleaseObject(ctxt->context, arg1);
7125         return(0);
7126     }
7127
7128     /*
7129      *If either argument is a nodeset, it's a 'special case'
7130      */
7131     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7132       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7133         /*
7134          *Hack it to assure arg1 is the nodeset
7135          */
7136         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7137                 argtmp = arg2;
7138                 arg2 = arg1;
7139                 arg1 = argtmp;
7140         }
7141         switch (arg2->type) {
7142             case XPATH_UNDEFINED:
7143 #ifdef DEBUG_EXPR
7144                 xmlGenericError(xmlGenericErrorContext,
7145                         "NotEqual: undefined\n");
7146 #endif
7147                 break;
7148             case XPATH_NODESET:
7149             case XPATH_XSLT_TREE:
7150                 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7151                 break;
7152             case XPATH_BOOLEAN:
7153                 if ((arg1->nodesetval == NULL) ||
7154                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
7155                 else
7156                     ret = 1;
7157                 ret = (ret != arg2->boolval);
7158                 break;
7159             case XPATH_NUMBER:
7160                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7161                 break;
7162             case XPATH_STRING:
7163                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7164                 break;
7165             case XPATH_USERS:
7166             case XPATH_POINT:
7167             case XPATH_RANGE:
7168             case XPATH_LOCATIONSET:
7169                 TODO
7170                 break;
7171         }
7172         xmlXPathReleaseObject(ctxt->context, arg1);
7173         xmlXPathReleaseObject(ctxt->context, arg2);
7174         return(ret);
7175     }
7176
7177     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7178 }
7179
7180 /**
7181  * xmlXPathCompareValues:
7182  * @ctxt:  the XPath Parser context
7183  * @inf:  less than (1) or greater than (0)
7184  * @strict:  is the comparison strict
7185  *
7186  * Implement the compare operation on XPath objects:
7187  *     @arg1 < @arg2    (1, 1, ...
7188  *     @arg1 <= @arg2   (1, 0, ...
7189  *     @arg1 > @arg2    (0, 1, ...
7190  *     @arg1 >= @arg2   (0, 0, ...
7191  *
7192  * When neither object to be compared is a node-set and the operator is
7193  * <=, <, >=, >, then the objects are compared by converted both objects
7194  * to numbers and comparing the numbers according to IEEE 754. The <
7195  * comparison will be true if and only if the first number is less than the
7196  * second number. The <= comparison will be true if and only if the first
7197  * number is less than or equal to the second number. The > comparison
7198  * will be true if and only if the first number is greater than the second
7199  * number. The >= comparison will be true if and only if the first number
7200  * is greater than or equal to the second number.
7201  *
7202  * Returns 1 if the comparison succeeded, 0 if it failed
7203  */
7204 int
7205 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7206     int ret = 0, arg1i = 0, arg2i = 0;
7207     xmlXPathObjectPtr arg1, arg2;
7208
7209     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7210     arg2 = valuePop(ctxt);
7211     arg1 = valuePop(ctxt);
7212     if ((arg1 == NULL) || (arg2 == NULL)) {
7213         if (arg1 != NULL)
7214             xmlXPathReleaseObject(ctxt->context, arg1);
7215         else
7216             xmlXPathReleaseObject(ctxt->context, arg2);
7217         XP_ERROR0(XPATH_INVALID_OPERAND);
7218     }
7219
7220     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7221       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7222         /*
7223          * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7224          * are not freed from within this routine; they will be freed from the
7225          * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7226          */
7227         if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7228           ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7229             ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7230         } else {
7231             if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7232                 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7233                                                   arg1, arg2);
7234             } else {
7235                 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7236                                                   arg2, arg1);
7237             }
7238         }
7239         return(ret);
7240     }
7241
7242     if (arg1->type != XPATH_NUMBER) {
7243         valuePush(ctxt, arg1);
7244         xmlXPathNumberFunction(ctxt, 1);
7245         arg1 = valuePop(ctxt);
7246     }
7247     if (arg1->type != XPATH_NUMBER) {
7248         xmlXPathFreeObject(arg1);
7249         xmlXPathFreeObject(arg2);
7250         XP_ERROR0(XPATH_INVALID_OPERAND);
7251     }
7252     if (arg2->type != XPATH_NUMBER) {
7253         valuePush(ctxt, arg2);
7254         xmlXPathNumberFunction(ctxt, 1);
7255         arg2 = valuePop(ctxt);
7256     }
7257     if (arg2->type != XPATH_NUMBER) {
7258         xmlXPathReleaseObject(ctxt->context, arg1);
7259         xmlXPathReleaseObject(ctxt->context, arg2);
7260         XP_ERROR0(XPATH_INVALID_OPERAND);
7261     }
7262     /*
7263      * Add tests for infinity and nan
7264      * => feedback on 3.4 for Inf and NaN
7265      */
7266     /* Hand check NaN and Infinity comparisons */
7267     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7268         ret=0;
7269     } else {
7270         arg1i=xmlXPathIsInf(arg1->floatval);
7271         arg2i=xmlXPathIsInf(arg2->floatval);
7272         if (inf && strict) {
7273             if ((arg1i == -1 && arg2i != -1) ||
7274                 (arg2i == 1 && arg1i != 1)) {
7275                 ret = 1;
7276             } else if (arg1i == 0 && arg2i == 0) {
7277                 ret = (arg1->floatval < arg2->floatval);
7278             } else {
7279                 ret = 0;
7280             }
7281         }
7282         else if (inf && !strict) {
7283             if (arg1i == -1 || arg2i == 1) {
7284                 ret = 1;
7285             } else if (arg1i == 0 && arg2i == 0) {
7286                 ret = (arg1->floatval <= arg2->floatval);
7287             } else {
7288                 ret = 0;
7289             }
7290         }
7291         else if (!inf && strict) {
7292             if ((arg1i == 1 && arg2i != 1) ||
7293                 (arg2i == -1 && arg1i != -1)) {
7294                 ret = 1;
7295             } else if (arg1i == 0 && arg2i == 0) {
7296                 ret = (arg1->floatval > arg2->floatval);
7297             } else {
7298                 ret = 0;
7299             }
7300         }
7301         else if (!inf && !strict) {
7302             if (arg1i == 1 || arg2i == -1) {
7303                 ret = 1;
7304             } else if (arg1i == 0 && arg2i == 0) {
7305                 ret = (arg1->floatval >= arg2->floatval);
7306             } else {
7307                 ret = 0;
7308             }
7309         }
7310     }
7311     xmlXPathReleaseObject(ctxt->context, arg1);
7312     xmlXPathReleaseObject(ctxt->context, arg2);
7313     return(ret);
7314 }
7315
7316 /**
7317  * xmlXPathValueFlipSign:
7318  * @ctxt:  the XPath Parser context
7319  *
7320  * Implement the unary - operation on an XPath object
7321  * The numeric operators convert their operands to numbers as if
7322  * by calling the number function.
7323  */
7324 void
7325 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7326     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7327     CAST_TO_NUMBER;
7328     CHECK_TYPE(XPATH_NUMBER);
7329     if (xmlXPathIsNaN(ctxt->value->floatval))
7330         ctxt->value->floatval=xmlXPathNAN;
7331     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7332         ctxt->value->floatval=xmlXPathNINF;
7333     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7334         ctxt->value->floatval=xmlXPathPINF;
7335     else if (ctxt->value->floatval == 0) {
7336         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7337             ctxt->value->floatval = xmlXPathNZERO;
7338         else
7339             ctxt->value->floatval = 0;
7340     }
7341     else
7342         ctxt->value->floatval = - ctxt->value->floatval;
7343 }
7344
7345 /**
7346  * xmlXPathAddValues:
7347  * @ctxt:  the XPath Parser context
7348  *
7349  * Implement the add operation on XPath objects:
7350  * The numeric operators convert their operands to numbers as if
7351  * by calling the number function.
7352  */
7353 void
7354 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7355     xmlXPathObjectPtr arg;
7356     double val;
7357
7358     arg = valuePop(ctxt);
7359     if (arg == NULL)
7360         XP_ERROR(XPATH_INVALID_OPERAND);
7361     val = xmlXPathCastToNumber(arg);
7362     xmlXPathReleaseObject(ctxt->context, arg);
7363     CAST_TO_NUMBER;
7364     CHECK_TYPE(XPATH_NUMBER);
7365     ctxt->value->floatval += val;
7366 }
7367
7368 /**
7369  * xmlXPathSubValues:
7370  * @ctxt:  the XPath Parser context
7371  *
7372  * Implement the subtraction operation on XPath objects:
7373  * The numeric operators convert their operands to numbers as if
7374  * by calling the number function.
7375  */
7376 void
7377 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7378     xmlXPathObjectPtr arg;
7379     double val;
7380
7381     arg = valuePop(ctxt);
7382     if (arg == NULL)
7383         XP_ERROR(XPATH_INVALID_OPERAND);
7384     val = xmlXPathCastToNumber(arg);
7385     xmlXPathReleaseObject(ctxt->context, arg);
7386     CAST_TO_NUMBER;
7387     CHECK_TYPE(XPATH_NUMBER);
7388     ctxt->value->floatval -= val;
7389 }
7390
7391 /**
7392  * xmlXPathMultValues:
7393  * @ctxt:  the XPath Parser context
7394  *
7395  * Implement the multiply operation on XPath objects:
7396  * The numeric operators convert their operands to numbers as if
7397  * by calling the number function.
7398  */
7399 void
7400 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7401     xmlXPathObjectPtr arg;
7402     double val;
7403
7404     arg = valuePop(ctxt);
7405     if (arg == NULL)
7406         XP_ERROR(XPATH_INVALID_OPERAND);
7407     val = xmlXPathCastToNumber(arg);
7408     xmlXPathReleaseObject(ctxt->context, arg);
7409     CAST_TO_NUMBER;
7410     CHECK_TYPE(XPATH_NUMBER);
7411     ctxt->value->floatval *= val;
7412 }
7413
7414 /**
7415  * xmlXPathDivValues:
7416  * @ctxt:  the XPath Parser context
7417  *
7418  * Implement the div operation on XPath objects @arg1 / @arg2:
7419  * The numeric operators convert their operands to numbers as if
7420  * by calling the number function.
7421  */
7422 void
7423 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7424     xmlXPathObjectPtr arg;
7425     double val;
7426
7427     arg = valuePop(ctxt);
7428     if (arg == NULL)
7429         XP_ERROR(XPATH_INVALID_OPERAND);
7430     val = xmlXPathCastToNumber(arg);
7431     xmlXPathReleaseObject(ctxt->context, arg);
7432     CAST_TO_NUMBER;
7433     CHECK_TYPE(XPATH_NUMBER);
7434     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7435         ctxt->value->floatval = xmlXPathNAN;
7436     else if (val == 0 && xmlXPathGetSign(val) != 0) {
7437         if (ctxt->value->floatval == 0)
7438             ctxt->value->floatval = xmlXPathNAN;
7439         else if (ctxt->value->floatval > 0)
7440             ctxt->value->floatval = xmlXPathNINF;
7441         else if (ctxt->value->floatval < 0)
7442             ctxt->value->floatval = xmlXPathPINF;
7443     }
7444     else if (val == 0) {
7445         if (ctxt->value->floatval == 0)
7446             ctxt->value->floatval = xmlXPathNAN;
7447         else if (ctxt->value->floatval > 0)
7448             ctxt->value->floatval = xmlXPathPINF;
7449         else if (ctxt->value->floatval < 0)
7450             ctxt->value->floatval = xmlXPathNINF;
7451     } else
7452         ctxt->value->floatval /= val;
7453 }
7454
7455 /**
7456  * xmlXPathModValues:
7457  * @ctxt:  the XPath Parser context
7458  *
7459  * Implement the mod operation on XPath objects: @arg1 / @arg2
7460  * The numeric operators convert their operands to numbers as if
7461  * by calling the number function.
7462  */
7463 void
7464 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7465     xmlXPathObjectPtr arg;
7466     double arg1, arg2;
7467
7468     arg = valuePop(ctxt);
7469     if (arg == NULL)
7470         XP_ERROR(XPATH_INVALID_OPERAND);
7471     arg2 = xmlXPathCastToNumber(arg);
7472     xmlXPathReleaseObject(ctxt->context, arg);
7473     CAST_TO_NUMBER;
7474     CHECK_TYPE(XPATH_NUMBER);
7475     arg1 = ctxt->value->floatval;
7476     if (arg2 == 0)
7477         ctxt->value->floatval = xmlXPathNAN;
7478     else {
7479         ctxt->value->floatval = fmod(arg1, arg2);
7480     }
7481 }
7482
7483 /************************************************************************
7484  *                                                                      *
7485  *              The traversal functions                                 *
7486  *                                                                      *
7487  ************************************************************************/
7488
7489 /*
7490  * A traversal function enumerates nodes along an axis.
7491  * Initially it must be called with NULL, and it indicates
7492  * termination on the axis by returning NULL.
7493  */
7494 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7495                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7496
7497 /*
7498  * xmlXPathTraversalFunctionExt:
7499  * A traversal function enumerates nodes along an axis.
7500  * Initially it must be called with NULL, and it indicates
7501  * termination on the axis by returning NULL.
7502  * The context node of the traversal is specified via @contextNode.
7503  */
7504 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7505                     (xmlNodePtr cur, xmlNodePtr contextNode);
7506
7507 /*
7508  * xmlXPathNodeSetMergeFunction:
7509  * Used for merging node sets in xmlXPathCollectAndTest().
7510  */
7511 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7512                     (xmlNodeSetPtr, xmlNodeSetPtr, int);
7513
7514
7515 /**
7516  * xmlXPathNextSelf:
7517  * @ctxt:  the XPath Parser context
7518  * @cur:  the current node in the traversal
7519  *
7520  * Traversal function for the "self" direction
7521  * The self axis contains just the context node itself
7522  *
7523  * Returns the next element following that axis
7524  */
7525 xmlNodePtr
7526 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7527     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7528     if (cur == NULL)
7529         return(ctxt->context->node);
7530     return(NULL);
7531 }
7532
7533 /**
7534  * xmlXPathNextChild:
7535  * @ctxt:  the XPath Parser context
7536  * @cur:  the current node in the traversal
7537  *
7538  * Traversal function for the "child" direction
7539  * The child axis contains the children of the context node in document order.
7540  *
7541  * Returns the next element following that axis
7542  */
7543 xmlNodePtr
7544 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7545     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7546     if (cur == NULL) {
7547         if (ctxt->context->node == NULL) return(NULL);
7548         switch (ctxt->context->node->type) {
7549             case XML_ELEMENT_NODE:
7550             case XML_TEXT_NODE:
7551             case XML_CDATA_SECTION_NODE:
7552             case XML_ENTITY_REF_NODE:
7553             case XML_ENTITY_NODE:
7554             case XML_PI_NODE:
7555             case XML_COMMENT_NODE:
7556             case XML_NOTATION_NODE:
7557             case XML_DTD_NODE:
7558                 return(ctxt->context->node->children);
7559             case XML_DOCUMENT_NODE:
7560             case XML_DOCUMENT_TYPE_NODE:
7561             case XML_DOCUMENT_FRAG_NODE:
7562             case XML_HTML_DOCUMENT_NODE:
7563 #ifdef LIBXML_DOCB_ENABLED
7564             case XML_DOCB_DOCUMENT_NODE:
7565 #endif
7566                 return(((xmlDocPtr) ctxt->context->node)->children);
7567             case XML_ELEMENT_DECL:
7568             case XML_ATTRIBUTE_DECL:
7569             case XML_ENTITY_DECL:
7570             case XML_ATTRIBUTE_NODE:
7571             case XML_NAMESPACE_DECL:
7572             case XML_XINCLUDE_START:
7573             case XML_XINCLUDE_END:
7574                 return(NULL);
7575         }
7576         return(NULL);
7577     }
7578     if ((cur->type == XML_DOCUMENT_NODE) ||
7579         (cur->type == XML_HTML_DOCUMENT_NODE))
7580         return(NULL);
7581     return(cur->next);
7582 }
7583
7584 /**
7585  * xmlXPathNextChildElement:
7586  * @ctxt:  the XPath Parser context
7587  * @cur:  the current node in the traversal
7588  *
7589  * Traversal function for the "child" direction and nodes of type element.
7590  * The child axis contains the children of the context node in document order.
7591  *
7592  * Returns the next element following that axis
7593  */
7594 static xmlNodePtr
7595 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7596     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7597     if (cur == NULL) {
7598         cur = ctxt->context->node;
7599         if (cur == NULL) return(NULL);
7600         /*
7601         * Get the first element child.
7602         */
7603         switch (cur->type) {
7604             case XML_ELEMENT_NODE:
7605             case XML_DOCUMENT_FRAG_NODE:
7606             case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7607             case XML_ENTITY_NODE:
7608                 cur = cur->children;
7609                 if (cur != NULL) {
7610                     if (cur->type == XML_ELEMENT_NODE)
7611                         return(cur);
7612                     do {
7613                         cur = cur->next;
7614                     } while ((cur != NULL) &&
7615                         (cur->type != XML_ELEMENT_NODE));
7616                     return(cur);
7617                 }
7618                 return(NULL);
7619             case XML_DOCUMENT_NODE:
7620             case XML_HTML_DOCUMENT_NODE:
7621 #ifdef LIBXML_DOCB_ENABLED
7622             case XML_DOCB_DOCUMENT_NODE:
7623 #endif
7624                 return(xmlDocGetRootElement((xmlDocPtr) cur));
7625             default:
7626                 return(NULL);
7627         }
7628         return(NULL);
7629     }
7630     /*
7631     * Get the next sibling element node.
7632     */
7633     switch (cur->type) {
7634         case XML_ELEMENT_NODE:
7635         case XML_TEXT_NODE:
7636         case XML_ENTITY_REF_NODE:
7637         case XML_ENTITY_NODE:
7638         case XML_CDATA_SECTION_NODE:
7639         case XML_PI_NODE:
7640         case XML_COMMENT_NODE:
7641         case XML_XINCLUDE_END:
7642             break;
7643         /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7644         default:
7645             return(NULL);
7646     }
7647     if (cur->next != NULL) {
7648         if (cur->next->type == XML_ELEMENT_NODE)
7649             return(cur->next);
7650         cur = cur->next;
7651         do {
7652             cur = cur->next;
7653         } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7654         return(cur);
7655     }
7656     return(NULL);
7657 }
7658
7659 /**
7660  * xmlXPathNextDescendantOrSelfElemParent:
7661  * @ctxt:  the XPath Parser context
7662  * @cur:  the current node in the traversal
7663  *
7664  * Traversal function for the "descendant-or-self" axis.
7665  * Additionally it returns only nodes which can be parents of
7666  * element nodes.
7667  *
7668  *
7669  * Returns the next element following that axis
7670  */
7671 static xmlNodePtr
7672 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7673                                        xmlNodePtr contextNode)
7674 {
7675     if (cur == NULL) {
7676         if (contextNode == NULL)
7677             return(NULL);
7678         switch (contextNode->type) {
7679             case XML_ELEMENT_NODE:
7680             case XML_XINCLUDE_START:
7681             case XML_DOCUMENT_FRAG_NODE:
7682             case XML_DOCUMENT_NODE:
7683 #ifdef LIBXML_DOCB_ENABLED
7684             case XML_DOCB_DOCUMENT_NODE:
7685 #endif
7686             case XML_HTML_DOCUMENT_NODE:            
7687                 return(contextNode);
7688             default:
7689                 return(NULL);
7690         }
7691         return(NULL);
7692     } else {
7693         xmlNodePtr start = cur;
7694
7695         while (cur != NULL) {
7696             switch (cur->type) {
7697                 case XML_ELEMENT_NODE:
7698                 /* TODO: OK to have XInclude here? */
7699                 case XML_XINCLUDE_START:
7700                 case XML_DOCUMENT_FRAG_NODE:
7701                     if (cur != start)
7702                         return(cur);
7703                     if (cur->children != NULL) {
7704                         cur = cur->children;
7705                         continue;
7706                     }
7707                     break;
7708                 /* Not sure if we need those here. */
7709                 case XML_DOCUMENT_NODE:
7710 #ifdef LIBXML_DOCB_ENABLED
7711                 case XML_DOCB_DOCUMENT_NODE:
7712 #endif
7713                 case XML_HTML_DOCUMENT_NODE:
7714                     if (cur != start)
7715                         return(cur);
7716                     return(xmlDocGetRootElement((xmlDocPtr) cur));
7717                 default:
7718                     break;
7719             }
7720
7721 next_sibling:
7722             if ((cur == NULL) || (cur == contextNode))
7723                 return(NULL);
7724             if (cur->next != NULL) {
7725                 cur = cur->next;
7726             } else {
7727                 cur = cur->parent;
7728                 goto next_sibling;
7729             }
7730         }
7731     }
7732     return(NULL);
7733 }
7734
7735 /**
7736  * xmlXPathNextDescendant:
7737  * @ctxt:  the XPath Parser context
7738  * @cur:  the current node in the traversal
7739  *
7740  * Traversal function for the "descendant" direction
7741  * the descendant axis contains the descendants of the context node in document
7742  * order; a descendant is a child or a child of a child and so on.
7743  *
7744  * Returns the next element following that axis
7745  */
7746 xmlNodePtr
7747 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7748     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7749     if (cur == NULL) {
7750         if (ctxt->context->node == NULL)
7751             return(NULL);
7752         if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7753             (ctxt->context->node->type == XML_NAMESPACE_DECL))
7754             return(NULL);
7755
7756         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7757             return(ctxt->context->doc->children);
7758         return(ctxt->context->node->children);
7759     }
7760
7761     if (cur->children != NULL) {
7762         /*
7763          * Do not descend on entities declarations
7764          */
7765         if (cur->children->type != XML_ENTITY_DECL) {
7766             cur = cur->children;
7767             /*
7768              * Skip DTDs
7769              */
7770             if (cur->type != XML_DTD_NODE)
7771                 return(cur);
7772         }
7773     }
7774
7775     if (cur == ctxt->context->node) return(NULL);
7776
7777     while (cur->next != NULL) {
7778         cur = cur->next;
7779         if ((cur->type != XML_ENTITY_DECL) &&
7780             (cur->type != XML_DTD_NODE))
7781             return(cur);
7782     }
7783
7784     do {
7785         cur = cur->parent;
7786         if (cur == NULL) break;
7787         if (cur == ctxt->context->node) return(NULL);
7788         if (cur->next != NULL) {
7789             cur = cur->next;
7790             return(cur);
7791         }
7792     } while (cur != NULL);
7793     return(cur);
7794 }
7795
7796 /**
7797  * xmlXPathNextDescendantOrSelf:
7798  * @ctxt:  the XPath Parser context
7799  * @cur:  the current node in the traversal
7800  *
7801  * Traversal function for the "descendant-or-self" direction
7802  * the descendant-or-self axis contains the context node and the descendants
7803  * of the context node in document order; thus the context node is the first
7804  * node on the axis, and the first child of the context node is the second node
7805  * on the axis
7806  *
7807  * Returns the next element following that axis
7808  */
7809 xmlNodePtr
7810 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7811     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7812     if (cur == NULL) {
7813         if (ctxt->context->node == NULL)
7814             return(NULL);
7815         if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7816             (ctxt->context->node->type == XML_NAMESPACE_DECL))
7817             return(NULL);
7818         return(ctxt->context->node);
7819     }
7820
7821     return(xmlXPathNextDescendant(ctxt, cur));
7822 }
7823
7824 /**
7825  * xmlXPathNextParent:
7826  * @ctxt:  the XPath Parser context
7827  * @cur:  the current node in the traversal
7828  *
7829  * Traversal function for the "parent" direction
7830  * The parent axis contains the parent of the context node, if there is one.
7831  *
7832  * Returns the next element following that axis
7833  */
7834 xmlNodePtr
7835 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7836     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7837     /*
7838      * the parent of an attribute or namespace node is the element
7839      * to which the attribute or namespace node is attached
7840      * Namespace handling !!!
7841      */
7842     if (cur == NULL) {
7843         if (ctxt->context->node == NULL) return(NULL);
7844         switch (ctxt->context->node->type) {
7845             case XML_ELEMENT_NODE:
7846             case XML_TEXT_NODE:
7847             case XML_CDATA_SECTION_NODE:
7848             case XML_ENTITY_REF_NODE:
7849             case XML_ENTITY_NODE:
7850             case XML_PI_NODE:
7851             case XML_COMMENT_NODE:
7852             case XML_NOTATION_NODE:
7853             case XML_DTD_NODE:
7854             case XML_ELEMENT_DECL:
7855             case XML_ATTRIBUTE_DECL:
7856             case XML_XINCLUDE_START:
7857             case XML_XINCLUDE_END:
7858             case XML_ENTITY_DECL:
7859                 if (ctxt->context->node->parent == NULL)
7860                     return((xmlNodePtr) ctxt->context->doc);
7861                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7862                     ((ctxt->context->node->parent->name[0] == ' ') ||
7863                      (xmlStrEqual(ctxt->context->node->parent->name,
7864                                  BAD_CAST "fake node libxslt"))))
7865                     return(NULL);
7866                 return(ctxt->context->node->parent);
7867             case XML_ATTRIBUTE_NODE: {
7868                 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7869
7870                 return(att->parent);
7871             }
7872             case XML_DOCUMENT_NODE:
7873             case XML_DOCUMENT_TYPE_NODE:
7874             case XML_DOCUMENT_FRAG_NODE:
7875             case XML_HTML_DOCUMENT_NODE:
7876 #ifdef LIBXML_DOCB_ENABLED
7877             case XML_DOCB_DOCUMENT_NODE:
7878 #endif
7879                 return(NULL);
7880             case XML_NAMESPACE_DECL: {
7881                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7882
7883                 if ((ns->next != NULL) &&
7884                     (ns->next->type != XML_NAMESPACE_DECL))
7885                     return((xmlNodePtr) ns->next);
7886                 return(NULL);
7887             }
7888         }
7889     }
7890     return(NULL);
7891 }
7892
7893 /**
7894  * xmlXPathNextAncestor:
7895  * @ctxt:  the XPath Parser context
7896  * @cur:  the current node in the traversal
7897  *
7898  * Traversal function for the "ancestor" direction
7899  * the ancestor axis contains the ancestors of the context node; the ancestors
7900  * of the context node consist of the parent of context node and the parent's
7901  * parent and so on; the nodes are ordered in reverse document order; thus the
7902  * parent is the first node on the axis, and the parent's parent is the second
7903  * node on the axis
7904  *
7905  * Returns the next element following that axis
7906  */
7907 xmlNodePtr
7908 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7909     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7910     /*
7911      * the parent of an attribute or namespace node is the element
7912      * to which the attribute or namespace node is attached
7913      * !!!!!!!!!!!!!
7914      */
7915     if (cur == NULL) {
7916         if (ctxt->context->node == NULL) return(NULL);
7917         switch (ctxt->context->node->type) {
7918             case XML_ELEMENT_NODE:
7919             case XML_TEXT_NODE:
7920             case XML_CDATA_SECTION_NODE:
7921             case XML_ENTITY_REF_NODE:
7922             case XML_ENTITY_NODE:
7923             case XML_PI_NODE:
7924             case XML_COMMENT_NODE:
7925             case XML_DTD_NODE:
7926             case XML_ELEMENT_DECL:
7927             case XML_ATTRIBUTE_DECL:
7928             case XML_ENTITY_DECL:
7929             case XML_NOTATION_NODE:
7930             case XML_XINCLUDE_START:
7931             case XML_XINCLUDE_END:
7932                 if (ctxt->context->node->parent == NULL)
7933                     return((xmlNodePtr) ctxt->context->doc);
7934                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7935                     ((ctxt->context->node->parent->name[0] == ' ') ||
7936                      (xmlStrEqual(ctxt->context->node->parent->name,
7937                                  BAD_CAST "fake node libxslt"))))
7938                     return(NULL);
7939                 return(ctxt->context->node->parent);
7940             case XML_ATTRIBUTE_NODE: {
7941                 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7942
7943                 return(tmp->parent);
7944             }
7945             case XML_DOCUMENT_NODE:
7946             case XML_DOCUMENT_TYPE_NODE:
7947             case XML_DOCUMENT_FRAG_NODE:
7948             case XML_HTML_DOCUMENT_NODE:
7949 #ifdef LIBXML_DOCB_ENABLED
7950             case XML_DOCB_DOCUMENT_NODE:
7951 #endif
7952                 return(NULL);
7953             case XML_NAMESPACE_DECL: {
7954                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7955
7956                 if ((ns->next != NULL) &&
7957                     (ns->next->type != XML_NAMESPACE_DECL))
7958                     return((xmlNodePtr) ns->next);
7959                 /* Bad, how did that namespace end up here ? */
7960                 return(NULL);
7961             }
7962         }
7963         return(NULL);
7964     }
7965     if (cur == ctxt->context->doc->children)
7966         return((xmlNodePtr) ctxt->context->doc);
7967     if (cur == (xmlNodePtr) ctxt->context->doc)
7968         return(NULL);
7969     switch (cur->type) {
7970         case XML_ELEMENT_NODE:
7971         case XML_TEXT_NODE:
7972         case XML_CDATA_SECTION_NODE:
7973         case XML_ENTITY_REF_NODE:
7974         case XML_ENTITY_NODE:
7975         case XML_PI_NODE:
7976         case XML_COMMENT_NODE:
7977         case XML_NOTATION_NODE:
7978         case XML_DTD_NODE:
7979         case XML_ELEMENT_DECL:
7980         case XML_ATTRIBUTE_DECL:
7981         case XML_ENTITY_DECL:
7982         case XML_XINCLUDE_START:
7983         case XML_XINCLUDE_END:
7984             if (cur->parent == NULL)
7985                 return(NULL);
7986             if ((cur->parent->type == XML_ELEMENT_NODE) &&
7987                 ((cur->parent->name[0] == ' ') ||
7988                  (xmlStrEqual(cur->parent->name,
7989                               BAD_CAST "fake node libxslt"))))
7990                 return(NULL);
7991             return(cur->parent);
7992         case XML_ATTRIBUTE_NODE: {
7993             xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7994
7995             return(att->parent);
7996         }
7997         case XML_NAMESPACE_DECL: {
7998             xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7999
8000             if ((ns->next != NULL) &&
8001                 (ns->next->type != XML_NAMESPACE_DECL))
8002                 return((xmlNodePtr) ns->next);
8003             /* Bad, how did that namespace end up here ? */
8004             return(NULL);
8005         }
8006         case XML_DOCUMENT_NODE:
8007         case XML_DOCUMENT_TYPE_NODE:
8008         case XML_DOCUMENT_FRAG_NODE:
8009         case XML_HTML_DOCUMENT_NODE:
8010 #ifdef LIBXML_DOCB_ENABLED
8011         case XML_DOCB_DOCUMENT_NODE:
8012 #endif
8013             return(NULL);
8014     }
8015     return(NULL);
8016 }
8017
8018 /**
8019  * xmlXPathNextAncestorOrSelf:
8020  * @ctxt:  the XPath Parser context
8021  * @cur:  the current node in the traversal
8022  *
8023  * Traversal function for the "ancestor-or-self" direction
8024  * he ancestor-or-self axis contains the context node and ancestors of
8025  * the context node in reverse document order; thus the context node is
8026  * the first node on the axis, and the context node's parent the second;
8027  * parent here is defined the same as with the parent axis.
8028  *
8029  * Returns the next element following that axis
8030  */
8031 xmlNodePtr
8032 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8033     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8034     if (cur == NULL)
8035         return(ctxt->context->node);
8036     return(xmlXPathNextAncestor(ctxt, cur));
8037 }
8038
8039 /**
8040  * xmlXPathNextFollowingSibling:
8041  * @ctxt:  the XPath Parser context
8042  * @cur:  the current node in the traversal
8043  *
8044  * Traversal function for the "following-sibling" direction
8045  * The following-sibling axis contains the following siblings of the context
8046  * node in document order.
8047  *
8048  * Returns the next element following that axis
8049  */
8050 xmlNodePtr
8051 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8052     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8053     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8054         (ctxt->context->node->type == XML_NAMESPACE_DECL))
8055         return(NULL);
8056     if (cur == (xmlNodePtr) ctxt->context->doc)
8057         return(NULL);
8058     if (cur == NULL)
8059         return(ctxt->context->node->next);
8060     return(cur->next);
8061 }
8062
8063 /**
8064  * xmlXPathNextPrecedingSibling:
8065  * @ctxt:  the XPath Parser context
8066  * @cur:  the current node in the traversal
8067  *
8068  * Traversal function for the "preceding-sibling" direction
8069  * The preceding-sibling axis contains the preceding siblings of the context
8070  * node in reverse document order; the first preceding sibling is first on the
8071  * axis; the sibling preceding that node is the second on the axis and so on.
8072  *
8073  * Returns the next element following that axis
8074  */
8075 xmlNodePtr
8076 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8077     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8078     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8079         (ctxt->context->node->type == XML_NAMESPACE_DECL))
8080         return(NULL);
8081     if (cur == (xmlNodePtr) ctxt->context->doc)
8082         return(NULL);
8083     if (cur == NULL)
8084         return(ctxt->context->node->prev);
8085     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8086         cur = cur->prev;
8087         if (cur == NULL)
8088             return(ctxt->context->node->prev);
8089     }
8090     return(cur->prev);
8091 }
8092
8093 /**
8094  * xmlXPathNextFollowing:
8095  * @ctxt:  the XPath Parser context
8096  * @cur:  the current node in the traversal
8097  *
8098  * Traversal function for the "following" direction
8099  * The following axis contains all nodes in the same document as the context
8100  * node that are after the context node in document order, excluding any
8101  * descendants and excluding attribute nodes and namespace nodes; the nodes
8102  * are ordered in document order
8103  *
8104  * Returns the next element following that axis
8105  */
8106 xmlNodePtr
8107 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8108     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8109     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8110         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8111         return(cur->children);
8112
8113     if (cur == NULL) {
8114         cur = ctxt->context->node;
8115         if (cur->type == XML_NAMESPACE_DECL)
8116             return(NULL);
8117         if (cur->type == XML_ATTRIBUTE_NODE)
8118             cur = cur->parent;
8119     }
8120     if (cur == NULL) return(NULL) ; /* ERROR */
8121     if (cur->next != NULL) return(cur->next) ;
8122     do {
8123         cur = cur->parent;
8124         if (cur == NULL) break;
8125         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8126         if (cur->next != NULL) return(cur->next);
8127     } while (cur != NULL);
8128     return(cur);
8129 }
8130
8131 /*
8132  * xmlXPathIsAncestor:
8133  * @ancestor:  the ancestor node
8134  * @node:  the current node
8135  *
8136  * Check that @ancestor is a @node's ancestor
8137  *
8138  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8139  */
8140 static int
8141 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8142     if ((ancestor == NULL) || (node == NULL)) return(0);
8143     /* nodes need to be in the same document */
8144     if (ancestor->doc != node->doc) return(0);
8145     /* avoid searching if ancestor or node is the root node */
8146     if (ancestor == (xmlNodePtr) node->doc) return(1);
8147     if (node == (xmlNodePtr) ancestor->doc) return(0);
8148     while (node->parent != NULL) {
8149         if (node->parent == ancestor)
8150             return(1);
8151         node = node->parent;
8152     }
8153     return(0);
8154 }
8155
8156 /**
8157  * xmlXPathNextPreceding:
8158  * @ctxt:  the XPath Parser context
8159  * @cur:  the current node in the traversal
8160  *
8161  * Traversal function for the "preceding" direction
8162  * the preceding axis contains all nodes in the same document as the context
8163  * node that are before the context node in document order, excluding any
8164  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8165  * ordered in reverse document order
8166  *
8167  * Returns the next element following that axis
8168  */
8169 xmlNodePtr
8170 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8171 {
8172     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8173     if (cur == NULL) {
8174         cur = ctxt->context->node;
8175         if (cur->type == XML_NAMESPACE_DECL)
8176             return(NULL);
8177         if (cur->type == XML_ATTRIBUTE_NODE)
8178             return(cur->parent);
8179     }
8180     if (cur == NULL)
8181         return (NULL);
8182     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8183         cur = cur->prev;
8184     do {
8185         if (cur->prev != NULL) {
8186             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8187             return (cur);
8188         }
8189
8190         cur = cur->parent;
8191         if (cur == NULL)
8192             return (NULL);
8193         if (cur == ctxt->context->doc->children)
8194             return (NULL);
8195     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8196     return (cur);
8197 }
8198
8199 /**
8200  * xmlXPathNextPrecedingInternal:
8201  * @ctxt:  the XPath Parser context
8202  * @cur:  the current node in the traversal
8203  *
8204  * Traversal function for the "preceding" direction
8205  * the preceding axis contains all nodes in the same document as the context
8206  * node that are before the context node in document order, excluding any
8207  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8208  * ordered in reverse document order
8209  * This is a faster implementation but internal only since it requires a
8210  * state kept in the parser context: ctxt->ancestor.
8211  *
8212  * Returns the next element following that axis
8213  */
8214 static xmlNodePtr
8215 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8216                               xmlNodePtr cur)
8217 {
8218     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8219     if (cur == NULL) {
8220         cur = ctxt->context->node;
8221         if (cur == NULL)
8222             return (NULL);
8223         if (cur->type == XML_NAMESPACE_DECL)
8224             return (NULL);
8225         ctxt->ancestor = cur->parent;
8226     }
8227     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8228         cur = cur->prev;
8229     while (cur->prev == NULL) {
8230         cur = cur->parent;
8231         if (cur == NULL)
8232             return (NULL);
8233         if (cur == ctxt->context->doc->children)
8234             return (NULL);
8235         if (cur != ctxt->ancestor)
8236             return (cur);
8237         ctxt->ancestor = cur->parent;
8238     }
8239     cur = cur->prev;
8240     while (cur->last != NULL)
8241         cur = cur->last;
8242     return (cur);
8243 }
8244
8245 /**
8246  * xmlXPathNextNamespace:
8247  * @ctxt:  the XPath Parser context
8248  * @cur:  the current attribute in the traversal
8249  *
8250  * Traversal function for the "namespace" direction
8251  * the namespace axis contains the namespace nodes of the context node;
8252  * the order of nodes on this axis is implementation-defined; the axis will
8253  * be empty unless the context node is an element
8254  *
8255  * We keep the XML namespace node at the end of the list.
8256  *
8257  * Returns the next element following that axis
8258  */
8259 xmlNodePtr
8260 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8261     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8262     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8263     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8264         if (ctxt->context->tmpNsList != NULL)
8265             xmlFree(ctxt->context->tmpNsList);
8266         ctxt->context->tmpNsList =
8267             xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8268         ctxt->context->tmpNsNr = 0;
8269         if (ctxt->context->tmpNsList != NULL) {
8270             while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8271                 ctxt->context->tmpNsNr++;
8272             }
8273         }
8274         return((xmlNodePtr) xmlXPathXMLNamespace);
8275     }
8276     if (ctxt->context->tmpNsNr > 0) {
8277         return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8278     } else {
8279         if (ctxt->context->tmpNsList != NULL)
8280             xmlFree(ctxt->context->tmpNsList);
8281         ctxt->context->tmpNsList = NULL;
8282         return(NULL);
8283     }
8284 }
8285
8286 /**
8287  * xmlXPathNextAttribute:
8288  * @ctxt:  the XPath Parser context
8289  * @cur:  the current attribute in the traversal
8290  *
8291  * Traversal function for the "attribute" direction
8292  * TODO: support DTD inherited default attributes
8293  *
8294  * Returns the next element following that axis
8295  */
8296 xmlNodePtr
8297 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8298     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8299     if (ctxt->context->node == NULL)
8300         return(NULL);
8301     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8302         return(NULL);
8303     if (cur == NULL) {
8304         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8305             return(NULL);
8306         return((xmlNodePtr)ctxt->context->node->properties);
8307     }
8308     return((xmlNodePtr)cur->next);
8309 }
8310
8311 /************************************************************************
8312  *                                                                      *
8313  *              NodeTest Functions                                      *
8314  *                                                                      *
8315  ************************************************************************/
8316
8317 #define IS_FUNCTION                     200
8318
8319
8320 /************************************************************************
8321  *                                                                      *
8322  *              Implicit tree core function library                     *
8323  *                                                                      *
8324  ************************************************************************/
8325
8326 /**
8327  * xmlXPathRoot:
8328  * @ctxt:  the XPath Parser context
8329  *
8330  * Initialize the context to the root of the document
8331  */
8332 void
8333 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8334     if ((ctxt == NULL) || (ctxt->context == NULL))
8335         return;
8336     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8337     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8338         ctxt->context->node));
8339 }
8340
8341 /************************************************************************
8342  *                                                                      *
8343  *              The explicit core function library                      *
8344  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8345  *                                                                      *
8346  ************************************************************************/
8347
8348
8349 /**
8350  * xmlXPathLastFunction:
8351  * @ctxt:  the XPath Parser context
8352  * @nargs:  the number of arguments
8353  *
8354  * Implement the last() XPath function
8355  *    number last()
8356  * The last function returns the number of nodes in the context node list.
8357  */
8358 void
8359 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8360     CHECK_ARITY(0);
8361     if (ctxt->context->contextSize >= 0) {
8362         valuePush(ctxt,
8363             xmlXPathCacheNewFloat(ctxt->context,
8364                 (double) ctxt->context->contextSize));
8365 #ifdef DEBUG_EXPR
8366         xmlGenericError(xmlGenericErrorContext,
8367                 "last() : %d\n", ctxt->context->contextSize);
8368 #endif
8369     } else {
8370         XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8371     }
8372 }
8373
8374 /**
8375  * xmlXPathPositionFunction:
8376  * @ctxt:  the XPath Parser context
8377  * @nargs:  the number of arguments
8378  *
8379  * Implement the position() XPath function
8380  *    number position()
8381  * The position function returns the position of the context node in the
8382  * context node list. The first position is 1, and so the last position
8383  * will be equal to last().
8384  */
8385 void
8386 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8387     CHECK_ARITY(0);
8388     if (ctxt->context->proximityPosition >= 0) {
8389         valuePush(ctxt,
8390               xmlXPathCacheNewFloat(ctxt->context,
8391                 (double) ctxt->context->proximityPosition));
8392 #ifdef DEBUG_EXPR
8393         xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8394                 ctxt->context->proximityPosition);
8395 #endif
8396     } else {
8397         XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8398     }
8399 }
8400
8401 /**
8402  * xmlXPathCountFunction:
8403  * @ctxt:  the XPath Parser context
8404  * @nargs:  the number of arguments
8405  *
8406  * Implement the count() XPath function
8407  *    number count(node-set)
8408  */
8409 void
8410 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8411     xmlXPathObjectPtr cur;
8412
8413     CHECK_ARITY(1);
8414     if ((ctxt->value == NULL) ||
8415         ((ctxt->value->type != XPATH_NODESET) &&
8416          (ctxt->value->type != XPATH_XSLT_TREE)))
8417         XP_ERROR(XPATH_INVALID_TYPE);
8418     cur = valuePop(ctxt);
8419
8420     if ((cur == NULL) || (cur->nodesetval == NULL))
8421         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8422     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8423         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8424             (double) cur->nodesetval->nodeNr));
8425     } else {
8426         if ((cur->nodesetval->nodeNr != 1) ||
8427             (cur->nodesetval->nodeTab == NULL)) {
8428             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8429         } else {
8430             xmlNodePtr tmp;
8431             int i = 0;
8432
8433             tmp = cur->nodesetval->nodeTab[0];
8434             if (tmp != NULL) {
8435                 tmp = tmp->children;
8436                 while (tmp != NULL) {
8437                     tmp = tmp->next;
8438                     i++;
8439                 }
8440             }
8441             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8442         }
8443     }
8444     xmlXPathReleaseObject(ctxt->context, cur);
8445 }
8446
8447 /**
8448  * xmlXPathGetElementsByIds:
8449  * @doc:  the document
8450  * @ids:  a whitespace separated list of IDs
8451  *
8452  * Selects elements by their unique ID.
8453  *
8454  * Returns a node-set of selected elements.
8455  */
8456 static xmlNodeSetPtr
8457 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8458     xmlNodeSetPtr ret;
8459     const xmlChar *cur = ids;
8460     xmlChar *ID;
8461     xmlAttrPtr attr;
8462     xmlNodePtr elem = NULL;
8463
8464     if (ids == NULL) return(NULL);
8465
8466     ret = xmlXPathNodeSetCreate(NULL);
8467     if (ret == NULL)
8468         return(ret);
8469
8470     while (IS_BLANK_CH(*cur)) cur++;
8471     while (*cur != 0) {
8472         while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8473             cur++;
8474
8475         ID = xmlStrndup(ids, cur - ids);
8476         if (ID != NULL) {
8477             /*
8478              * We used to check the fact that the value passed
8479              * was an NCName, but this generated much troubles for
8480              * me and Aleksey Sanin, people blatantly violated that
8481              * constaint, like Visa3D spec.
8482              * if (xmlValidateNCName(ID, 1) == 0)
8483              */
8484             attr = xmlGetID(doc, ID);
8485             if (attr != NULL) {
8486                 if (attr->type == XML_ATTRIBUTE_NODE)
8487                     elem = attr->parent;
8488                 else if (attr->type == XML_ELEMENT_NODE)
8489                     elem = (xmlNodePtr) attr;
8490                 else
8491                     elem = NULL;
8492                 if (elem != NULL)
8493                     xmlXPathNodeSetAdd(ret, elem);
8494             }
8495             xmlFree(ID);
8496         }
8497
8498         while (IS_BLANK_CH(*cur)) cur++;
8499         ids = cur;
8500     }
8501     return(ret);
8502 }
8503
8504 /**
8505  * xmlXPathIdFunction:
8506  * @ctxt:  the XPath Parser context
8507  * @nargs:  the number of arguments
8508  *
8509  * Implement the id() XPath function
8510  *    node-set id(object)
8511  * The id function selects elements by their unique ID
8512  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8513  * then the result is the union of the result of applying id to the
8514  * string value of each of the nodes in the argument node-set. When the
8515  * argument to id is of any other type, the argument is converted to a
8516  * string as if by a call to the string function; the string is split
8517  * into a whitespace-separated list of tokens (whitespace is any sequence
8518  * of characters matching the production S); the result is a node-set
8519  * containing the elements in the same document as the context node that
8520  * have a unique ID equal to any of the tokens in the list.
8521  */
8522 void
8523 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8524     xmlChar *tokens;
8525     xmlNodeSetPtr ret;
8526     xmlXPathObjectPtr obj;
8527
8528     CHECK_ARITY(1);
8529     obj = valuePop(ctxt);
8530     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8531     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8532         xmlNodeSetPtr ns;
8533         int i;
8534
8535         ret = xmlXPathNodeSetCreate(NULL);
8536         /*
8537          * FIXME -- in an out-of-memory condition this will behave badly.
8538          * The solution is not clear -- we already popped an item from
8539          * ctxt, so the object is in a corrupt state.
8540          */
8541
8542         if (obj->nodesetval != NULL) {
8543             for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8544                 tokens =
8545                     xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8546                 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8547                 ret = xmlXPathNodeSetMerge(ret, ns);
8548                 xmlXPathFreeNodeSet(ns);
8549                 if (tokens != NULL)
8550                     xmlFree(tokens);
8551             }
8552         }
8553         xmlXPathReleaseObject(ctxt->context, obj);
8554         valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8555         return;
8556     }
8557     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8558     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8559     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8560     xmlXPathReleaseObject(ctxt->context, obj);
8561     return;
8562 }
8563
8564 /**
8565  * xmlXPathLocalNameFunction:
8566  * @ctxt:  the XPath Parser context
8567  * @nargs:  the number of arguments
8568  *
8569  * Implement the local-name() XPath function
8570  *    string local-name(node-set?)
8571  * The local-name function returns a string containing the local part
8572  * of the name of the node in the argument node-set that is first in
8573  * document order. If the node-set is empty or the first node has no
8574  * name, an empty string is returned. If the argument is omitted it
8575  * defaults to the context node.
8576  */
8577 void
8578 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8579     xmlXPathObjectPtr cur;
8580
8581     if (ctxt == NULL) return;
8582
8583     if (nargs == 0) {
8584         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8585             ctxt->context->node));
8586         nargs = 1;
8587     }
8588
8589     CHECK_ARITY(1);
8590     if ((ctxt->value == NULL) ||
8591         ((ctxt->value->type != XPATH_NODESET) &&
8592          (ctxt->value->type != XPATH_XSLT_TREE)))
8593         XP_ERROR(XPATH_INVALID_TYPE);
8594     cur = valuePop(ctxt);
8595
8596     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8597         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8598     } else {
8599         int i = 0; /* Should be first in document order !!!!! */
8600         switch (cur->nodesetval->nodeTab[i]->type) {
8601         case XML_ELEMENT_NODE:
8602         case XML_ATTRIBUTE_NODE:
8603         case XML_PI_NODE:
8604             if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8605                 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8606             else
8607                 valuePush(ctxt,
8608                       xmlXPathCacheNewString(ctxt->context,
8609                         cur->nodesetval->nodeTab[i]->name));
8610             break;
8611         case XML_NAMESPACE_DECL:
8612             valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8613                         ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8614             break;
8615         default:
8616             valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8617         }
8618     }
8619     xmlXPathReleaseObject(ctxt->context, cur);
8620 }
8621
8622 /**
8623  * xmlXPathNamespaceURIFunction:
8624  * @ctxt:  the XPath Parser context
8625  * @nargs:  the number of arguments
8626  *
8627  * Implement the namespace-uri() XPath function
8628  *    string namespace-uri(node-set?)
8629  * The namespace-uri function returns a string containing the
8630  * namespace URI of the expanded name of the node in the argument
8631  * node-set that is first in document order. If the node-set is empty,
8632  * the first node has no name, or the expanded name has no namespace
8633  * URI, an empty string is returned. If the argument is omitted it
8634  * defaults to the context node.
8635  */
8636 void
8637 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8638     xmlXPathObjectPtr cur;
8639
8640     if (ctxt == NULL) return;
8641
8642     if (nargs == 0) {
8643         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8644             ctxt->context->node));
8645         nargs = 1;
8646     }
8647     CHECK_ARITY(1);
8648     if ((ctxt->value == NULL) ||
8649         ((ctxt->value->type != XPATH_NODESET) &&
8650          (ctxt->value->type != XPATH_XSLT_TREE)))
8651         XP_ERROR(XPATH_INVALID_TYPE);
8652     cur = valuePop(ctxt);
8653
8654     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8655         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8656     } else {
8657         int i = 0; /* Should be first in document order !!!!! */
8658         switch (cur->nodesetval->nodeTab[i]->type) {
8659         case XML_ELEMENT_NODE:
8660         case XML_ATTRIBUTE_NODE:
8661             if (cur->nodesetval->nodeTab[i]->ns == NULL)
8662                 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8663             else
8664                 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8665                           cur->nodesetval->nodeTab[i]->ns->href));
8666             break;
8667         default:
8668             valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8669         }
8670     }
8671     xmlXPathReleaseObject(ctxt->context, cur);
8672 }
8673
8674 /**
8675  * xmlXPathNameFunction:
8676  * @ctxt:  the XPath Parser context
8677  * @nargs:  the number of arguments
8678  *
8679  * Implement the name() XPath function
8680  *    string name(node-set?)
8681  * The name function returns a string containing a QName representing
8682  * the name of the node in the argument node-set that is first in document
8683  * order. The QName must represent the name with respect to the namespace
8684  * declarations in effect on the node whose name is being represented.
8685  * Typically, this will be the form in which the name occurred in the XML
8686  * source. This need not be the case if there are namespace declarations
8687  * in effect on the node that associate multiple prefixes with the same
8688  * namespace. However, an implementation may include information about
8689  * the original prefix in its representation of nodes; in this case, an
8690  * implementation can ensure that the returned string is always the same
8691  * as the QName used in the XML source. If the argument it omitted it
8692  * defaults to the context node.
8693  * Libxml keep the original prefix so the "real qualified name" used is
8694  * returned.
8695  */
8696 static void
8697 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8698 {
8699     xmlXPathObjectPtr cur;
8700
8701     if (nargs == 0) {
8702         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8703             ctxt->context->node));
8704         nargs = 1;
8705     }
8706
8707     CHECK_ARITY(1);
8708     if ((ctxt->value == NULL) ||
8709         ((ctxt->value->type != XPATH_NODESET) &&
8710          (ctxt->value->type != XPATH_XSLT_TREE)))
8711         XP_ERROR(XPATH_INVALID_TYPE);
8712     cur = valuePop(ctxt);
8713
8714     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8715         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8716     } else {
8717         int i = 0;              /* Should be first in document order !!!!! */
8718
8719         switch (cur->nodesetval->nodeTab[i]->type) {
8720             case XML_ELEMENT_NODE:
8721             case XML_ATTRIBUTE_NODE:
8722                 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8723                     valuePush(ctxt,
8724                         xmlXPathCacheNewCString(ctxt->context, ""));
8725                 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8726                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8727                     valuePush(ctxt,
8728                         xmlXPathCacheNewString(ctxt->context,
8729                             cur->nodesetval->nodeTab[i]->name));
8730                 } else {
8731                     xmlChar *fullname;
8732
8733                     fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8734                                      cur->nodesetval->nodeTab[i]->ns->prefix,
8735                                      NULL, 0);
8736                     if (fullname == cur->nodesetval->nodeTab[i]->name)
8737                         fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8738                     if (fullname == NULL) {
8739                         XP_ERROR(XPATH_MEMORY_ERROR);
8740                     }
8741                     valuePush(ctxt, xmlXPathCacheWrapString(
8742                         ctxt->context, fullname));
8743                 }
8744                 break;
8745             default:
8746                 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8747                     cur->nodesetval->nodeTab[i]));
8748                 xmlXPathLocalNameFunction(ctxt, 1);
8749         }
8750     }
8751     xmlXPathReleaseObject(ctxt->context, cur);
8752 }
8753
8754
8755 /**
8756  * xmlXPathStringFunction:
8757  * @ctxt:  the XPath Parser context
8758  * @nargs:  the number of arguments
8759  *
8760  * Implement the string() XPath function
8761  *    string string(object?)
8762  * The string function converts an object to a string as follows:
8763  *    - A node-set is converted to a string by returning the value of
8764  *      the node in the node-set that is first in document order.
8765  *      If the node-set is empty, an empty string is returned.
8766  *    - A number is converted to a string as follows
8767  *      + NaN is converted to the string NaN
8768  *      + positive zero is converted to the string 0
8769  *      + negative zero is converted to the string 0
8770  *      + positive infinity is converted to the string Infinity
8771  *      + negative infinity is converted to the string -Infinity
8772  *      + if the number is an integer, the number is represented in
8773  *        decimal form as a Number with no decimal point and no leading
8774  *        zeros, preceded by a minus sign (-) if the number is negative
8775  *      + otherwise, the number is represented in decimal form as a
8776  *        Number including a decimal point with at least one digit
8777  *        before the decimal point and at least one digit after the
8778  *        decimal point, preceded by a minus sign (-) if the number
8779  *        is negative; there must be no leading zeros before the decimal
8780  *        point apart possibly from the one required digit immediately
8781  *        before the decimal point; beyond the one required digit
8782  *        after the decimal point there must be as many, but only as
8783  *        many, more digits as are needed to uniquely distinguish the
8784  *        number from all other IEEE 754 numeric values.
8785  *    - The boolean false value is converted to the string false.
8786  *      The boolean true value is converted to the string true.
8787  *
8788  * If the argument is omitted, it defaults to a node-set with the
8789  * context node as its only member.
8790  */
8791 void
8792 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8793     xmlXPathObjectPtr cur;
8794
8795     if (ctxt == NULL) return;
8796     if (nargs == 0) {
8797     valuePush(ctxt,
8798         xmlXPathCacheWrapString(ctxt->context,
8799             xmlXPathCastNodeToString(ctxt->context->node)));
8800         return;
8801     }
8802
8803     CHECK_ARITY(1);
8804     cur = valuePop(ctxt);
8805     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8806     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8807 }
8808
8809 /**
8810  * xmlXPathStringLengthFunction:
8811  * @ctxt:  the XPath Parser context
8812  * @nargs:  the number of arguments
8813  *
8814  * Implement the string-length() XPath function
8815  *    number string-length(string?)
8816  * The string-length returns the number of characters in the string
8817  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8818  * the context node converted to a string, in other words the value
8819  * of the context node.
8820  */
8821 void
8822 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8823     xmlXPathObjectPtr cur;
8824
8825     if (nargs == 0) {
8826         if ((ctxt == NULL) || (ctxt->context == NULL))
8827             return;
8828         if (ctxt->context->node == NULL) {
8829             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8830         } else {
8831             xmlChar *content;
8832
8833             content = xmlXPathCastNodeToString(ctxt->context->node);
8834             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8835                 xmlUTF8Strlen(content)));
8836             xmlFree(content);
8837         }
8838         return;
8839     }
8840     CHECK_ARITY(1);
8841     CAST_TO_STRING;
8842     CHECK_TYPE(XPATH_STRING);
8843     cur = valuePop(ctxt);
8844     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8845         xmlUTF8Strlen(cur->stringval)));
8846     xmlXPathReleaseObject(ctxt->context, cur);
8847 }
8848
8849 /**
8850  * xmlXPathConcatFunction:
8851  * @ctxt:  the XPath Parser context
8852  * @nargs:  the number of arguments
8853  *
8854  * Implement the concat() XPath function
8855  *    string concat(string, string, string*)
8856  * The concat function returns the concatenation of its arguments.
8857  */
8858 void
8859 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8860     xmlXPathObjectPtr cur, newobj;
8861     xmlChar *tmp;
8862
8863     if (ctxt == NULL) return;
8864     if (nargs < 2) {
8865         CHECK_ARITY(2);
8866     }
8867
8868     CAST_TO_STRING;
8869     cur = valuePop(ctxt);
8870     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8871         xmlXPathReleaseObject(ctxt->context, cur);
8872         return;
8873     }
8874     nargs--;
8875
8876     while (nargs > 0) {
8877         CAST_TO_STRING;
8878         newobj = valuePop(ctxt);
8879         if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8880             xmlXPathReleaseObject(ctxt->context, newobj);
8881             xmlXPathReleaseObject(ctxt->context, cur);
8882             XP_ERROR(XPATH_INVALID_TYPE);
8883         }
8884         tmp = xmlStrcat(newobj->stringval, cur->stringval);
8885         newobj->stringval = cur->stringval;
8886         cur->stringval = tmp;
8887         xmlXPathReleaseObject(ctxt->context, newobj);
8888         nargs--;
8889     }
8890     valuePush(ctxt, cur);
8891 }
8892
8893 /**
8894  * xmlXPathContainsFunction:
8895  * @ctxt:  the XPath Parser context
8896  * @nargs:  the number of arguments
8897  *
8898  * Implement the contains() XPath function
8899  *    boolean contains(string, string)
8900  * The contains function returns true if the first argument string
8901  * contains the second argument string, and otherwise returns false.
8902  */
8903 void
8904 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8905     xmlXPathObjectPtr hay, needle;
8906
8907     CHECK_ARITY(2);
8908     CAST_TO_STRING;
8909     CHECK_TYPE(XPATH_STRING);
8910     needle = valuePop(ctxt);
8911     CAST_TO_STRING;
8912     hay = valuePop(ctxt);
8913
8914     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8915         xmlXPathReleaseObject(ctxt->context, hay);
8916         xmlXPathReleaseObject(ctxt->context, needle);
8917         XP_ERROR(XPATH_INVALID_TYPE);
8918     }
8919     if (xmlStrstr(hay->stringval, needle->stringval))
8920         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8921     else
8922         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8923     xmlXPathReleaseObject(ctxt->context, hay);
8924     xmlXPathReleaseObject(ctxt->context, needle);
8925 }
8926
8927 /**
8928  * xmlXPathStartsWithFunction:
8929  * @ctxt:  the XPath Parser context
8930  * @nargs:  the number of arguments
8931  *
8932  * Implement the starts-with() XPath function
8933  *    boolean starts-with(string, string)
8934  * The starts-with function returns true if the first argument string
8935  * starts with the second argument string, and otherwise returns false.
8936  */
8937 void
8938 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8939     xmlXPathObjectPtr hay, needle;
8940     int n;
8941
8942     CHECK_ARITY(2);
8943     CAST_TO_STRING;
8944     CHECK_TYPE(XPATH_STRING);
8945     needle = valuePop(ctxt);
8946     CAST_TO_STRING;
8947     hay = valuePop(ctxt);
8948
8949     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8950         xmlXPathReleaseObject(ctxt->context, hay);
8951         xmlXPathReleaseObject(ctxt->context, needle);
8952         XP_ERROR(XPATH_INVALID_TYPE);
8953     }
8954     n = xmlStrlen(needle->stringval);
8955     if (xmlStrncmp(hay->stringval, needle->stringval, n))
8956         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8957     else
8958         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8959     xmlXPathReleaseObject(ctxt->context, hay);
8960     xmlXPathReleaseObject(ctxt->context, needle);
8961 }
8962
8963 /**
8964  * xmlXPathSubstringFunction:
8965  * @ctxt:  the XPath Parser context
8966  * @nargs:  the number of arguments
8967  *
8968  * Implement the substring() XPath function
8969  *    string substring(string, number, number?)
8970  * The substring function returns the substring of the first argument
8971  * starting at the position specified in the second argument with
8972  * length specified in the third argument. For example,
8973  * substring("12345",2,3) returns "234". If the third argument is not
8974  * specified, it returns the substring starting at the position specified
8975  * in the second argument and continuing to the end of the string. For
8976  * example, substring("12345",2) returns "2345".  More precisely, each
8977  * character in the string (see [3.6 Strings]) is considered to have a
8978  * numeric position: the position of the first character is 1, the position
8979  * of the second character is 2 and so on. The returned substring contains
8980  * those characters for which the position of the character is greater than
8981  * or equal to the second argument and, if the third argument is specified,
8982  * less than the sum of the second and third arguments; the comparisons
8983  * and addition used for the above follow the standard IEEE 754 rules. Thus:
8984  *  - substring("12345", 1.5, 2.6) returns "234"
8985  *  - substring("12345", 0, 3) returns "12"
8986  *  - substring("12345", 0 div 0, 3) returns ""
8987  *  - substring("12345", 1, 0 div 0) returns ""
8988  *  - substring("12345", -42, 1 div 0) returns "12345"
8989  *  - substring("12345", -1 div 0, 1 div 0) returns ""
8990  */
8991 void
8992 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8993     xmlXPathObjectPtr str, start, len;
8994     double le=0, in;
8995     int i, l, m;
8996     xmlChar *ret;
8997
8998     if (nargs < 2) {
8999         CHECK_ARITY(2);
9000     }
9001     if (nargs > 3) {
9002         CHECK_ARITY(3);
9003     }
9004     /*
9005      * take care of possible last (position) argument
9006     */
9007     if (nargs == 3) {
9008         CAST_TO_NUMBER;
9009         CHECK_TYPE(XPATH_NUMBER);
9010         len = valuePop(ctxt);
9011         le = len->floatval;
9012         xmlXPathReleaseObject(ctxt->context, len);
9013     }
9014
9015     CAST_TO_NUMBER;
9016     CHECK_TYPE(XPATH_NUMBER);
9017     start = valuePop(ctxt);
9018     in = start->floatval;
9019     xmlXPathReleaseObject(ctxt->context, start);
9020     CAST_TO_STRING;
9021     CHECK_TYPE(XPATH_STRING);
9022     str = valuePop(ctxt);
9023     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9024
9025     /*
9026      * If last pos not present, calculate last position
9027     */
9028     if (nargs != 3) {
9029         le = (double)m;
9030         if (in < 1.0)
9031             in = 1.0;
9032     }
9033
9034     /* Need to check for the special cases where either
9035      * the index is NaN, the length is NaN, or both
9036      * arguments are infinity (relying on Inf + -Inf = NaN)
9037      */
9038     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9039         /*
9040          * To meet the requirements of the spec, the arguments
9041          * must be converted to integer format before
9042          * initial index calculations are done
9043          *
9044          * First we go to integer form, rounding up
9045          * and checking for special cases
9046          */
9047         i = (int) in;
9048         if (((double)i)+0.5 <= in) i++;
9049
9050         if (xmlXPathIsInf(le) == 1) {
9051             l = m;
9052             if (i < 1)
9053                 i = 1;
9054         }
9055         else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9056             l = 0;
9057         else {
9058             l = (int) le;
9059             if (((double)l)+0.5 <= le) l++;
9060         }
9061
9062         /* Now we normalize inidices */
9063         i -= 1;
9064         l += i;
9065         if (i < 0)
9066             i = 0;
9067         if (l > m)
9068             l = m;
9069
9070         /* number of chars to copy */
9071         l -= i;
9072
9073         ret = xmlUTF8Strsub(str->stringval, i, l);
9074     }
9075     else {
9076         ret = NULL;
9077     }
9078     if (ret == NULL)
9079         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9080     else {
9081         valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9082         xmlFree(ret);
9083     }
9084     xmlXPathReleaseObject(ctxt->context, str);
9085 }
9086
9087 /**
9088  * xmlXPathSubstringBeforeFunction:
9089  * @ctxt:  the XPath Parser context
9090  * @nargs:  the number of arguments
9091  *
9092  * Implement the substring-before() XPath function
9093  *    string substring-before(string, string)
9094  * The substring-before function returns the substring of the first
9095  * argument string that precedes the first occurrence of the second
9096  * argument string in the first argument string, or the empty string
9097  * if the first argument string does not contain the second argument
9098  * string. For example, substring-before("1999/04/01","/") returns 1999.
9099  */
9100 void
9101 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9102   xmlXPathObjectPtr str;
9103   xmlXPathObjectPtr find;
9104   xmlBufferPtr target;
9105   const xmlChar *point;
9106   int offset;
9107
9108   CHECK_ARITY(2);
9109   CAST_TO_STRING;
9110   find = valuePop(ctxt);
9111   CAST_TO_STRING;
9112   str = valuePop(ctxt);
9113
9114   target = xmlBufferCreate();
9115   if (target) {
9116     point = xmlStrstr(str->stringval, find->stringval);
9117     if (point) {
9118       offset = (int)(point - str->stringval);
9119       xmlBufferAdd(target, str->stringval, offset);
9120     }
9121     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9122         xmlBufferContent(target)));
9123     xmlBufferFree(target);
9124   }
9125   xmlXPathReleaseObject(ctxt->context, str);
9126   xmlXPathReleaseObject(ctxt->context, find);
9127 }
9128
9129 /**
9130  * xmlXPathSubstringAfterFunction:
9131  * @ctxt:  the XPath Parser context
9132  * @nargs:  the number of arguments
9133  *
9134  * Implement the substring-after() XPath function
9135  *    string substring-after(string, string)
9136  * The substring-after function returns the substring of the first
9137  * argument string that follows the first occurrence of the second
9138  * argument string in the first argument string, or the empty stringi
9139  * if the first argument string does not contain the second argument
9140  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9141  * and substring-after("1999/04/01","19") returns 99/04/01.
9142  */
9143 void
9144 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9145   xmlXPathObjectPtr str;
9146   xmlXPathObjectPtr find;
9147   xmlBufferPtr target;
9148   const xmlChar *point;
9149   int offset;
9150
9151   CHECK_ARITY(2);
9152   CAST_TO_STRING;
9153   find = valuePop(ctxt);
9154   CAST_TO_STRING;
9155   str = valuePop(ctxt);
9156
9157   target = xmlBufferCreate();
9158   if (target) {
9159     point = xmlStrstr(str->stringval, find->stringval);
9160     if (point) {
9161       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9162       xmlBufferAdd(target, &str->stringval[offset],
9163                    xmlStrlen(str->stringval) - offset);
9164     }
9165     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9166         xmlBufferContent(target)));
9167     xmlBufferFree(target);
9168   }
9169   xmlXPathReleaseObject(ctxt->context, str);
9170   xmlXPathReleaseObject(ctxt->context, find);
9171 }
9172
9173 /**
9174  * xmlXPathNormalizeFunction:
9175  * @ctxt:  the XPath Parser context
9176  * @nargs:  the number of arguments
9177  *
9178  * Implement the normalize-space() XPath function
9179  *    string normalize-space(string?)
9180  * The normalize-space function returns the argument string with white
9181  * space normalized by stripping leading and trailing whitespace
9182  * and replacing sequences of whitespace characters by a single
9183  * space. Whitespace characters are the same allowed by the S production
9184  * in XML. If the argument is omitted, it defaults to the context
9185  * node converted to a string, in other words the value of the context node.
9186  */
9187 void
9188 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9189   xmlXPathObjectPtr obj = NULL;
9190   xmlChar *source = NULL;
9191   xmlBufferPtr target;
9192   xmlChar blank;
9193
9194   if (ctxt == NULL) return;
9195   if (nargs == 0) {
9196     /* Use current context node */
9197       valuePush(ctxt,
9198           xmlXPathCacheWrapString(ctxt->context,
9199             xmlXPathCastNodeToString(ctxt->context->node)));
9200     nargs = 1;
9201   }
9202
9203   CHECK_ARITY(1);
9204   CAST_TO_STRING;
9205   CHECK_TYPE(XPATH_STRING);
9206   obj = valuePop(ctxt);
9207   source = obj->stringval;
9208
9209   target = xmlBufferCreate();
9210   if (target && source) {
9211
9212     /* Skip leading whitespaces */
9213     while (IS_BLANK_CH(*source))
9214       source++;
9215
9216     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9217     blank = 0;
9218     while (*source) {
9219       if (IS_BLANK_CH(*source)) {
9220         blank = 0x20;
9221       } else {
9222         if (blank) {
9223           xmlBufferAdd(target, &blank, 1);
9224           blank = 0;
9225         }
9226         xmlBufferAdd(target, source, 1);
9227       }
9228       source++;
9229     }
9230     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9231         xmlBufferContent(target)));
9232     xmlBufferFree(target);
9233   }
9234   xmlXPathReleaseObject(ctxt->context, obj);
9235 }
9236
9237 /**
9238  * xmlXPathTranslateFunction:
9239  * @ctxt:  the XPath Parser context
9240  * @nargs:  the number of arguments
9241  *
9242  * Implement the translate() XPath function
9243  *    string translate(string, string, string)
9244  * The translate function returns the first argument string with
9245  * occurrences of characters in the second argument string replaced
9246  * by the character at the corresponding position in the third argument
9247  * string. For example, translate("bar","abc","ABC") returns the string
9248  * BAr. If there is a character in the second argument string with no
9249  * character at a corresponding position in the third argument string
9250  * (because the second argument string is longer than the third argument
9251  * string), then occurrences of that character in the first argument
9252  * string are removed. For example, translate("--aaa--","abc-","ABC")
9253  * returns "AAA". If a character occurs more than once in second
9254  * argument string, then the first occurrence determines the replacement
9255  * character. If the third argument string is longer than the second
9256  * argument string, then excess characters are ignored.
9257  */
9258 void
9259 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9260     xmlXPathObjectPtr str;
9261     xmlXPathObjectPtr from;
9262     xmlXPathObjectPtr to;
9263     xmlBufferPtr target;
9264     int offset, max;
9265     xmlChar ch;
9266     const xmlChar *point;
9267     xmlChar *cptr;
9268
9269     CHECK_ARITY(3);
9270
9271     CAST_TO_STRING;
9272     to = valuePop(ctxt);
9273     CAST_TO_STRING;
9274     from = valuePop(ctxt);
9275     CAST_TO_STRING;
9276     str = valuePop(ctxt);
9277
9278     target = xmlBufferCreate();
9279     if (target) {
9280         max = xmlUTF8Strlen(to->stringval);
9281         for (cptr = str->stringval; (ch=*cptr); ) {
9282             offset = xmlUTF8Strloc(from->stringval, cptr);
9283             if (offset >= 0) {
9284                 if (offset < max) {
9285                     point = xmlUTF8Strpos(to->stringval, offset);
9286                     if (point)
9287                         xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9288                 }
9289             } else
9290                 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9291
9292             /* Step to next character in input */
9293             cptr++;
9294             if ( ch & 0x80 ) {
9295                 /* if not simple ascii, verify proper format */
9296                 if ( (ch & 0xc0) != 0xc0 ) {
9297                     xmlGenericError(xmlGenericErrorContext,
9298                         "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9299                     break;
9300                 }
9301                 /* then skip over remaining bytes for this char */
9302                 while ( (ch <<= 1) & 0x80 )
9303                     if ( (*cptr++ & 0xc0) != 0x80 ) {
9304                         xmlGenericError(xmlGenericErrorContext,
9305                             "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9306                         break;
9307                     }
9308                 if (ch & 0x80) /* must have had error encountered */
9309                     break;
9310             }
9311         }
9312     }
9313     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9314         xmlBufferContent(target)));
9315     xmlBufferFree(target);
9316     xmlXPathReleaseObject(ctxt->context, str);
9317     xmlXPathReleaseObject(ctxt->context, from);
9318     xmlXPathReleaseObject(ctxt->context, to);
9319 }
9320
9321 /**
9322  * xmlXPathBooleanFunction:
9323  * @ctxt:  the XPath Parser context
9324  * @nargs:  the number of arguments
9325  *
9326  * Implement the boolean() XPath function
9327  *    boolean boolean(object)
9328  * The boolean function converts its argument to a boolean as follows:
9329  *    - a number is true if and only if it is neither positive or
9330  *      negative zero nor NaN
9331  *    - a node-set is true if and only if it is non-empty
9332  *    - a string is true if and only if its length is non-zero
9333  */
9334 void
9335 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9336     xmlXPathObjectPtr cur;
9337
9338     CHECK_ARITY(1);
9339     cur = valuePop(ctxt);
9340     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9341     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9342     valuePush(ctxt, cur);
9343 }
9344
9345 /**
9346  * xmlXPathNotFunction:
9347  * @ctxt:  the XPath Parser context
9348  * @nargs:  the number of arguments
9349  *
9350  * Implement the not() XPath function
9351  *    boolean not(boolean)
9352  * The not function returns true if its argument is false,
9353  * and false otherwise.
9354  */
9355 void
9356 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9357     CHECK_ARITY(1);
9358     CAST_TO_BOOLEAN;
9359     CHECK_TYPE(XPATH_BOOLEAN);
9360     ctxt->value->boolval = ! ctxt->value->boolval;
9361 }
9362
9363 /**
9364  * xmlXPathTrueFunction:
9365  * @ctxt:  the XPath Parser context
9366  * @nargs:  the number of arguments
9367  *
9368  * Implement the true() XPath function
9369  *    boolean true()
9370  */
9371 void
9372 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9373     CHECK_ARITY(0);
9374     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9375 }
9376
9377 /**
9378  * xmlXPathFalseFunction:
9379  * @ctxt:  the XPath Parser context
9380  * @nargs:  the number of arguments
9381  *
9382  * Implement the false() XPath function
9383  *    boolean false()
9384  */
9385 void
9386 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9387     CHECK_ARITY(0);
9388     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9389 }
9390
9391 /**
9392  * xmlXPathLangFunction:
9393  * @ctxt:  the XPath Parser context
9394  * @nargs:  the number of arguments
9395  *
9396  * Implement the lang() XPath function
9397  *    boolean lang(string)
9398  * The lang function returns true or false depending on whether the
9399  * language of the context node as specified by xml:lang attributes
9400  * is the same as or is a sublanguage of the language specified by
9401  * the argument string. The language of the context node is determined
9402  * by the value of the xml:lang attribute on the context node, or, if
9403  * the context node has no xml:lang attribute, by the value of the
9404  * xml:lang attribute on the nearest ancestor of the context node that
9405  * has an xml:lang attribute. If there is no such attribute, then lang
9406  * returns false. If there is such an attribute, then lang returns
9407  * true if the attribute value is equal to the argument ignoring case,
9408  * or if there is some suffix starting with - such that the attribute
9409  * value is equal to the argument ignoring that suffix of the attribute
9410  * value and ignoring case.
9411  */
9412 void
9413 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9414     xmlXPathObjectPtr val = NULL;
9415     const xmlChar *theLang = NULL;
9416     const xmlChar *lang;
9417     int ret = 0;
9418     int i;
9419
9420     CHECK_ARITY(1);
9421     CAST_TO_STRING;
9422     CHECK_TYPE(XPATH_STRING);
9423     val = valuePop(ctxt);
9424     lang = val->stringval;
9425     theLang = xmlNodeGetLang(ctxt->context->node);
9426     if ((theLang != NULL) && (lang != NULL)) {
9427         for (i = 0;lang[i] != 0;i++)
9428             if (toupper(lang[i]) != toupper(theLang[i]))
9429                 goto not_equal;
9430         if ((theLang[i] == 0) || (theLang[i] == '-'))
9431             ret = 1;
9432     }
9433 not_equal:
9434     if (theLang != NULL)
9435         xmlFree((void *)theLang);
9436
9437     xmlXPathReleaseObject(ctxt->context, val);
9438     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9439 }
9440
9441 /**
9442  * xmlXPathNumberFunction:
9443  * @ctxt:  the XPath Parser context
9444  * @nargs:  the number of arguments
9445  *
9446  * Implement the number() XPath function
9447  *    number number(object?)
9448  */
9449 void
9450 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9451     xmlXPathObjectPtr cur;
9452     double res;
9453
9454     if (ctxt == NULL) return;
9455     if (nargs == 0) {
9456         if (ctxt->context->node == NULL) {
9457             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9458         } else {
9459             xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9460
9461             res = xmlXPathStringEvalNumber(content);
9462             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9463             xmlFree(content);
9464         }
9465         return;
9466     }
9467
9468     CHECK_ARITY(1);
9469     cur = valuePop(ctxt);
9470     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9471 }
9472
9473 /**
9474  * xmlXPathSumFunction:
9475  * @ctxt:  the XPath Parser context
9476  * @nargs:  the number of arguments
9477  *
9478  * Implement the sum() XPath function
9479  *    number sum(node-set)
9480  * The sum function returns the sum of the values of the nodes in
9481  * the argument node-set.
9482  */
9483 void
9484 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9485     xmlXPathObjectPtr cur;
9486     int i;
9487     double res = 0.0;
9488
9489     CHECK_ARITY(1);
9490     if ((ctxt->value == NULL) ||
9491         ((ctxt->value->type != XPATH_NODESET) &&
9492          (ctxt->value->type != XPATH_XSLT_TREE)))
9493         XP_ERROR(XPATH_INVALID_TYPE);
9494     cur = valuePop(ctxt);
9495
9496     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9497         for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9498             res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9499         }
9500     }
9501     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9502     xmlXPathReleaseObject(ctxt->context, cur);
9503 }
9504
9505 /*
9506  * To assure working code on multiple platforms, we want to only depend
9507  * upon the characteristic truncation of converting a floating point value
9508  * to an integer.  Unfortunately, because of the different storage sizes
9509  * of our internal floating point value (double) and integer (int), we
9510  * can't directly convert (see bug 301162).  This macro is a messy
9511  * 'workaround'
9512  */
9513 #define XTRUNC(f, v)            \
9514     f = fmod((v), INT_MAX);     \
9515     f = (v) - (f) + (double)((int)(f));
9516
9517 /**
9518  * xmlXPathFloorFunction:
9519  * @ctxt:  the XPath Parser context
9520  * @nargs:  the number of arguments
9521  *
9522  * Implement the floor() XPath function
9523  *    number floor(number)
9524  * The floor function returns the largest (closest to positive infinity)
9525  * number that is not greater than the argument and that is an integer.
9526  */
9527 void
9528 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9529     double f;
9530
9531     CHECK_ARITY(1);
9532     CAST_TO_NUMBER;
9533     CHECK_TYPE(XPATH_NUMBER);
9534
9535     XTRUNC(f, ctxt->value->floatval);
9536     if (f != ctxt->value->floatval) {
9537         if (ctxt->value->floatval > 0)
9538             ctxt->value->floatval = f;
9539         else
9540             ctxt->value->floatval = f - 1;
9541     }
9542 }
9543
9544 /**
9545  * xmlXPathCeilingFunction:
9546  * @ctxt:  the XPath Parser context
9547  * @nargs:  the number of arguments
9548  *
9549  * Implement the ceiling() XPath function
9550  *    number ceiling(number)
9551  * The ceiling function returns the smallest (closest to negative infinity)
9552  * number that is not less than the argument and that is an integer.
9553  */
9554 void
9555 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9556     double f;
9557
9558     CHECK_ARITY(1);
9559     CAST_TO_NUMBER;
9560     CHECK_TYPE(XPATH_NUMBER);
9561
9562 #if 0
9563     ctxt->value->floatval = ceil(ctxt->value->floatval);
9564 #else
9565     XTRUNC(f, ctxt->value->floatval);
9566     if (f != ctxt->value->floatval) {
9567         if (ctxt->value->floatval > 0)
9568             ctxt->value->floatval = f + 1;
9569         else {
9570             if (ctxt->value->floatval < 0 && f == 0)
9571                 ctxt->value->floatval = xmlXPathNZERO;
9572             else
9573                 ctxt->value->floatval = f;
9574         }
9575
9576     }
9577 #endif
9578 }
9579
9580 /**
9581  * xmlXPathRoundFunction:
9582  * @ctxt:  the XPath Parser context
9583  * @nargs:  the number of arguments
9584  *
9585  * Implement the round() XPath function
9586  *    number round(number)
9587  * The round function returns the number that is closest to the
9588  * argument and that is an integer. If there are two such numbers,
9589  * then the one that is even is returned.
9590  */
9591 void
9592 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9593     double f;
9594
9595     CHECK_ARITY(1);
9596     CAST_TO_NUMBER;
9597     CHECK_TYPE(XPATH_NUMBER);
9598
9599     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9600         (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9601         (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9602         (ctxt->value->floatval == 0.0))
9603         return;
9604
9605     XTRUNC(f, ctxt->value->floatval);
9606     if (ctxt->value->floatval < 0) {
9607         if (ctxt->value->floatval < f - 0.5)
9608             ctxt->value->floatval = f - 1;
9609         else
9610             ctxt->value->floatval = f;
9611         if (ctxt->value->floatval == 0)
9612             ctxt->value->floatval = xmlXPathNZERO;
9613     } else {
9614         if (ctxt->value->floatval < f + 0.5)
9615             ctxt->value->floatval = f;
9616         else
9617             ctxt->value->floatval = f + 1;
9618     }
9619 }
9620
9621 /************************************************************************
9622  *                                                                      *
9623  *                      The Parser                                      *
9624  *                                                                      *
9625  ************************************************************************/
9626
9627 /*
9628  * a few forward declarations since we use a recursive call based
9629  * implementation.
9630  */
9631 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9632 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9633 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9634 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9635 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9636                                           int qualified);
9637
9638 /**
9639  * xmlXPathCurrentChar:
9640  * @ctxt:  the XPath parser context
9641  * @cur:  pointer to the beginning of the char
9642  * @len:  pointer to the length of the char read
9643  *
9644  * The current char value, if using UTF-8 this may actually span multiple
9645  * bytes in the input buffer.
9646  *
9647  * Returns the current char value and its length
9648  */
9649
9650 static int
9651 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9652     unsigned char c;
9653     unsigned int val;
9654     const xmlChar *cur;
9655
9656     if (ctxt == NULL)
9657         return(0);
9658     cur = ctxt->cur;
9659
9660     /*
9661      * We are supposed to handle UTF8, check it's valid
9662      * From rfc2044: encoding of the Unicode values on UTF-8:
9663      *
9664      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9665      * 0000 0000-0000 007F   0xxxxxxx
9666      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9667      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9668      *
9669      * Check for the 0x110000 limit too
9670      */
9671     c = *cur;
9672     if (c & 0x80) {
9673         if ((cur[1] & 0xc0) != 0x80)
9674             goto encoding_error;
9675         if ((c & 0xe0) == 0xe0) {
9676
9677             if ((cur[2] & 0xc0) != 0x80)
9678                 goto encoding_error;
9679             if ((c & 0xf0) == 0xf0) {
9680                 if (((c & 0xf8) != 0xf0) ||
9681                     ((cur[3] & 0xc0) != 0x80))
9682                     goto encoding_error;
9683                 /* 4-byte code */
9684                 *len = 4;
9685                 val = (cur[0] & 0x7) << 18;
9686                 val |= (cur[1] & 0x3f) << 12;
9687                 val |= (cur[2] & 0x3f) << 6;
9688                 val |= cur[3] & 0x3f;
9689             } else {
9690               /* 3-byte code */
9691                 *len = 3;
9692                 val = (cur[0] & 0xf) << 12;
9693                 val |= (cur[1] & 0x3f) << 6;
9694                 val |= cur[2] & 0x3f;
9695             }
9696         } else {
9697           /* 2-byte code */
9698             *len = 2;
9699             val = (cur[0] & 0x1f) << 6;
9700             val |= cur[1] & 0x3f;
9701         }
9702         if (!IS_CHAR(val)) {
9703             XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9704         }
9705         return(val);
9706     } else {
9707         /* 1-byte code */
9708         *len = 1;
9709         return((int) *cur);
9710     }
9711 encoding_error:
9712     /*
9713      * If we detect an UTF8 error that probably means that the
9714      * input encoding didn't get properly advertised in the
9715      * declaration header. Report the error and switch the encoding
9716      * to ISO-Latin-1 (if you don't like this policy, just declare the
9717      * encoding !)
9718      */
9719     *len = 0;
9720     XP_ERROR0(XPATH_ENCODING_ERROR);
9721 }
9722
9723 /**
9724  * xmlXPathParseNCName:
9725  * @ctxt:  the XPath Parser context
9726  *
9727  * parse an XML namespace non qualified name.
9728  *
9729  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9730  *
9731  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9732  *                       CombiningChar | Extender
9733  *
9734  * Returns the namespace name or NULL
9735  */
9736
9737 xmlChar *
9738 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9739     const xmlChar *in;
9740     xmlChar *ret;
9741     int count = 0;
9742
9743     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9744     /*
9745      * Accelerator for simple ASCII names
9746      */
9747     in = ctxt->cur;
9748     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9749         ((*in >= 0x41) && (*in <= 0x5A)) ||
9750         (*in == '_')) {
9751         in++;
9752         while (((*in >= 0x61) && (*in <= 0x7A)) ||
9753                ((*in >= 0x41) && (*in <= 0x5A)) ||
9754                ((*in >= 0x30) && (*in <= 0x39)) ||
9755                (*in == '_') || (*in == '.') ||
9756                (*in == '-'))
9757             in++;
9758         if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9759             (*in == '[') || (*in == ']') || (*in == ':') ||
9760             (*in == '@') || (*in == '*')) {
9761             count = in - ctxt->cur;
9762             if (count == 0)
9763                 return(NULL);
9764             ret = xmlStrndup(ctxt->cur, count);
9765             ctxt->cur = in;
9766             return(ret);
9767         }
9768     }
9769     return(xmlXPathParseNameComplex(ctxt, 0));
9770 }
9771
9772
9773 /**
9774  * xmlXPathParseQName:
9775  * @ctxt:  the XPath Parser context
9776  * @prefix:  a xmlChar **
9777  *
9778  * parse an XML qualified name
9779  *
9780  * [NS 5] QName ::= (Prefix ':')? LocalPart
9781  *
9782  * [NS 6] Prefix ::= NCName
9783  *
9784  * [NS 7] LocalPart ::= NCName
9785  *
9786  * Returns the function returns the local part, and prefix is updated
9787  *   to get the Prefix if any.
9788  */
9789
9790 static xmlChar *
9791 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9792     xmlChar *ret = NULL;
9793
9794     *prefix = NULL;
9795     ret = xmlXPathParseNCName(ctxt);
9796     if (ret && CUR == ':') {
9797         *prefix = ret;
9798         NEXT;
9799         ret = xmlXPathParseNCName(ctxt);
9800     }
9801     return(ret);
9802 }
9803
9804 /**
9805  * xmlXPathParseName:
9806  * @ctxt:  the XPath Parser context
9807  *
9808  * parse an XML name
9809  *
9810  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9811  *                  CombiningChar | Extender
9812  *
9813  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9814  *
9815  * Returns the namespace name or NULL
9816  */
9817
9818 xmlChar *
9819 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9820     const xmlChar *in;
9821     xmlChar *ret;
9822     int count = 0;
9823
9824     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9825     /*
9826      * Accelerator for simple ASCII names
9827      */
9828     in = ctxt->cur;
9829     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9830         ((*in >= 0x41) && (*in <= 0x5A)) ||
9831         (*in == '_') || (*in == ':')) {
9832         in++;
9833         while (((*in >= 0x61) && (*in <= 0x7A)) ||
9834                ((*in >= 0x41) && (*in <= 0x5A)) ||
9835                ((*in >= 0x30) && (*in <= 0x39)) ||
9836                (*in == '_') || (*in == '-') ||
9837                (*in == ':') || (*in == '.'))
9838             in++;
9839         if ((*in > 0) && (*in < 0x80)) {
9840             count = in - ctxt->cur;
9841             ret = xmlStrndup(ctxt->cur, count);
9842             ctxt->cur = in;
9843             return(ret);
9844         }
9845     }
9846     return(xmlXPathParseNameComplex(ctxt, 1));
9847 }
9848
9849 static xmlChar *
9850 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9851     xmlChar buf[XML_MAX_NAMELEN + 5];
9852     int len = 0, l;
9853     int c;
9854
9855     /*
9856      * Handler for more complex cases
9857      */
9858     c = CUR_CHAR(l);
9859     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9860         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9861         (c == '*') || /* accelerators */
9862         (!IS_LETTER(c) && (c != '_') &&
9863          ((qualified) && (c != ':')))) {
9864         return(NULL);
9865     }
9866
9867     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9868            ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9869             (c == '.') || (c == '-') ||
9870             (c == '_') || ((qualified) && (c == ':')) ||
9871             (IS_COMBINING(c)) ||
9872             (IS_EXTENDER(c)))) {
9873         COPY_BUF(l,buf,len,c);
9874         NEXTL(l);
9875         c = CUR_CHAR(l);
9876         if (len >= XML_MAX_NAMELEN) {
9877             /*
9878              * Okay someone managed to make a huge name, so he's ready to pay
9879              * for the processing speed.
9880              */
9881             xmlChar *buffer;
9882             int max = len * 2;
9883
9884             buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9885             if (buffer == NULL) {
9886                 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9887             }
9888             memcpy(buffer, buf, len);
9889             while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9890                    (c == '.') || (c == '-') ||
9891                    (c == '_') || ((qualified) && (c == ':')) ||
9892                    (IS_COMBINING(c)) ||
9893                    (IS_EXTENDER(c))) {
9894                 if (len + 10 > max) {
9895                     max *= 2;
9896                     buffer = (xmlChar *) xmlRealloc(buffer,
9897                                                     max * sizeof(xmlChar));
9898                     if (buffer == NULL) {
9899                         XP_ERRORNULL(XPATH_MEMORY_ERROR);
9900                     }
9901                 }
9902                 COPY_BUF(l,buffer,len,c);
9903                 NEXTL(l);
9904                 c = CUR_CHAR(l);
9905             }
9906             buffer[len] = 0;
9907             return(buffer);
9908         }
9909     }
9910     if (len == 0)
9911         return(NULL);
9912     return(xmlStrndup(buf, len));
9913 }
9914
9915 #define MAX_FRAC 20
9916
9917 /*
9918  * These are used as divisors for the fractional part of a number.
9919  * Since the table includes 1.0 (representing '0' fractional digits),
9920  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9921  */
9922 static double my_pow10[MAX_FRAC+1] = {
9923     1.0, 10.0, 100.0, 1000.0, 10000.0,
9924     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9925     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9926     100000000000000.0,
9927     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9928     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9929 };
9930
9931 /**
9932  * xmlXPathStringEvalNumber:
9933  * @str:  A string to scan
9934  *
9935  *  [30a]  Float  ::= Number ('e' Digits?)?
9936  *
9937  *  [30]   Number ::=   Digits ('.' Digits?)?
9938  *                    | '.' Digits
9939  *  [31]   Digits ::=   [0-9]+
9940  *
9941  * Compile a Number in the string
9942  * In complement of the Number expression, this function also handles
9943  * negative values : '-' Number.
9944  *
9945  * Returns the double value.
9946  */
9947 double
9948 xmlXPathStringEvalNumber(const xmlChar *str) {
9949     const xmlChar *cur = str;
9950     double ret;
9951     int ok = 0;
9952     int isneg = 0;
9953     int exponent = 0;
9954     int is_exponent_negative = 0;
9955 #ifdef __GNUC__
9956     unsigned long tmp = 0;
9957     double temp;
9958 #endif
9959     if (cur == NULL) return(0);
9960     while (IS_BLANK_CH(*cur)) cur++;
9961     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9962         return(xmlXPathNAN);
9963     }
9964     if (*cur == '-') {
9965         isneg = 1;
9966         cur++;
9967     }
9968
9969 #ifdef __GNUC__
9970     /*
9971      * tmp/temp is a workaround against a gcc compiler bug
9972      * http://veillard.com/gcc.bug
9973      */
9974     ret = 0;
9975     while ((*cur >= '0') && (*cur <= '9')) {
9976         ret = ret * 10;
9977         tmp = (*cur - '0');
9978         ok = 1;
9979         cur++;
9980         temp = (double) tmp;
9981         ret = ret + temp;
9982     }
9983 #else
9984     ret = 0;
9985     while ((*cur >= '0') && (*cur <= '9')) {
9986         ret = ret * 10 + (*cur - '0');
9987         ok = 1;
9988         cur++;
9989     }
9990 #endif
9991
9992     if (*cur == '.') {
9993         int v, frac = 0;
9994         double fraction = 0;
9995
9996         cur++;
9997         if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9998             return(xmlXPathNAN);
9999         }
10000         while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10001             v = (*cur - '0');
10002             fraction = fraction * 10 + v;
10003             frac = frac + 1;
10004             cur++;
10005         }
10006         fraction /= my_pow10[frac];
10007         ret = ret + fraction;
10008         while ((*cur >= '0') && (*cur <= '9'))
10009             cur++;
10010     }
10011     if ((*cur == 'e') || (*cur == 'E')) {
10012       cur++;
10013       if (*cur == '-') {
10014         is_exponent_negative = 1;
10015         cur++;
10016       } else if (*cur == '+') {
10017         cur++;
10018       }
10019       while ((*cur >= '0') && (*cur <= '9')) {
10020         exponent = exponent * 10 + (*cur - '0');
10021         cur++;
10022       }
10023     }
10024     while (IS_BLANK_CH(*cur)) cur++;
10025     if (*cur != 0) return(xmlXPathNAN);
10026     if (isneg) ret = -ret;
10027     if (is_exponent_negative) exponent = -exponent;
10028     ret *= pow(10.0, (double)exponent);
10029     return(ret);
10030 }
10031
10032 /**
10033  * xmlXPathCompNumber:
10034  * @ctxt:  the XPath Parser context
10035  *
10036  *  [30]   Number ::=   Digits ('.' Digits?)?
10037  *                    | '.' Digits
10038  *  [31]   Digits ::=   [0-9]+
10039  *
10040  * Compile a Number, then push it on the stack
10041  *
10042  */
10043 static void
10044 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10045 {
10046     double ret = 0.0;
10047     double mult = 1;
10048     int ok = 0;
10049     int exponent = 0;
10050     int is_exponent_negative = 0;
10051 #ifdef __GNUC__
10052     unsigned long tmp = 0;
10053     double temp;
10054 #endif
10055
10056     CHECK_ERROR;
10057     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10058         XP_ERROR(XPATH_NUMBER_ERROR);
10059     }
10060 #ifdef __GNUC__
10061     /*
10062      * tmp/temp is a workaround against a gcc compiler bug
10063      * http://veillard.com/gcc.bug
10064      */
10065     ret = 0;
10066     while ((CUR >= '0') && (CUR <= '9')) {
10067         ret = ret * 10;
10068         tmp = (CUR - '0');
10069         ok = 1;
10070         NEXT;
10071         temp = (double) tmp;
10072         ret = ret + temp;
10073     }
10074 #else
10075     ret = 0;
10076     while ((CUR >= '0') && (CUR <= '9')) {
10077         ret = ret * 10 + (CUR - '0');
10078         ok = 1;
10079         NEXT;
10080     }
10081 #endif
10082     if (CUR == '.') {
10083         int v, frac = 0;
10084         double fraction = 0;
10085
10086         NEXT;
10087         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10088             XP_ERROR(XPATH_NUMBER_ERROR);
10089         }
10090         while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10091             v = (CUR - '0');
10092             fraction = fraction * 10 + v;
10093             frac = frac + 1;
10094             NEXT;
10095         }
10096         fraction /= my_pow10[frac];
10097         ret = ret + fraction;
10098         while ((CUR >= '0') && (CUR <= '9'))
10099             NEXT;
10100     }
10101     if ((CUR == 'e') || (CUR == 'E')) {
10102         NEXT;
10103         if (CUR == '-') {
10104             is_exponent_negative = 1;
10105             NEXT;
10106         } else if (CUR == '+') {
10107             NEXT;
10108         }
10109         while ((CUR >= '0') && (CUR <= '9')) {
10110             exponent = exponent * 10 + (CUR - '0');
10111             NEXT;
10112         }
10113         if (is_exponent_negative)
10114             exponent = -exponent;
10115         ret *= pow(10.0, (double) exponent);
10116     }
10117     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10118                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10119 }
10120
10121 /**
10122  * xmlXPathParseLiteral:
10123  * @ctxt:  the XPath Parser context
10124  *
10125  * Parse a Literal
10126  *
10127  *  [29]   Literal ::=   '"' [^"]* '"'
10128  *                    | "'" [^']* "'"
10129  *
10130  * Returns the value found or NULL in case of error
10131  */
10132 static xmlChar *
10133 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10134     const xmlChar *q;
10135     xmlChar *ret = NULL;
10136
10137     if (CUR == '"') {
10138         NEXT;
10139         q = CUR_PTR;
10140         while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10141             NEXT;
10142         if (!IS_CHAR_CH(CUR)) {
10143             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10144         } else {
10145             ret = xmlStrndup(q, CUR_PTR - q);
10146             NEXT;
10147         }
10148     } else if (CUR == '\'') {
10149         NEXT;
10150         q = CUR_PTR;
10151         while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10152             NEXT;
10153         if (!IS_CHAR_CH(CUR)) {
10154             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10155         } else {
10156             ret = xmlStrndup(q, CUR_PTR - q);
10157             NEXT;
10158         }
10159     } else {
10160         XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10161     }
10162     return(ret);
10163 }
10164
10165 /**
10166  * xmlXPathCompLiteral:
10167  * @ctxt:  the XPath Parser context
10168  *
10169  * Parse a Literal and push it on the stack.
10170  *
10171  *  [29]   Literal ::=   '"' [^"]* '"'
10172  *                    | "'" [^']* "'"
10173  *
10174  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10175  */
10176 static void
10177 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10178     const xmlChar *q;
10179     xmlChar *ret = NULL;
10180
10181     if (CUR == '"') {
10182         NEXT;
10183         q = CUR_PTR;
10184         while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10185             NEXT;
10186         if (!IS_CHAR_CH(CUR)) {
10187             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10188         } else {
10189             ret = xmlStrndup(q, CUR_PTR - q);
10190             NEXT;
10191         }
10192     } else if (CUR == '\'') {
10193         NEXT;
10194         q = CUR_PTR;
10195         while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10196             NEXT;
10197         if (!IS_CHAR_CH(CUR)) {
10198             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10199         } else {
10200             ret = xmlStrndup(q, CUR_PTR - q);
10201             NEXT;
10202         }
10203     } else {
10204         XP_ERROR(XPATH_START_LITERAL_ERROR);
10205     }
10206     if (ret == NULL) return;
10207     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10208                    xmlXPathCacheNewString(ctxt->context, ret), NULL);
10209     xmlFree(ret);
10210 }
10211
10212 /**
10213  * xmlXPathCompVariableReference:
10214  * @ctxt:  the XPath Parser context
10215  *
10216  * Parse a VariableReference, evaluate it and push it on the stack.
10217  *
10218  * The variable bindings consist of a mapping from variable names
10219  * to variable values. The value of a variable is an object, which can be
10220  * of any of the types that are possible for the value of an expression,
10221  * and may also be of additional types not specified here.
10222  *
10223  * Early evaluation is possible since:
10224  * The variable bindings [...] used to evaluate a subexpression are
10225  * always the same as those used to evaluate the containing expression.
10226  *
10227  *  [36]   VariableReference ::=   '$' QName
10228  */
10229 static void
10230 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10231     xmlChar *name;
10232     xmlChar *prefix;
10233
10234     SKIP_BLANKS;
10235     if (CUR != '$') {
10236         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10237     }
10238     NEXT;
10239     name = xmlXPathParseQName(ctxt, &prefix);
10240     if (name == NULL) {
10241         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10242     }
10243     ctxt->comp->last = -1;
10244     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10245                    name, prefix);
10246     SKIP_BLANKS;
10247     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10248         XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10249     }
10250 }
10251
10252 /**
10253  * xmlXPathIsNodeType:
10254  * @name:  a name string
10255  *
10256  * Is the name given a NodeType one.
10257  *
10258  *  [38]   NodeType ::=   'comment'
10259  *                    | 'text'
10260  *                    | 'processing-instruction'
10261  *                    | 'node'
10262  *
10263  * Returns 1 if true 0 otherwise
10264  */
10265 int
10266 xmlXPathIsNodeType(const xmlChar *name) {
10267     if (name == NULL)
10268         return(0);
10269
10270     if (xmlStrEqual(name, BAD_CAST "node"))
10271         return(1);
10272     if (xmlStrEqual(name, BAD_CAST "text"))
10273         return(1);
10274     if (xmlStrEqual(name, BAD_CAST "comment"))
10275         return(1);
10276     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10277         return(1);
10278     return(0);
10279 }
10280
10281 /**
10282  * xmlXPathCompFunctionCall:
10283  * @ctxt:  the XPath Parser context
10284  *
10285  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10286  *  [17]   Argument ::=   Expr
10287  *
10288  * Compile a function call, the evaluation of all arguments are
10289  * pushed on the stack
10290  */
10291 static void
10292 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10293     xmlChar *name;
10294     xmlChar *prefix;
10295     int nbargs = 0;
10296     int sort = 1;
10297
10298     name = xmlXPathParseQName(ctxt, &prefix);
10299     if (name == NULL) {
10300         xmlFree(prefix);
10301         XP_ERROR(XPATH_EXPR_ERROR);
10302     }
10303     SKIP_BLANKS;
10304 #ifdef DEBUG_EXPR
10305     if (prefix == NULL)
10306         xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10307                         name);
10308     else
10309         xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10310                         prefix, name);
10311 #endif
10312
10313     if (CUR != '(') {
10314         XP_ERROR(XPATH_EXPR_ERROR);
10315     }
10316     NEXT;
10317     SKIP_BLANKS;
10318
10319     /*
10320     * Optimization for count(): we don't need the node-set to be sorted.
10321     */
10322     if ((prefix == NULL) && (name[0] == 'c') &&
10323         xmlStrEqual(name, BAD_CAST "count"))
10324     {
10325         sort = 0;
10326     }
10327     ctxt->comp->last = -1;
10328     if (CUR != ')') {
10329         while (CUR != 0) {
10330             int op1 = ctxt->comp->last;
10331             ctxt->comp->last = -1;
10332             xmlXPathCompileExpr(ctxt, sort);
10333             if (ctxt->error != XPATH_EXPRESSION_OK) {
10334                 xmlFree(name);
10335                 xmlFree(prefix);
10336                 return;
10337             }
10338             PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10339             nbargs++;
10340             if (CUR == ')') break;
10341             if (CUR != ',') {
10342                 XP_ERROR(XPATH_EXPR_ERROR);
10343             }
10344             NEXT;
10345             SKIP_BLANKS;
10346         }
10347     }
10348     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10349                    name, prefix);
10350     NEXT;
10351     SKIP_BLANKS;
10352 }
10353
10354 /**
10355  * xmlXPathCompPrimaryExpr:
10356  * @ctxt:  the XPath Parser context
10357  *
10358  *  [15]   PrimaryExpr ::=   VariableReference
10359  *                | '(' Expr ')'
10360  *                | Literal
10361  *                | Number
10362  *                | FunctionCall
10363  *
10364  * Compile a primary expression.
10365  */
10366 static void
10367 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10368     SKIP_BLANKS;
10369     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10370     else if (CUR == '(') {
10371         NEXT;
10372         SKIP_BLANKS;
10373         xmlXPathCompileExpr(ctxt, 1);
10374         CHECK_ERROR;
10375         if (CUR != ')') {
10376             XP_ERROR(XPATH_EXPR_ERROR);
10377         }
10378         NEXT;
10379         SKIP_BLANKS;
10380     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10381         xmlXPathCompNumber(ctxt);
10382     } else if ((CUR == '\'') || (CUR == '"')) {
10383         xmlXPathCompLiteral(ctxt);
10384     } else {
10385         xmlXPathCompFunctionCall(ctxt);
10386     }
10387     SKIP_BLANKS;
10388 }
10389
10390 /**
10391  * xmlXPathCompFilterExpr:
10392  * @ctxt:  the XPath Parser context
10393  *
10394  *  [20]   FilterExpr ::=   PrimaryExpr
10395  *               | FilterExpr Predicate
10396  *
10397  * Compile a filter expression.
10398  * Square brackets are used to filter expressions in the same way that
10399  * they are used in location paths. It is an error if the expression to
10400  * be filtered does not evaluate to a node-set. The context node list
10401  * used for evaluating the expression in square brackets is the node-set
10402  * to be filtered listed in document order.
10403  */
10404
10405 static void
10406 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10407     xmlXPathCompPrimaryExpr(ctxt);
10408     CHECK_ERROR;
10409     SKIP_BLANKS;
10410
10411     while (CUR == '[') {
10412         xmlXPathCompPredicate(ctxt, 1);
10413         SKIP_BLANKS;
10414     }
10415
10416
10417 }
10418
10419 /**
10420  * xmlXPathScanName:
10421  * @ctxt:  the XPath Parser context
10422  *
10423  * Trickery: parse an XML name but without consuming the input flow
10424  * Needed to avoid insanity in the parser state.
10425  *
10426  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10427  *                  CombiningChar | Extender
10428  *
10429  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10430  *
10431  * [6] Names ::= Name (S Name)*
10432  *
10433  * Returns the Name parsed or NULL
10434  */
10435
10436 static xmlChar *
10437 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10438     int len = 0, l;
10439     int c;
10440     const xmlChar *cur;
10441     xmlChar *ret;
10442
10443     cur = ctxt->cur;
10444
10445     c = CUR_CHAR(l);
10446     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10447         (!IS_LETTER(c) && (c != '_') &&
10448          (c != ':'))) {
10449         return(NULL);
10450     }
10451
10452     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10453            ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10454             (c == '.') || (c == '-') ||
10455             (c == '_') || (c == ':') ||
10456             (IS_COMBINING(c)) ||
10457             (IS_EXTENDER(c)))) {
10458         len += l;
10459         NEXTL(l);
10460         c = CUR_CHAR(l);
10461     }
10462     ret = xmlStrndup(cur, ctxt->cur - cur);
10463     ctxt->cur = cur;
10464     return(ret);
10465 }
10466
10467 /**
10468  * xmlXPathCompPathExpr:
10469  * @ctxt:  the XPath Parser context
10470  *
10471  *  [19]   PathExpr ::=   LocationPath
10472  *               | FilterExpr
10473  *               | FilterExpr '/' RelativeLocationPath
10474  *               | FilterExpr '//' RelativeLocationPath
10475  *
10476  * Compile a path expression.
10477  * The / operator and // operators combine an arbitrary expression
10478  * and a relative location path. It is an error if the expression
10479  * does not evaluate to a node-set.
10480  * The / operator does composition in the same way as when / is
10481  * used in a location path. As in location paths, // is short for
10482  * /descendant-or-self::node()/.
10483  */
10484
10485 static void
10486 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10487     int lc = 1;           /* Should we branch to LocationPath ?         */
10488     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10489
10490     SKIP_BLANKS;
10491     if ((CUR == '$') || (CUR == '(') ||
10492         (IS_ASCII_DIGIT(CUR)) ||
10493         (CUR == '\'') || (CUR == '"') ||
10494         (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10495         lc = 0;
10496     } else if (CUR == '*') {
10497         /* relative or absolute location path */
10498         lc = 1;
10499     } else if (CUR == '/') {
10500         /* relative or absolute location path */
10501         lc = 1;
10502     } else if (CUR == '@') {
10503         /* relative abbreviated attribute location path */
10504         lc = 1;
10505     } else if (CUR == '.') {
10506         /* relative abbreviated attribute location path */
10507         lc = 1;
10508     } else {
10509         /*
10510          * Problem is finding if we have a name here whether it's:
10511          *   - a nodetype
10512          *   - a function call in which case it's followed by '('
10513          *   - an axis in which case it's followed by ':'
10514          *   - a element name
10515          * We do an a priori analysis here rather than having to
10516          * maintain parsed token content through the recursive function
10517          * calls. This looks uglier but makes the code easier to
10518          * read/write/debug.
10519          */
10520         SKIP_BLANKS;
10521         name = xmlXPathScanName(ctxt);
10522         if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10523 #ifdef DEBUG_STEP
10524             xmlGenericError(xmlGenericErrorContext,
10525                     "PathExpr: Axis\n");
10526 #endif
10527             lc = 1;
10528             xmlFree(name);
10529         } else if (name != NULL) {
10530             int len =xmlStrlen(name);
10531
10532
10533             while (NXT(len) != 0) {
10534                 if (NXT(len) == '/') {
10535                     /* element name */
10536 #ifdef DEBUG_STEP
10537                     xmlGenericError(xmlGenericErrorContext,
10538                             "PathExpr: AbbrRelLocation\n");
10539 #endif
10540                     lc = 1;
10541                     break;
10542                 } else if (IS_BLANK_CH(NXT(len))) {
10543                     /* ignore blanks */
10544                     ;
10545                 } else if (NXT(len) == ':') {
10546 #ifdef DEBUG_STEP
10547                     xmlGenericError(xmlGenericErrorContext,
10548                             "PathExpr: AbbrRelLocation\n");
10549 #endif
10550                     lc = 1;
10551                     break;
10552                 } else if ((NXT(len) == '(')) {
10553                     /* Note Type or Function */
10554                     if (xmlXPathIsNodeType(name)) {
10555 #ifdef DEBUG_STEP
10556                         xmlGenericError(xmlGenericErrorContext,
10557                                 "PathExpr: Type search\n");
10558 #endif
10559                         lc = 1;
10560                     } else {
10561 #ifdef DEBUG_STEP
10562                         xmlGenericError(xmlGenericErrorContext,
10563                                 "PathExpr: function call\n");
10564 #endif
10565                         lc = 0;
10566                     }
10567                     break;
10568                 } else if ((NXT(len) == '[')) {
10569                     /* element name */
10570 #ifdef DEBUG_STEP
10571                     xmlGenericError(xmlGenericErrorContext,
10572                             "PathExpr: AbbrRelLocation\n");
10573 #endif
10574                     lc = 1;
10575                     break;
10576                 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10577                            (NXT(len) == '=')) {
10578                     lc = 1;
10579                     break;
10580                 } else {
10581                     lc = 1;
10582                     break;
10583                 }
10584                 len++;
10585             }
10586             if (NXT(len) == 0) {
10587 #ifdef DEBUG_STEP
10588                 xmlGenericError(xmlGenericErrorContext,
10589                         "PathExpr: AbbrRelLocation\n");
10590 #endif
10591                 /* element name */
10592                 lc = 1;
10593             }
10594             xmlFree(name);
10595         } else {
10596             /* make sure all cases are covered explicitly */
10597             XP_ERROR(XPATH_EXPR_ERROR);
10598         }
10599     }
10600
10601     if (lc) {
10602         if (CUR == '/') {
10603             PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10604         } else {
10605             PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10606         }
10607         xmlXPathCompLocationPath(ctxt);
10608     } else {
10609         xmlXPathCompFilterExpr(ctxt);
10610         CHECK_ERROR;
10611         if ((CUR == '/') && (NXT(1) == '/')) {
10612             SKIP(2);
10613             SKIP_BLANKS;
10614
10615             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10616                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10617             PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10618
10619             xmlXPathCompRelativeLocationPath(ctxt);
10620         } else if (CUR == '/') {
10621             xmlXPathCompRelativeLocationPath(ctxt);
10622         }
10623     }
10624     SKIP_BLANKS;
10625 }
10626
10627 /**
10628  * xmlXPathCompUnionExpr:
10629  * @ctxt:  the XPath Parser context
10630  *
10631  *  [18]   UnionExpr ::=   PathExpr
10632  *               | UnionExpr '|' PathExpr
10633  *
10634  * Compile an union expression.
10635  */
10636
10637 static void
10638 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10639     xmlXPathCompPathExpr(ctxt);
10640     CHECK_ERROR;
10641     SKIP_BLANKS;
10642     while (CUR == '|') {
10643         int op1 = ctxt->comp->last;
10644         PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10645
10646         NEXT;
10647         SKIP_BLANKS;
10648         xmlXPathCompPathExpr(ctxt);
10649
10650         PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10651
10652         SKIP_BLANKS;
10653     }
10654 }
10655
10656 /**
10657  * xmlXPathCompUnaryExpr:
10658  * @ctxt:  the XPath Parser context
10659  *
10660  *  [27]   UnaryExpr ::=   UnionExpr
10661  *                   | '-' UnaryExpr
10662  *
10663  * Compile an unary expression.
10664  */
10665
10666 static void
10667 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10668     int minus = 0;
10669     int found = 0;
10670
10671     SKIP_BLANKS;
10672     while (CUR == '-') {
10673         minus = 1 - minus;
10674         found = 1;
10675         NEXT;
10676         SKIP_BLANKS;
10677     }
10678
10679     xmlXPathCompUnionExpr(ctxt);
10680     CHECK_ERROR;
10681     if (found) {
10682         if (minus)
10683             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10684         else
10685             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10686     }
10687 }
10688
10689 /**
10690  * xmlXPathCompMultiplicativeExpr:
10691  * @ctxt:  the XPath Parser context
10692  *
10693  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10694  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10695  *                   | MultiplicativeExpr 'div' UnaryExpr
10696  *                   | MultiplicativeExpr 'mod' UnaryExpr
10697  *  [34]   MultiplyOperator ::=   '*'
10698  *
10699  * Compile an Additive expression.
10700  */
10701
10702 static void
10703 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10704     xmlXPathCompUnaryExpr(ctxt);
10705     CHECK_ERROR;
10706     SKIP_BLANKS;
10707     while ((CUR == '*') ||
10708            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10709            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10710         int op = -1;
10711         int op1 = ctxt->comp->last;
10712
10713         if (CUR == '*') {
10714             op = 0;
10715             NEXT;
10716         } else if (CUR == 'd') {
10717             op = 1;
10718             SKIP(3);
10719         } else if (CUR == 'm') {
10720             op = 2;
10721             SKIP(3);
10722         }
10723         SKIP_BLANKS;
10724         xmlXPathCompUnaryExpr(ctxt);
10725         CHECK_ERROR;
10726         PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10727         SKIP_BLANKS;
10728     }
10729 }
10730
10731 /**
10732  * xmlXPathCompAdditiveExpr:
10733  * @ctxt:  the XPath Parser context
10734  *
10735  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10736  *                   | AdditiveExpr '+' MultiplicativeExpr
10737  *                   | AdditiveExpr '-' MultiplicativeExpr
10738  *
10739  * Compile an Additive expression.
10740  */
10741
10742 static void
10743 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10744
10745     xmlXPathCompMultiplicativeExpr(ctxt);
10746     CHECK_ERROR;
10747     SKIP_BLANKS;
10748     while ((CUR == '+') || (CUR == '-')) {
10749         int plus;
10750         int op1 = ctxt->comp->last;
10751
10752         if (CUR == '+') plus = 1;
10753         else plus = 0;
10754         NEXT;
10755         SKIP_BLANKS;
10756         xmlXPathCompMultiplicativeExpr(ctxt);
10757         CHECK_ERROR;
10758         PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10759         SKIP_BLANKS;
10760     }
10761 }
10762
10763 /**
10764  * xmlXPathCompRelationalExpr:
10765  * @ctxt:  the XPath Parser context
10766  *
10767  *  [24]   RelationalExpr ::=   AdditiveExpr
10768  *                 | RelationalExpr '<' AdditiveExpr
10769  *                 | RelationalExpr '>' AdditiveExpr
10770  *                 | RelationalExpr '<=' AdditiveExpr
10771  *                 | RelationalExpr '>=' AdditiveExpr
10772  *
10773  *  A <= B > C is allowed ? Answer from James, yes with
10774  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10775  *  which is basically what got implemented.
10776  *
10777  * Compile a Relational expression, then push the result
10778  * on the stack
10779  */
10780
10781 static void
10782 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10783     xmlXPathCompAdditiveExpr(ctxt);
10784     CHECK_ERROR;
10785     SKIP_BLANKS;
10786     while ((CUR == '<') ||
10787            (CUR == '>') ||
10788            ((CUR == '<') && (NXT(1) == '=')) ||
10789            ((CUR == '>') && (NXT(1) == '='))) {
10790         int inf, strict;
10791         int op1 = ctxt->comp->last;
10792
10793         if (CUR == '<') inf = 1;
10794         else inf = 0;
10795         if (NXT(1) == '=') strict = 0;
10796         else strict = 1;
10797         NEXT;
10798         if (!strict) NEXT;
10799         SKIP_BLANKS;
10800         xmlXPathCompAdditiveExpr(ctxt);
10801         CHECK_ERROR;
10802         PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10803         SKIP_BLANKS;
10804     }
10805 }
10806
10807 /**
10808  * xmlXPathCompEqualityExpr:
10809  * @ctxt:  the XPath Parser context
10810  *
10811  *  [23]   EqualityExpr ::=   RelationalExpr
10812  *                 | EqualityExpr '=' RelationalExpr
10813  *                 | EqualityExpr '!=' RelationalExpr
10814  *
10815  *  A != B != C is allowed ? Answer from James, yes with
10816  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10817  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10818  *  which is basically what got implemented.
10819  *
10820  * Compile an Equality expression.
10821  *
10822  */
10823 static void
10824 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10825     xmlXPathCompRelationalExpr(ctxt);
10826     CHECK_ERROR;
10827     SKIP_BLANKS;
10828     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10829         int eq;
10830         int op1 = ctxt->comp->last;
10831
10832         if (CUR == '=') eq = 1;
10833         else eq = 0;
10834         NEXT;
10835         if (!eq) NEXT;
10836         SKIP_BLANKS;
10837         xmlXPathCompRelationalExpr(ctxt);
10838         CHECK_ERROR;
10839         PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10840         SKIP_BLANKS;
10841     }
10842 }
10843
10844 /**
10845  * xmlXPathCompAndExpr:
10846  * @ctxt:  the XPath Parser context
10847  *
10848  *  [22]   AndExpr ::=   EqualityExpr
10849  *                 | AndExpr 'and' EqualityExpr
10850  *
10851  * Compile an AND expression.
10852  *
10853  */
10854 static void
10855 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10856     xmlXPathCompEqualityExpr(ctxt);
10857     CHECK_ERROR;
10858     SKIP_BLANKS;
10859     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10860         int op1 = ctxt->comp->last;
10861         SKIP(3);
10862         SKIP_BLANKS;
10863         xmlXPathCompEqualityExpr(ctxt);
10864         CHECK_ERROR;
10865         PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10866         SKIP_BLANKS;
10867     }
10868 }
10869
10870 /**
10871  * xmlXPathCompileExpr:
10872  * @ctxt:  the XPath Parser context
10873  *
10874  *  [14]   Expr ::=   OrExpr
10875  *  [21]   OrExpr ::=   AndExpr
10876  *                 | OrExpr 'or' AndExpr
10877  *
10878  * Parse and compile an expression
10879  */
10880 static void
10881 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10882     xmlXPathCompAndExpr(ctxt);
10883     CHECK_ERROR;
10884     SKIP_BLANKS;
10885     while ((CUR == 'o') && (NXT(1) == 'r')) {
10886         int op1 = ctxt->comp->last;
10887         SKIP(2);
10888         SKIP_BLANKS;
10889         xmlXPathCompAndExpr(ctxt);
10890         CHECK_ERROR;
10891         PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10892         SKIP_BLANKS;
10893     }
10894     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10895         /* more ops could be optimized too */
10896         /*
10897         * This is the main place to eliminate sorting for
10898         * operations which don't require a sorted node-set.
10899         * E.g. count().
10900         */
10901         PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10902     }
10903 }
10904
10905 /**
10906  * xmlXPathCompPredicate:
10907  * @ctxt:  the XPath Parser context
10908  * @filter:  act as a filter
10909  *
10910  *  [8]   Predicate ::=   '[' PredicateExpr ']'
10911  *  [9]   PredicateExpr ::=   Expr
10912  *
10913  * Compile a predicate expression
10914  */
10915 static void
10916 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10917     int op1 = ctxt->comp->last;
10918
10919     SKIP_BLANKS;
10920     if (CUR != '[') {
10921         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10922     }
10923     NEXT;
10924     SKIP_BLANKS;
10925
10926     ctxt->comp->last = -1;
10927     /*
10928     * This call to xmlXPathCompileExpr() will deactivate sorting
10929     * of the predicate result.
10930     * TODO: Sorting is still activated for filters, since I'm not
10931     *  sure if needed. Normally sorting should not be needed, since
10932     *  a filter can only diminish the number of items in a sequence,
10933     *  but won't change its order; so if the initial sequence is sorted,
10934     *  subsequent sorting is not needed.
10935     */
10936     if (! filter)
10937         xmlXPathCompileExpr(ctxt, 0);
10938     else
10939         xmlXPathCompileExpr(ctxt, 1);
10940     CHECK_ERROR;
10941
10942     if (CUR != ']') {
10943         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10944     }
10945
10946     if (filter)
10947         PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10948     else
10949         PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10950
10951     NEXT;
10952     SKIP_BLANKS;
10953 }
10954
10955 /**
10956  * xmlXPathCompNodeTest:
10957  * @ctxt:  the XPath Parser context
10958  * @test:  pointer to a xmlXPathTestVal
10959  * @type:  pointer to a xmlXPathTypeVal
10960  * @prefix:  placeholder for a possible name prefix
10961  *
10962  * [7] NodeTest ::=   NameTest
10963  *                  | NodeType '(' ')'
10964  *                  | 'processing-instruction' '(' Literal ')'
10965  *
10966  * [37] NameTest ::=  '*'
10967  *                  | NCName ':' '*'
10968  *                  | QName
10969  * [38] NodeType ::= 'comment'
10970  *                 | 'text'
10971  *                 | 'processing-instruction'
10972  *                 | 'node'
10973  *
10974  * Returns the name found and updates @test, @type and @prefix appropriately
10975  */
10976 static xmlChar *
10977 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10978                      xmlXPathTypeVal *type, const xmlChar **prefix,
10979                      xmlChar *name) {
10980     int blanks;
10981
10982     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10983         STRANGE;
10984         return(NULL);
10985     }
10986     *type = (xmlXPathTypeVal) 0;
10987     *test = (xmlXPathTestVal) 0;
10988     *prefix = NULL;
10989     SKIP_BLANKS;
10990
10991     if ((name == NULL) && (CUR == '*')) {
10992         /*
10993          * All elements
10994          */
10995         NEXT;
10996         *test = NODE_TEST_ALL;
10997         return(NULL);
10998     }
10999
11000     if (name == NULL)
11001         name = xmlXPathParseNCName(ctxt);
11002     if (name == NULL) {
11003         XP_ERRORNULL(XPATH_EXPR_ERROR);
11004     }
11005
11006     blanks = IS_BLANK_CH(CUR);
11007     SKIP_BLANKS;
11008     if (CUR == '(') {
11009         NEXT;
11010         /*
11011          * NodeType or PI search
11012          */
11013         if (xmlStrEqual(name, BAD_CAST "comment"))
11014             *type = NODE_TYPE_COMMENT;
11015         else if (xmlStrEqual(name, BAD_CAST "node"))
11016             *type = NODE_TYPE_NODE;
11017         else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11018             *type = NODE_TYPE_PI;
11019         else if (xmlStrEqual(name, BAD_CAST "text"))
11020             *type = NODE_TYPE_TEXT;
11021         else {
11022             if (name != NULL)
11023                 xmlFree(name);
11024             XP_ERRORNULL(XPATH_EXPR_ERROR);
11025         }
11026
11027         *test = NODE_TEST_TYPE;
11028
11029         SKIP_BLANKS;
11030         if (*type == NODE_TYPE_PI) {
11031             /*
11032              * Specific case: search a PI by name.
11033              */
11034             if (name != NULL)
11035                 xmlFree(name);
11036             name = NULL;
11037             if (CUR != ')') {
11038                 name = xmlXPathParseLiteral(ctxt);
11039                 CHECK_ERROR NULL;
11040                 *test = NODE_TEST_PI;
11041                 SKIP_BLANKS;
11042             }
11043         }
11044         if (CUR != ')') {
11045             if (name != NULL)
11046                 xmlFree(name);
11047             XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11048         }
11049         NEXT;
11050         return(name);
11051     }
11052     *test = NODE_TEST_NAME;
11053     if ((!blanks) && (CUR == ':')) {
11054         NEXT;
11055
11056         /*
11057          * Since currently the parser context don't have a
11058          * namespace list associated:
11059          * The namespace name for this prefix can be computed
11060          * only at evaluation time. The compilation is done
11061          * outside of any context.
11062          */
11063 #if 0
11064         *prefix = xmlXPathNsLookup(ctxt->context, name);
11065         if (name != NULL)
11066             xmlFree(name);
11067         if (*prefix == NULL) {
11068             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11069         }
11070 #else
11071         *prefix = name;
11072 #endif
11073
11074         if (CUR == '*') {
11075             /*
11076              * All elements
11077              */
11078             NEXT;
11079             *test = NODE_TEST_ALL;
11080             return(NULL);
11081         }
11082
11083         name = xmlXPathParseNCName(ctxt);
11084         if (name == NULL) {
11085             XP_ERRORNULL(XPATH_EXPR_ERROR);
11086         }
11087     }
11088     return(name);
11089 }
11090
11091 /**
11092  * xmlXPathIsAxisName:
11093  * @name:  a preparsed name token
11094  *
11095  * [6] AxisName ::=   'ancestor'
11096  *                  | 'ancestor-or-self'
11097  *                  | 'attribute'
11098  *                  | 'child'
11099  *                  | 'descendant'
11100  *                  | 'descendant-or-self'
11101  *                  | 'following'
11102  *                  | 'following-sibling'
11103  *                  | 'namespace'
11104  *                  | 'parent'
11105  *                  | 'preceding'
11106  *                  | 'preceding-sibling'
11107  *                  | 'self'
11108  *
11109  * Returns the axis or 0
11110  */
11111 static xmlXPathAxisVal
11112 xmlXPathIsAxisName(const xmlChar *name) {
11113     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11114     switch (name[0]) {
11115         case 'a':
11116             if (xmlStrEqual(name, BAD_CAST "ancestor"))
11117                 ret = AXIS_ANCESTOR;
11118             if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11119                 ret = AXIS_ANCESTOR_OR_SELF;
11120             if (xmlStrEqual(name, BAD_CAST "attribute"))
11121                 ret = AXIS_ATTRIBUTE;
11122             break;
11123         case 'c':
11124             if (xmlStrEqual(name, BAD_CAST "child"))
11125                 ret = AXIS_CHILD;
11126             break;
11127         case 'd':
11128             if (xmlStrEqual(name, BAD_CAST "descendant"))
11129                 ret = AXIS_DESCENDANT;
11130             if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11131                 ret = AXIS_DESCENDANT_OR_SELF;
11132             break;
11133         case 'f':
11134             if (xmlStrEqual(name, BAD_CAST "following"))
11135                 ret = AXIS_FOLLOWING;
11136             if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11137                 ret = AXIS_FOLLOWING_SIBLING;
11138             break;
11139         case 'n':
11140             if (xmlStrEqual(name, BAD_CAST "namespace"))
11141                 ret = AXIS_NAMESPACE;
11142             break;
11143         case 'p':
11144             if (xmlStrEqual(name, BAD_CAST "parent"))
11145                 ret = AXIS_PARENT;
11146             if (xmlStrEqual(name, BAD_CAST "preceding"))
11147                 ret = AXIS_PRECEDING;
11148             if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11149                 ret = AXIS_PRECEDING_SIBLING;
11150             break;
11151         case 's':
11152             if (xmlStrEqual(name, BAD_CAST "self"))
11153                 ret = AXIS_SELF;
11154             break;
11155     }
11156     return(ret);
11157 }
11158
11159 /**
11160  * xmlXPathCompStep:
11161  * @ctxt:  the XPath Parser context
11162  *
11163  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11164  *                  | AbbreviatedStep
11165  *
11166  * [12] AbbreviatedStep ::=   '.' | '..'
11167  *
11168  * [5] AxisSpecifier ::= AxisName '::'
11169  *                  | AbbreviatedAxisSpecifier
11170  *
11171  * [13] AbbreviatedAxisSpecifier ::= '@'?
11172  *
11173  * Modified for XPtr range support as:
11174  *
11175  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11176  *                     | AbbreviatedStep
11177  *                     | 'range-to' '(' Expr ')' Predicate*
11178  *
11179  * Compile one step in a Location Path
11180  * A location step of . is short for self::node(). This is
11181  * particularly useful in conjunction with //. For example, the
11182  * location path .//para is short for
11183  * self::node()/descendant-or-self::node()/child::para
11184  * and so will select all para descendant elements of the context
11185  * node.
11186  * Similarly, a location step of .. is short for parent::node().
11187  * For example, ../title is short for parent::node()/child::title
11188  * and so will select the title children of the parent of the context
11189  * node.
11190  */
11191 static void
11192 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11193 #ifdef LIBXML_XPTR_ENABLED
11194     int rangeto = 0;
11195     int op2 = -1;
11196 #endif
11197
11198     SKIP_BLANKS;
11199     if ((CUR == '.') && (NXT(1) == '.')) {
11200         SKIP(2);
11201         SKIP_BLANKS;
11202         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11203                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11204     } else if (CUR == '.') {
11205         NEXT;
11206         SKIP_BLANKS;
11207     } else {
11208         xmlChar *name = NULL;
11209         const xmlChar *prefix = NULL;
11210         xmlXPathTestVal test = (xmlXPathTestVal) 0;
11211         xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11212         xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11213         int op1;
11214
11215         /*
11216          * The modification needed for XPointer change to the production
11217          */
11218 #ifdef LIBXML_XPTR_ENABLED
11219         if (ctxt->xptr) {
11220             name = xmlXPathParseNCName(ctxt);
11221             if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11222                 op2 = ctxt->comp->last;
11223                 xmlFree(name);
11224                 SKIP_BLANKS;
11225                 if (CUR != '(') {
11226                     XP_ERROR(XPATH_EXPR_ERROR);
11227                 }
11228                 NEXT;
11229                 SKIP_BLANKS;
11230
11231                 xmlXPathCompileExpr(ctxt, 1);
11232                 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11233                 CHECK_ERROR;
11234
11235                 SKIP_BLANKS;
11236                 if (CUR != ')') {
11237                     XP_ERROR(XPATH_EXPR_ERROR);
11238                 }
11239                 NEXT;
11240                 rangeto = 1;
11241                 goto eval_predicates;
11242             }
11243         }
11244 #endif
11245         if (CUR == '*') {
11246             axis = AXIS_CHILD;
11247         } else {
11248             if (name == NULL)
11249                 name = xmlXPathParseNCName(ctxt);
11250             if (name != NULL) {
11251                 axis = xmlXPathIsAxisName(name);
11252                 if (axis != 0) {
11253                     SKIP_BLANKS;
11254                     if ((CUR == ':') && (NXT(1) == ':')) {
11255                         SKIP(2);
11256                         xmlFree(name);
11257                         name = NULL;
11258                     } else {
11259                         /* an element name can conflict with an axis one :-\ */
11260                         axis = AXIS_CHILD;
11261                     }
11262                 } else {
11263                     axis = AXIS_CHILD;
11264                 }
11265             } else if (CUR == '@') {
11266                 NEXT;
11267                 axis = AXIS_ATTRIBUTE;
11268             } else {
11269                 axis = AXIS_CHILD;
11270             }
11271         }
11272
11273         if (ctxt->error != XPATH_EXPRESSION_OK) {
11274             xmlFree(name);
11275             return;
11276         }
11277
11278         name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11279         if (test == 0)
11280             return;
11281
11282         if ((prefix != NULL) && (ctxt->context != NULL) &&
11283             (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11284             if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11285                 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11286             }
11287         }
11288 #ifdef DEBUG_STEP
11289         xmlGenericError(xmlGenericErrorContext,
11290                 "Basis : computing new set\n");
11291 #endif
11292
11293 #ifdef DEBUG_STEP
11294         xmlGenericError(xmlGenericErrorContext, "Basis : ");
11295         if (ctxt->value == NULL)
11296             xmlGenericError(xmlGenericErrorContext, "no value\n");
11297         else if (ctxt->value->nodesetval == NULL)
11298             xmlGenericError(xmlGenericErrorContext, "Empty\n");
11299         else
11300             xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11301 #endif
11302
11303 #ifdef LIBXML_XPTR_ENABLED
11304 eval_predicates:
11305 #endif
11306         op1 = ctxt->comp->last;
11307         ctxt->comp->last = -1;
11308
11309         SKIP_BLANKS;
11310         while (CUR == '[') {
11311             xmlXPathCompPredicate(ctxt, 0);
11312         }
11313
11314 #ifdef LIBXML_XPTR_ENABLED
11315         if (rangeto) {
11316             PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11317         } else
11318 #endif
11319             PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11320                            test, type, (void *)prefix, (void *)name);
11321
11322     }
11323 #ifdef DEBUG_STEP
11324     xmlGenericError(xmlGenericErrorContext, "Step : ");
11325     if (ctxt->value == NULL)
11326         xmlGenericError(xmlGenericErrorContext, "no value\n");
11327     else if (ctxt->value->nodesetval == NULL)
11328         xmlGenericError(xmlGenericErrorContext, "Empty\n");
11329     else
11330         xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11331                 ctxt->value->nodesetval);
11332 #endif
11333 }
11334
11335 /**
11336  * xmlXPathCompRelativeLocationPath:
11337  * @ctxt:  the XPath Parser context
11338  *
11339  *  [3]   RelativeLocationPath ::=   Step
11340  *                     | RelativeLocationPath '/' Step
11341  *                     | AbbreviatedRelativeLocationPath
11342  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11343  *
11344  * Compile a relative location path.
11345  */
11346 static void
11347 xmlXPathCompRelativeLocationPath
11348 (xmlXPathParserContextPtr ctxt) {
11349     SKIP_BLANKS;
11350     if ((CUR == '/') && (NXT(1) == '/')) {
11351         SKIP(2);
11352         SKIP_BLANKS;
11353         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11354                          NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11355     } else if (CUR == '/') {
11356             NEXT;
11357         SKIP_BLANKS;
11358     }
11359     xmlXPathCompStep(ctxt);
11360     CHECK_ERROR;
11361     SKIP_BLANKS;
11362     while (CUR == '/') {
11363         if ((CUR == '/') && (NXT(1) == '/')) {
11364             SKIP(2);
11365             SKIP_BLANKS;
11366             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11367                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11368             xmlXPathCompStep(ctxt);
11369         } else if (CUR == '/') {
11370             NEXT;
11371             SKIP_BLANKS;
11372             xmlXPathCompStep(ctxt);
11373         }
11374         SKIP_BLANKS;
11375     }
11376 }
11377
11378 /**
11379  * xmlXPathCompLocationPath:
11380  * @ctxt:  the XPath Parser context
11381  *
11382  *  [1]   LocationPath ::=   RelativeLocationPath
11383  *                     | AbsoluteLocationPath
11384  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11385  *                     | AbbreviatedAbsoluteLocationPath
11386  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11387  *                           '//' RelativeLocationPath
11388  *
11389  * Compile a location path
11390  *
11391  * // is short for /descendant-or-self::node()/. For example,
11392  * //para is short for /descendant-or-self::node()/child::para and
11393  * so will select any para element in the document (even a para element
11394  * that is a document element will be selected by //para since the
11395  * document element node is a child of the root node); div//para is
11396  * short for div/descendant-or-self::node()/child::para and so will
11397  * select all para descendants of div children.
11398  */
11399 static void
11400 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11401     SKIP_BLANKS;
11402     if (CUR != '/') {
11403         xmlXPathCompRelativeLocationPath(ctxt);
11404     } else {
11405         while (CUR == '/') {
11406             if ((CUR == '/') && (NXT(1) == '/')) {
11407                 SKIP(2);
11408                 SKIP_BLANKS;
11409                 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11410                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11411                 xmlXPathCompRelativeLocationPath(ctxt);
11412             } else if (CUR == '/') {
11413                 NEXT;
11414                 SKIP_BLANKS;
11415                 if ((CUR != 0 ) &&
11416                     ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11417                      (CUR == '@') || (CUR == '*')))
11418                     xmlXPathCompRelativeLocationPath(ctxt);
11419             }
11420             CHECK_ERROR;
11421         }
11422     }
11423 }
11424
11425 /************************************************************************
11426  *                                                                      *
11427  *              XPath precompiled expression evaluation                 *
11428  *                                                                      *
11429  ************************************************************************/
11430
11431 static int
11432 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11433
11434 #ifdef DEBUG_STEP
11435 static void
11436 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11437                           int nbNodes)
11438 {
11439     xmlGenericError(xmlGenericErrorContext, "new step : ");
11440     switch (op->value) {
11441         case AXIS_ANCESTOR:
11442             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11443             break;
11444         case AXIS_ANCESTOR_OR_SELF:
11445             xmlGenericError(xmlGenericErrorContext,
11446                             "axis 'ancestors-or-self' ");
11447             break;
11448         case AXIS_ATTRIBUTE:
11449             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11450             break;
11451         case AXIS_CHILD:
11452             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11453             break;
11454         case AXIS_DESCENDANT:
11455             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11456             break;
11457         case AXIS_DESCENDANT_OR_SELF:
11458             xmlGenericError(xmlGenericErrorContext,
11459                             "axis 'descendant-or-self' ");
11460             break;
11461         case AXIS_FOLLOWING:
11462             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11463             break;
11464         case AXIS_FOLLOWING_SIBLING:
11465             xmlGenericError(xmlGenericErrorContext,
11466                             "axis 'following-siblings' ");
11467             break;
11468         case AXIS_NAMESPACE:
11469             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11470             break;
11471         case AXIS_PARENT:
11472             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11473             break;
11474         case AXIS_PRECEDING:
11475             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11476             break;
11477         case AXIS_PRECEDING_SIBLING:
11478             xmlGenericError(xmlGenericErrorContext,
11479                             "axis 'preceding-sibling' ");
11480             break;
11481         case AXIS_SELF:
11482             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11483             break;
11484     }
11485     xmlGenericError(xmlGenericErrorContext,
11486         " context contains %d nodes\n", nbNodes);
11487     switch (op->value2) {
11488         case NODE_TEST_NONE:
11489             xmlGenericError(xmlGenericErrorContext,
11490                             "           searching for none !!!\n");
11491             break;
11492         case NODE_TEST_TYPE:
11493             xmlGenericError(xmlGenericErrorContext,
11494                             "           searching for type %d\n", op->value3);
11495             break;
11496         case NODE_TEST_PI:
11497             xmlGenericError(xmlGenericErrorContext,
11498                             "           searching for PI !!!\n");
11499             break;
11500         case NODE_TEST_ALL:
11501             xmlGenericError(xmlGenericErrorContext,
11502                             "           searching for *\n");
11503             break;
11504         case NODE_TEST_NS:
11505             xmlGenericError(xmlGenericErrorContext,
11506                             "           searching for namespace %s\n",
11507                             op->value5);
11508             break;
11509         case NODE_TEST_NAME:
11510             xmlGenericError(xmlGenericErrorContext,
11511                             "           searching for name %s\n", op->value5);
11512             if (op->value4)
11513                 xmlGenericError(xmlGenericErrorContext,
11514                                 "           with namespace %s\n", op->value4);
11515             break;
11516     }
11517     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11518 }
11519 #endif /* DEBUG_STEP */
11520
11521 static int
11522 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11523                             xmlXPathStepOpPtr op,
11524                             xmlNodeSetPtr set,
11525                             int contextSize,
11526                             int hasNsNodes)
11527 {
11528     if (op->ch1 != -1) {
11529         xmlXPathCompExprPtr comp = ctxt->comp;
11530         /*
11531         * Process inner predicates first.
11532         */
11533         if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11534             /*
11535             * TODO: raise an internal error.
11536             */
11537         }
11538         contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11539             &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11540         CHECK_ERROR0;
11541         if (contextSize <= 0)
11542             return(0);
11543     }
11544     if (op->ch2 != -1) {
11545         xmlXPathContextPtr xpctxt = ctxt->context;
11546         xmlNodePtr contextNode, oldContextNode;
11547         xmlDocPtr oldContextDoc;
11548         int i, res, contextPos = 0, newContextSize;
11549         xmlXPathStepOpPtr exprOp;
11550         xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11551
11552 #ifdef LIBXML_XPTR_ENABLED
11553         /*
11554         * URGENT TODO: Check the following:
11555         *  We don't expect location sets if evaluating prediates, right?
11556         *  Only filters should expect location sets, right?
11557         */
11558 #endif
11559         /*
11560         * SPEC XPath 1.0:
11561         *  "For each node in the node-set to be filtered, the
11562         *  PredicateExpr is evaluated with that node as the
11563         *  context node, with the number of nodes in the
11564         *  node-set as the context size, and with the proximity
11565         *  position of the node in the node-set with respect to
11566         *  the axis as the context position;"
11567         * @oldset is the node-set" to be filtered.
11568         *
11569         * SPEC XPath 1.0:
11570         *  "only predicates change the context position and
11571         *  context size (see [2.4 Predicates])."
11572         * Example:
11573         *   node-set  context pos
11574         *    nA         1
11575         *    nB         2
11576         *    nC         3
11577         *   After applying predicate [position() > 1] :
11578         *   node-set  context pos
11579         *    nB         1
11580         *    nC         2
11581         */
11582         oldContextNode = xpctxt->node;
11583         oldContextDoc = xpctxt->doc;
11584         /*
11585         * Get the expression of this predicate.
11586         */
11587         exprOp = &ctxt->comp->steps[op->ch2];
11588         newContextSize = 0;
11589         for (i = 0; i < set->nodeNr; i++) {
11590             if (set->nodeTab[i] == NULL)
11591                 continue;
11592
11593             contextNode = set->nodeTab[i];
11594             xpctxt->node = contextNode;
11595             xpctxt->contextSize = contextSize;
11596             xpctxt->proximityPosition = ++contextPos;
11597
11598             /*
11599             * Also set the xpath document in case things like
11600             * key() are evaluated in the predicate.
11601             */
11602             if ((contextNode->type != XML_NAMESPACE_DECL) &&
11603                 (contextNode->doc != NULL))
11604                 xpctxt->doc = contextNode->doc;
11605             /*
11606             * Evaluate the predicate expression with 1 context node
11607             * at a time; this node is packaged into a node set; this
11608             * node set is handed over to the evaluation mechanism.
11609             */
11610             if (contextObj == NULL)
11611                 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11612             else
11613                 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11614                     contextNode);
11615
11616             valuePush(ctxt, contextObj);
11617
11618             res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11619
11620             if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11621                 xmlXPathNodeSetClear(set, hasNsNodes);
11622                 newContextSize = 0;
11623                 goto evaluation_exit;
11624             }
11625
11626             if (res != 0) {
11627                 newContextSize++;
11628             } else {
11629                 /*
11630                 * Remove the entry from the initial node set.
11631                 */
11632                 set->nodeTab[i] = NULL;
11633                 if (contextNode->type == XML_NAMESPACE_DECL)
11634                     xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11635             }
11636             if (ctxt->value == contextObj) {
11637                 /*
11638                 * Don't free the temporary XPath object holding the
11639                 * context node, in order to avoid massive recreation
11640                 * inside this loop.
11641                 */
11642                 valuePop(ctxt);
11643                 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11644             } else {
11645                 /*
11646                 * TODO: The object was lost in the evaluation machinery.
11647                 *  Can this happen? Maybe in internal-error cases.
11648                 */
11649                 contextObj = NULL;
11650             }
11651         }
11652
11653         if (contextObj != NULL) {
11654             if (ctxt->value == contextObj)
11655                 valuePop(ctxt);
11656             xmlXPathReleaseObject(xpctxt, contextObj);
11657         }
11658 evaluation_exit:
11659         if (exprRes != NULL)
11660             xmlXPathReleaseObject(ctxt->context, exprRes);
11661         /*
11662         * Reset/invalidate the context.
11663         */
11664         xpctxt->node = oldContextNode;
11665         xpctxt->doc = oldContextDoc;
11666         xpctxt->contextSize = -1;
11667         xpctxt->proximityPosition = -1;
11668         return(newContextSize);
11669     }
11670     return(contextSize);
11671 }
11672
11673 static int
11674 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11675                                       xmlXPathStepOpPtr op,
11676                                       xmlNodeSetPtr set,
11677                                       int contextSize,
11678                                       int minPos,
11679                                       int maxPos,
11680                                       int hasNsNodes)
11681 {
11682     if (op->ch1 != -1) {
11683         xmlXPathCompExprPtr comp = ctxt->comp;
11684         if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11685             /*
11686             * TODO: raise an internal error.
11687             */
11688         }
11689         contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11690             &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11691         CHECK_ERROR0;
11692         if (contextSize <= 0)
11693             return(0);
11694     }
11695     /*
11696     * Check if the node set contains a sufficient number of nodes for
11697     * the requested range.
11698     */
11699     if (contextSize < minPos) {
11700         xmlXPathNodeSetClear(set, hasNsNodes);
11701         return(0);
11702     }
11703     if (op->ch2 == -1) {
11704         /*
11705         * TODO: Can this ever happen?
11706         */
11707         return (contextSize);
11708     } else {
11709         xmlDocPtr oldContextDoc;
11710         int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11711         xmlXPathStepOpPtr exprOp;
11712         xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11713         xmlNodePtr oldContextNode, contextNode = NULL;
11714         xmlXPathContextPtr xpctxt = ctxt->context;
11715
11716 #ifdef LIBXML_XPTR_ENABLED
11717             /*
11718             * URGENT TODO: Check the following:
11719             *  We don't expect location sets if evaluating prediates, right?
11720             *  Only filters should expect location sets, right?
11721         */
11722 #endif /* LIBXML_XPTR_ENABLED */
11723
11724         /*
11725         * Save old context.
11726         */
11727         oldContextNode = xpctxt->node;
11728         oldContextDoc = xpctxt->doc;
11729         /*
11730         * Get the expression of this predicate.
11731         */
11732         exprOp = &ctxt->comp->steps[op->ch2];
11733         for (i = 0; i < set->nodeNr; i++) {
11734             if (set->nodeTab[i] == NULL)
11735                 continue;
11736
11737             contextNode = set->nodeTab[i];
11738             xpctxt->node = contextNode;
11739             xpctxt->contextSize = contextSize;
11740             xpctxt->proximityPosition = ++contextPos;
11741
11742             /*
11743             * Initialize the new set.
11744             * Also set the xpath document in case things like
11745             * key() evaluation are attempted on the predicate
11746             */
11747             if ((contextNode->type != XML_NAMESPACE_DECL) &&
11748                 (contextNode->doc != NULL))
11749                 xpctxt->doc = contextNode->doc;
11750             /*
11751             * Evaluate the predicate expression with 1 context node
11752             * at a time; this node is packaged into a node set; this
11753             * node set is handed over to the evaluation mechanism.
11754             */
11755             if (contextObj == NULL)
11756                 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11757             else
11758                 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11759                     contextNode);
11760
11761             valuePush(ctxt, contextObj);
11762             res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11763
11764             if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11765                 xmlXPathObjectPtr tmp;
11766                 /* pop the result */
11767                 tmp = valuePop(ctxt);
11768                 xmlXPathReleaseObject(xpctxt, tmp);
11769                 /* then pop off contextObj, which will be freed later */
11770                 valuePop(ctxt);
11771                 goto evaluation_error;
11772             }
11773
11774             if (res)
11775                 pos++;
11776
11777             if (res && (pos >= minPos) && (pos <= maxPos)) {
11778                 /*
11779                 * Fits in the requested range.
11780                 */
11781                 newContextSize++;
11782                 if (minPos == maxPos) {
11783                     /*
11784                     * Only 1 node was requested.
11785                     */
11786                     if (contextNode->type == XML_NAMESPACE_DECL) {
11787                         /*
11788                         * As always: take care of those nasty
11789                         * namespace nodes.
11790                         */
11791                         set->nodeTab[i] = NULL;
11792                     }
11793                     xmlXPathNodeSetClear(set, hasNsNodes);
11794                     set->nodeNr = 1;
11795                     set->nodeTab[0] = contextNode;
11796                     goto evaluation_exit;
11797                 }
11798                 if (pos == maxPos) {
11799                     /*
11800                     * We are done.
11801                     */
11802                     xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11803                     goto evaluation_exit;
11804                 }
11805             } else {
11806                 /*
11807                 * Remove the entry from the initial node set.
11808                 */
11809                 set->nodeTab[i] = NULL;
11810                 if (contextNode->type == XML_NAMESPACE_DECL)
11811                     xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11812             }
11813             if (exprRes != NULL) {
11814                 xmlXPathReleaseObject(ctxt->context, exprRes);
11815                 exprRes = NULL;
11816             }
11817             if (ctxt->value == contextObj) {
11818                 /*
11819                 * Don't free the temporary XPath object holding the
11820                 * context node, in order to avoid massive recreation
11821                 * inside this loop.
11822                 */
11823                 valuePop(ctxt);
11824                 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11825             } else {
11826                 /*
11827                 * The object was lost in the evaluation machinery.
11828                 * Can this happen? Maybe in case of internal-errors.
11829                 */
11830                 contextObj = NULL;
11831             }
11832         }
11833         goto evaluation_exit;
11834
11835 evaluation_error:
11836         xmlXPathNodeSetClear(set, hasNsNodes);
11837         newContextSize = 0;
11838
11839 evaluation_exit:
11840         if (contextObj != NULL) {
11841             if (ctxt->value == contextObj)
11842                 valuePop(ctxt);
11843             xmlXPathReleaseObject(xpctxt, contextObj);
11844         }
11845         if (exprRes != NULL)
11846             xmlXPathReleaseObject(ctxt->context, exprRes);
11847         /*
11848         * Reset/invalidate the context.
11849         */
11850         xpctxt->node = oldContextNode;
11851         xpctxt->doc = oldContextDoc;
11852         xpctxt->contextSize = -1;
11853         xpctxt->proximityPosition = -1;
11854         return(newContextSize);
11855     }
11856     return(contextSize);
11857 }
11858
11859 static int
11860 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11861                             xmlXPathStepOpPtr op,
11862                             int *maxPos)
11863 {
11864
11865     xmlXPathStepOpPtr exprOp;
11866
11867     /*
11868     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11869     */
11870
11871     /*
11872     * If not -1, then ch1 will point to:
11873     * 1) For predicates (XPATH_OP_PREDICATE):
11874     *    - an inner predicate operator
11875     * 2) For filters (XPATH_OP_FILTER):
11876     *    - an inner filter operater OR
11877     *    - an expression selecting the node set.
11878     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11879     */
11880     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11881         return(0);
11882
11883     if (op->ch2 != -1) {
11884         exprOp = &ctxt->comp->steps[op->ch2];
11885     } else
11886         return(0);
11887
11888     if ((exprOp != NULL) &&
11889         (exprOp->op == XPATH_OP_VALUE) &&
11890         (exprOp->value4 != NULL) &&
11891         (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11892     {
11893         /*
11894         * We have a "[n]" predicate here.
11895         * TODO: Unfortunately this simplistic test here is not
11896         * able to detect a position() predicate in compound
11897         * expressions like "[@attr = 'a" and position() = 1],
11898         * and even not the usage of position() in
11899         * "[position() = 1]"; thus - obviously - a position-range,
11900         * like it "[position() < 5]", is also not detected.
11901         * Maybe we could rewrite the AST to ease the optimization.
11902         */
11903         *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11904
11905         if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11906             (float) *maxPos)
11907         {
11908             return(1);
11909         }
11910     }
11911     return(0);
11912 }
11913
11914 static int
11915 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11916                            xmlXPathStepOpPtr op,
11917                            xmlNodePtr * first, xmlNodePtr * last,
11918                            int toBool)
11919 {
11920
11921 #define XP_TEST_HIT \
11922     if (hasAxisRange != 0) { \
11923         if (++pos == maxPos) { \
11924             addNode(seq, cur); \
11925         goto axis_range_end; } \
11926     } else { \
11927         addNode(seq, cur); \
11928         if (breakOnFirstHit) goto first_hit; }
11929
11930 #define XP_TEST_HIT_NS \
11931     if (hasAxisRange != 0) { \
11932         if (++pos == maxPos) { \
11933             hasNsNodes = 1; \
11934             xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11935         goto axis_range_end; } \
11936     } else { \
11937         hasNsNodes = 1; \
11938         xmlXPathNodeSetAddNs(seq, \
11939         xpctxt->node, (xmlNsPtr) cur); \
11940         if (breakOnFirstHit) goto first_hit; }
11941
11942     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11943     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11944     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11945     const xmlChar *prefix = op->value4;
11946     const xmlChar *name = op->value5;
11947     const xmlChar *URI = NULL;
11948
11949 #ifdef DEBUG_STEP
11950     int nbMatches = 0, prevMatches = 0;
11951 #endif
11952     int total = 0, hasNsNodes = 0;
11953     /* The popped object holding the context nodes */
11954     xmlXPathObjectPtr obj;
11955     /* The set of context nodes for the node tests */
11956     xmlNodeSetPtr contextSeq;
11957     int contextIdx;
11958     xmlNodePtr contextNode;
11959     /* The context node for a compound traversal */
11960     xmlNodePtr outerContextNode;
11961     /* The final resulting node set wrt to all context nodes */
11962     xmlNodeSetPtr outSeq;
11963     /*
11964     * The temporary resulting node set wrt 1 context node.
11965     * Used to feed predicate evaluation.
11966     */
11967     xmlNodeSetPtr seq;
11968     xmlNodePtr cur;
11969     /* First predicate operator */
11970     xmlXPathStepOpPtr predOp;
11971     int maxPos; /* The requested position() (when a "[n]" predicate) */
11972     int hasPredicateRange, hasAxisRange, pos, size, newSize;
11973     int breakOnFirstHit;
11974
11975     xmlXPathTraversalFunction next = NULL;
11976     /* compound axis traversal */
11977     xmlXPathTraversalFunctionExt outerNext = NULL;
11978     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11979     xmlXPathNodeSetMergeFunction mergeAndClear;
11980     xmlNodePtr oldContextNode;
11981     xmlXPathContextPtr xpctxt = ctxt->context;
11982
11983
11984     CHECK_TYPE0(XPATH_NODESET);
11985     obj = valuePop(ctxt);
11986     /*
11987     * Setup namespaces.
11988     */
11989     if (prefix != NULL) {
11990         URI = xmlXPathNsLookup(xpctxt, prefix);
11991         if (URI == NULL) {
11992             xmlXPathReleaseObject(xpctxt, obj);
11993             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11994         }
11995     }
11996     /*
11997     * Setup axis.
11998     *
11999     * MAYBE FUTURE TODO: merging optimizations:
12000     * - If the nodes to be traversed wrt to the initial nodes and
12001     *   the current axis cannot overlap, then we could avoid searching
12002     *   for duplicates during the merge.
12003     *   But the question is how/when to evaluate if they cannot overlap.
12004     *   Example: if we know that for two initial nodes, the one is
12005     *   not in the ancestor-or-self axis of the other, then we could safely
12006     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12007     *   the descendant-or-self axis.
12008     */
12009     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12010     switch (axis) {
12011         case AXIS_ANCESTOR:
12012             first = NULL;
12013             next = xmlXPathNextAncestor;
12014             break;
12015         case AXIS_ANCESTOR_OR_SELF:
12016             first = NULL;
12017             next = xmlXPathNextAncestorOrSelf;
12018             break;
12019         case AXIS_ATTRIBUTE:
12020             first = NULL;
12021             last = NULL;
12022             next = xmlXPathNextAttribute;
12023             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12024             break;
12025         case AXIS_CHILD:
12026             last = NULL;
12027             if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12028                 /*
12029                 * This iterator will give us only nodes which can
12030                 * hold element nodes.
12031                 */
12032                 outerNext = xmlXPathNextDescendantOrSelfElemParent;
12033             }
12034             if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12035                 (type == NODE_TYPE_NODE))
12036             {
12037                 /*
12038                 * Optimization if an element node type is 'element'.
12039                 */
12040                 next = xmlXPathNextChildElement;
12041             } else
12042                 next = xmlXPathNextChild;
12043             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12044             break;
12045         case AXIS_DESCENDANT:
12046             last = NULL;
12047             next = xmlXPathNextDescendant;
12048             break;
12049         case AXIS_DESCENDANT_OR_SELF:
12050             last = NULL;
12051             next = xmlXPathNextDescendantOrSelf;
12052             break;
12053         case AXIS_FOLLOWING:
12054             last = NULL;
12055             next = xmlXPathNextFollowing;
12056             break;
12057         case AXIS_FOLLOWING_SIBLING:
12058             last = NULL;
12059             next = xmlXPathNextFollowingSibling;
12060             break;
12061         case AXIS_NAMESPACE:
12062             first = NULL;
12063             last = NULL;
12064             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12065             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12066             break;
12067         case AXIS_PARENT:
12068             first = NULL;
12069             next = xmlXPathNextParent;
12070             break;
12071         case AXIS_PRECEDING:
12072             first = NULL;
12073             next = xmlXPathNextPrecedingInternal;
12074             break;
12075         case AXIS_PRECEDING_SIBLING:
12076             first = NULL;
12077             next = xmlXPathNextPrecedingSibling;
12078             break;
12079         case AXIS_SELF:
12080             first = NULL;
12081             last = NULL;
12082             next = xmlXPathNextSelf;
12083             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12084             break;
12085     }
12086
12087 #ifdef DEBUG_STEP
12088     xmlXPathDebugDumpStepAxis(op,
12089         (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12090 #endif
12091
12092     if (next == NULL) {
12093         xmlXPathReleaseObject(xpctxt, obj);
12094         return(0);
12095     }
12096     contextSeq = obj->nodesetval;
12097     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12098         xmlXPathReleaseObject(xpctxt, obj);
12099         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12100         return(0);
12101     }
12102     /*
12103     * Predicate optimization ---------------------------------------------
12104     * If this step has a last predicate, which contains a position(),
12105     * then we'll optimize (although not exactly "position()", but only
12106     * the  short-hand form, i.e., "[n]".
12107     *
12108     * Example - expression "/foo[parent::bar][1]":
12109     *
12110     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12111     *   ROOT                               -- op->ch1
12112     *   PREDICATE                          -- op->ch2 (predOp)
12113     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12114     *       SORT
12115     *         COLLECT  'parent' 'name' 'node' bar
12116     *           NODE
12117     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12118     *
12119     */
12120     maxPos = 0;
12121     predOp = NULL;
12122     hasPredicateRange = 0;
12123     hasAxisRange = 0;
12124     if (op->ch2 != -1) {
12125         /*
12126         * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12127         */
12128         predOp = &ctxt->comp->steps[op->ch2];
12129         if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12130             if (predOp->ch1 != -1) {
12131                 /*
12132                 * Use the next inner predicate operator.
12133                 */
12134                 predOp = &ctxt->comp->steps[predOp->ch1];
12135                 hasPredicateRange = 1;
12136             } else {
12137                 /*
12138                 * There's no other predicate than the [n] predicate.
12139                 */
12140                 predOp = NULL;
12141                 hasAxisRange = 1;
12142             }
12143         }
12144     }
12145     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12146     /*
12147     * Axis traversal -----------------------------------------------------
12148     */
12149     /*
12150      * 2.3 Node Tests
12151      *  - For the attribute axis, the principal node type is attribute.
12152      *  - For the namespace axis, the principal node type is namespace.
12153      *  - For other axes, the principal node type is element.
12154      *
12155      * A node test * is true for any node of the
12156      * principal node type. For example, child::* will
12157      * select all element children of the context node
12158      */
12159     oldContextNode = xpctxt->node;
12160     addNode = xmlXPathNodeSetAddUnique;
12161     outSeq = NULL;
12162     seq = NULL;
12163     outerContextNode = NULL;
12164     contextNode = NULL;
12165     contextIdx = 0;
12166
12167
12168     while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12169         if (outerNext != NULL) {
12170             /*
12171             * This is a compound traversal.
12172             */
12173             if (contextNode == NULL) {
12174                 /*
12175                 * Set the context for the outer traversal.
12176                 */
12177                 outerContextNode = contextSeq->nodeTab[contextIdx++];
12178                 contextNode = outerNext(NULL, outerContextNode);
12179             } else
12180                 contextNode = outerNext(contextNode, outerContextNode);
12181             if (contextNode == NULL)
12182                 continue;
12183             /*
12184             * Set the context for the main traversal.
12185             */
12186             xpctxt->node = contextNode;
12187         } else
12188             xpctxt->node = contextSeq->nodeTab[contextIdx++];
12189
12190         if (seq == NULL) {
12191             seq = xmlXPathNodeSetCreate(NULL);
12192             if (seq == NULL) {
12193                 total = 0;
12194                 goto error;
12195             }
12196         }
12197         /*
12198         * Traverse the axis and test the nodes.
12199         */
12200         pos = 0;
12201         cur = NULL;
12202         hasNsNodes = 0;
12203         do {
12204             cur = next(ctxt, cur);
12205             if (cur == NULL)
12206                 break;
12207
12208             /*
12209             * QUESTION TODO: What does the "first" and "last" stuff do?
12210             */
12211             if ((first != NULL) && (*first != NULL)) {
12212                 if (*first == cur)
12213                     break;
12214                 if (((total % 256) == 0) &&
12215 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12216                     (xmlXPathCmpNodesExt(*first, cur) >= 0))
12217 #else
12218                     (xmlXPathCmpNodes(*first, cur) >= 0))
12219 #endif
12220                 {
12221                     break;
12222                 }
12223             }
12224             if ((last != NULL) && (*last != NULL)) {
12225                 if (*last == cur)
12226                     break;
12227                 if (((total % 256) == 0) &&
12228 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12229                     (xmlXPathCmpNodesExt(cur, *last) >= 0))
12230 #else
12231                     (xmlXPathCmpNodes(cur, *last) >= 0))
12232 #endif
12233                 {
12234                     break;
12235                 }
12236             }
12237
12238             total++;
12239
12240 #ifdef DEBUG_STEP
12241             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12242 #endif
12243
12244             switch (test) {
12245                 case NODE_TEST_NONE:
12246                     total = 0;
12247                     STRANGE
12248                     goto error;
12249                 case NODE_TEST_TYPE:
12250                     /*
12251                     * TODO: Don't we need to use
12252                     *  xmlXPathNodeSetAddNs() for namespace nodes here?
12253                     *  Surprisingly, some c14n tests fail, if we do this.
12254                     */
12255                     if (type == NODE_TYPE_NODE) {
12256                         switch (cur->type) {
12257                             case XML_DOCUMENT_NODE:
12258                             case XML_HTML_DOCUMENT_NODE:
12259 #ifdef LIBXML_DOCB_ENABLED
12260                             case XML_DOCB_DOCUMENT_NODE:
12261 #endif
12262                             case XML_ELEMENT_NODE:
12263                             case XML_ATTRIBUTE_NODE:
12264                             case XML_PI_NODE:
12265                             case XML_COMMENT_NODE:
12266                             case XML_CDATA_SECTION_NODE:
12267                             case XML_TEXT_NODE:
12268                             case XML_NAMESPACE_DECL:
12269                                 XP_TEST_HIT
12270                                 break;
12271                             default:
12272                                 break;
12273                         }
12274                     } else if (cur->type == type) {
12275                         if (type == XML_NAMESPACE_DECL)
12276                             XP_TEST_HIT_NS
12277                         else
12278                             XP_TEST_HIT
12279                     } else if ((type == NODE_TYPE_TEXT) &&
12280                          (cur->type == XML_CDATA_SECTION_NODE))
12281                     {
12282                         XP_TEST_HIT
12283                     }
12284                     break;
12285                 case NODE_TEST_PI:
12286                     if ((cur->type == XML_PI_NODE) &&
12287                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12288                     {
12289                         XP_TEST_HIT
12290                     }
12291                     break;
12292                 case NODE_TEST_ALL:
12293                     if (axis == AXIS_ATTRIBUTE) {
12294                         if (cur->type == XML_ATTRIBUTE_NODE)
12295                         {
12296                             XP_TEST_HIT
12297                         }
12298                     } else if (axis == AXIS_NAMESPACE) {
12299                         if (cur->type == XML_NAMESPACE_DECL)
12300                         {
12301                             XP_TEST_HIT_NS
12302                         }
12303                     } else {
12304                         if (cur->type == XML_ELEMENT_NODE) {
12305                             if (prefix == NULL)
12306                             {
12307                                 XP_TEST_HIT
12308
12309                             } else if ((cur->ns != NULL) &&
12310                                 (xmlStrEqual(URI, cur->ns->href)))
12311                             {
12312                                 XP_TEST_HIT
12313                             }
12314                         }
12315                     }
12316                     break;
12317                 case NODE_TEST_NS:{
12318                         TODO;
12319                         break;
12320                     }
12321                 case NODE_TEST_NAME:
12322                     if (axis == AXIS_ATTRIBUTE) {
12323                         if (cur->type != XML_ATTRIBUTE_NODE)
12324                             break;
12325                     } else if (axis == AXIS_NAMESPACE) {
12326                         if (cur->type != XML_NAMESPACE_DECL)
12327                             break;
12328                     } else {
12329                         if (cur->type != XML_ELEMENT_NODE)
12330                             break;
12331                     }
12332                     switch (cur->type) {
12333                         case XML_ELEMENT_NODE:
12334                             if (xmlStrEqual(name, cur->name)) {
12335                                 if (prefix == NULL) {
12336                                     if (cur->ns == NULL)
12337                                     {
12338                                         XP_TEST_HIT
12339                                     }
12340                                 } else {
12341                                     if ((cur->ns != NULL) &&
12342                                         (xmlStrEqual(URI, cur->ns->href)))
12343                                     {
12344                                         XP_TEST_HIT
12345                                     }
12346                                 }
12347                             }
12348                             break;
12349                         case XML_ATTRIBUTE_NODE:{
12350                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12351
12352                                 if (xmlStrEqual(name, attr->name)) {
12353                                     if (prefix == NULL) {
12354                                         if ((attr->ns == NULL) ||
12355                                             (attr->ns->prefix == NULL))
12356                                         {
12357                                             XP_TEST_HIT
12358                                         }
12359                                     } else {
12360                                         if ((attr->ns != NULL) &&
12361                                             (xmlStrEqual(URI,
12362                                               attr->ns->href)))
12363                                         {
12364                                             XP_TEST_HIT
12365                                         }
12366                                     }
12367                                 }
12368                                 break;
12369                             }
12370                         case XML_NAMESPACE_DECL:
12371                             if (cur->type == XML_NAMESPACE_DECL) {
12372                                 xmlNsPtr ns = (xmlNsPtr) cur;
12373
12374                                 if ((ns->prefix != NULL) && (name != NULL)
12375                                     && (xmlStrEqual(ns->prefix, name)))
12376                                 {
12377                                     XP_TEST_HIT_NS
12378                                 }
12379                             }
12380                             break;
12381                         default:
12382                             break;
12383                     }
12384                     break;
12385             } /* switch(test) */
12386         } while (cur != NULL);
12387
12388         goto apply_predicates;
12389
12390 axis_range_end: /* ----------------------------------------------------- */
12391         /*
12392         * We have a "/foo[n]", and position() = n was reached.
12393         * Note that we can have as well "/foo/::parent::foo[1]", so
12394         * a duplicate-aware merge is still needed.
12395         * Merge with the result.
12396         */
12397         if (outSeq == NULL) {
12398             outSeq = seq;
12399             seq = NULL;
12400         } else
12401             outSeq = mergeAndClear(outSeq, seq, 0);
12402         /*
12403         * Break if only a true/false result was requested.
12404         */
12405         if (toBool)
12406             break;
12407         continue;
12408
12409 first_hit: /* ---------------------------------------------------------- */
12410         /*
12411         * Break if only a true/false result was requested and
12412         * no predicates existed and a node test succeeded.
12413         */
12414         if (outSeq == NULL) {
12415             outSeq = seq;
12416             seq = NULL;
12417         } else
12418             outSeq = mergeAndClear(outSeq, seq, 0);
12419         break;
12420
12421 #ifdef DEBUG_STEP
12422         if (seq != NULL)
12423             nbMatches += seq->nodeNr;
12424 #endif
12425
12426 apply_predicates: /* --------------------------------------------------- */
12427         /*
12428         * Apply predicates.
12429         */
12430         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12431             /*
12432             * E.g. when we have a "/foo[some expression][n]".
12433             */      
12434             /*
12435             * QUESTION TODO: The old predicate evaluation took into
12436             *  account location-sets.
12437             *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12438             *  Do we expect such a set here?
12439             *  All what I learned now from the evaluation semantics
12440             *  does not indicate that a location-set will be processed
12441             *  here, so this looks OK.
12442             */      
12443             /*
12444             * Iterate over all predicates, starting with the outermost
12445             * predicate.
12446             * TODO: Problem: we cannot execute the inner predicates first
12447             *  since we cannot go back *up* the operator tree!
12448             *  Options we have:
12449             *  1) Use of recursive functions (like is it currently done
12450             *     via xmlXPathCompOpEval())
12451             *  2) Add a predicate evaluation information stack to the
12452             *     context struct
12453             *  3) Change the way the operators are linked; we need a
12454             *     "parent" field on xmlXPathStepOp
12455             *
12456             * For the moment, I'll try to solve this with a recursive
12457             * function: xmlXPathCompOpEvalPredicate().
12458             */
12459             size = seq->nodeNr;
12460             if (hasPredicateRange != 0)
12461                 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12462                     predOp, seq, size, maxPos, maxPos, hasNsNodes);
12463             else
12464                 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12465                     predOp, seq, size, hasNsNodes);
12466
12467             if (ctxt->error != XPATH_EXPRESSION_OK) {
12468                 total = 0;
12469                 goto error;
12470             }
12471             /*
12472             * Add the filtered set of nodes to the result node set.
12473             */
12474             if (newSize == 0) {
12475                 /*
12476                 * The predicates filtered all nodes out.
12477                 */
12478                 xmlXPathNodeSetClear(seq, hasNsNodes);
12479             } else if (seq->nodeNr > 0) {
12480                 /*
12481                 * Add to result set.
12482                 */
12483                 if (outSeq == NULL) {
12484                     if (size != newSize) {
12485                         /*
12486                         * We need to merge and clear here, since
12487                         * the sequence will contained NULLed entries.
12488                         */
12489                         outSeq = mergeAndClear(NULL, seq, 1);
12490                     } else {
12491                         outSeq = seq;
12492                         seq = NULL;
12493                     }
12494                 } else
12495                     outSeq = mergeAndClear(outSeq, seq,
12496                         (size != newSize) ? 1: 0);
12497                 /*
12498                 * Break if only a true/false result was requested.
12499                 */
12500                 if (toBool)
12501                     break;
12502             }
12503         } else if (seq->nodeNr > 0) {
12504             /*
12505             * Add to result set.
12506             */
12507             if (outSeq == NULL) {
12508                 outSeq = seq;
12509                 seq = NULL;
12510             } else {
12511                 outSeq = mergeAndClear(outSeq, seq, 0);
12512             }
12513         }
12514     }
12515
12516 error:
12517     if ((obj->boolval) && (obj->user != NULL)) {
12518         /*
12519         * QUESTION TODO: What does this do and why?
12520         * TODO: Do we have to do this also for the "error"
12521         * cleanup further down?
12522         */
12523         ctxt->value->boolval = 1;
12524         ctxt->value->user = obj->user;
12525         obj->user = NULL;
12526         obj->boolval = 0;
12527     }
12528     xmlXPathReleaseObject(xpctxt, obj);
12529
12530     /*
12531     * Ensure we return at least an emtpy set.
12532     */
12533     if (outSeq == NULL) {
12534         if ((seq != NULL) && (seq->nodeNr == 0))
12535             outSeq = seq;
12536         else
12537             outSeq = xmlXPathNodeSetCreate(NULL);
12538         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12539     }
12540     if ((seq != NULL) && (seq != outSeq)) {
12541          xmlXPathFreeNodeSet(seq);
12542     }
12543     /*
12544     * Hand over the result. Better to push the set also in
12545     * case of errors.
12546     */
12547     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12548     /*
12549     * Reset the context node.
12550     */
12551     xpctxt->node = oldContextNode;
12552
12553 #ifdef DEBUG_STEP
12554     xmlGenericError(xmlGenericErrorContext,
12555         "\nExamined %d nodes, found %d nodes at that step\n",
12556         total, nbMatches);
12557 #endif
12558
12559     return(total);
12560 }
12561
12562 static int
12563 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12564                               xmlXPathStepOpPtr op, xmlNodePtr * first);
12565
12566 /**
12567  * xmlXPathCompOpEvalFirst:
12568  * @ctxt:  the XPath parser context with the compiled expression
12569  * @op:  an XPath compiled operation
12570  * @first:  the first elem found so far
12571  *
12572  * Evaluate the Precompiled XPath operation searching only the first
12573  * element in document order
12574  *
12575  * Returns the number of examined objects.
12576  */
12577 static int
12578 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12579                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12580 {
12581     int total = 0, cur;
12582     xmlXPathCompExprPtr comp;
12583     xmlXPathObjectPtr arg1, arg2;
12584
12585     CHECK_ERROR0;
12586     comp = ctxt->comp;
12587     switch (op->op) {
12588         case XPATH_OP_END:
12589             return (0);
12590         case XPATH_OP_UNION:
12591             total =
12592                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12593                                         first);
12594             CHECK_ERROR0;
12595             if ((ctxt->value != NULL)
12596                 && (ctxt->value->type == XPATH_NODESET)
12597                 && (ctxt->value->nodesetval != NULL)
12598                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12599                 /*
12600                  * limit tree traversing to first node in the result
12601                  */
12602                 /*
12603                 * OPTIMIZE TODO: This implicitely sorts
12604                 *  the result, even if not needed. E.g. if the argument
12605                 *  of the count() function, no sorting is needed.
12606                 * OPTIMIZE TODO: How do we know if the node-list wasn't
12607                 *  aready sorted?
12608                 */
12609                 if (ctxt->value->nodesetval->nodeNr > 1)
12610                     xmlXPathNodeSetSort(ctxt->value->nodesetval);
12611                 *first = ctxt->value->nodesetval->nodeTab[0];
12612             }
12613             cur =
12614                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12615                                         first);
12616             CHECK_ERROR0;
12617             CHECK_TYPE0(XPATH_NODESET);
12618             arg2 = valuePop(ctxt);
12619
12620             CHECK_TYPE0(XPATH_NODESET);
12621             arg1 = valuePop(ctxt);
12622
12623             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12624                                                     arg2->nodesetval);
12625             valuePush(ctxt, arg1);
12626             xmlXPathReleaseObject(ctxt->context, arg2);
12627             /* optimizer */
12628             if (total > cur)
12629                 xmlXPathCompSwap(op);
12630             return (total + cur);
12631         case XPATH_OP_ROOT:
12632             xmlXPathRoot(ctxt);
12633             return (0);
12634         case XPATH_OP_NODE:
12635             if (op->ch1 != -1)
12636                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12637             CHECK_ERROR0;
12638             if (op->ch2 != -1)
12639                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12640             CHECK_ERROR0;
12641             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12642                 ctxt->context->node));
12643             return (total);
12644         case XPATH_OP_RESET:
12645             if (op->ch1 != -1)
12646                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12647             CHECK_ERROR0;
12648             if (op->ch2 != -1)
12649                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12650             CHECK_ERROR0;
12651             ctxt->context->node = NULL;
12652             return (total);
12653         case XPATH_OP_COLLECT:{
12654                 if (op->ch1 == -1)
12655                     return (total);
12656
12657                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12658                 CHECK_ERROR0;
12659
12660                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12661                 return (total);
12662             }
12663         case XPATH_OP_VALUE:
12664             valuePush(ctxt,
12665                       xmlXPathCacheObjectCopy(ctxt->context,
12666                         (xmlXPathObjectPtr) op->value4));
12667             return (0);
12668         case XPATH_OP_SORT:
12669             if (op->ch1 != -1)
12670                 total +=
12671                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12672                                             first);
12673             CHECK_ERROR0;
12674             if ((ctxt->value != NULL)
12675                 && (ctxt->value->type == XPATH_NODESET)
12676                 && (ctxt->value->nodesetval != NULL)
12677                 && (ctxt->value->nodesetval->nodeNr > 1))
12678                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12679             return (total);
12680 #ifdef XP_OPTIMIZED_FILTER_FIRST
12681         case XPATH_OP_FILTER:
12682                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12683             return (total);
12684 #endif
12685         default:
12686             return (xmlXPathCompOpEval(ctxt, op));
12687     }
12688 }
12689
12690 /**
12691  * xmlXPathCompOpEvalLast:
12692  * @ctxt:  the XPath parser context with the compiled expression
12693  * @op:  an XPath compiled operation
12694  * @last:  the last elem found so far
12695  *
12696  * Evaluate the Precompiled XPath operation searching only the last
12697  * element in document order
12698  *
12699  * Returns the number of nodes traversed
12700  */
12701 static int
12702 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12703                        xmlNodePtr * last)
12704 {
12705     int total = 0, cur;
12706     xmlXPathCompExprPtr comp;
12707     xmlXPathObjectPtr arg1, arg2;
12708     xmlNodePtr bak;
12709     xmlDocPtr bakd;
12710     int pp;
12711     int cs;
12712
12713     CHECK_ERROR0;
12714     comp = ctxt->comp;
12715     switch (op->op) {
12716         case XPATH_OP_END:
12717             return (0);
12718         case XPATH_OP_UNION:
12719             bakd = ctxt->context->doc;
12720             bak = ctxt->context->node;
12721             pp = ctxt->context->proximityPosition;
12722             cs = ctxt->context->contextSize;
12723             total =
12724                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12725             CHECK_ERROR0;
12726             if ((ctxt->value != NULL)
12727                 && (ctxt->value->type == XPATH_NODESET)
12728                 && (ctxt->value->nodesetval != NULL)
12729                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12730                 /*
12731                  * limit tree traversing to first node in the result
12732                  */
12733                 if (ctxt->value->nodesetval->nodeNr > 1)
12734                     xmlXPathNodeSetSort(ctxt->value->nodesetval);
12735                 *last =
12736                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12737                                                      nodesetval->nodeNr -
12738                                                      1];
12739             }
12740             ctxt->context->doc = bakd;
12741             ctxt->context->node = bak;
12742             ctxt->context->proximityPosition = pp;
12743             ctxt->context->contextSize = cs;
12744             cur =
12745                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12746             CHECK_ERROR0;
12747             if ((ctxt->value != NULL)
12748                 && (ctxt->value->type == XPATH_NODESET)
12749                 && (ctxt->value->nodesetval != NULL)
12750                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12751             }
12752             CHECK_TYPE0(XPATH_NODESET);
12753             arg2 = valuePop(ctxt);
12754
12755             CHECK_TYPE0(XPATH_NODESET);
12756             arg1 = valuePop(ctxt);
12757
12758             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12759                                                     arg2->nodesetval);
12760             valuePush(ctxt, arg1);
12761             xmlXPathReleaseObject(ctxt->context, arg2);
12762             /* optimizer */
12763             if (total > cur)
12764                 xmlXPathCompSwap(op);
12765             return (total + cur);
12766         case XPATH_OP_ROOT:
12767             xmlXPathRoot(ctxt);
12768             return (0);
12769         case XPATH_OP_NODE:
12770             if (op->ch1 != -1)
12771                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12772             CHECK_ERROR0;
12773             if (op->ch2 != -1)
12774                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12775             CHECK_ERROR0;
12776             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12777                 ctxt->context->node));
12778             return (total);
12779         case XPATH_OP_RESET:
12780             if (op->ch1 != -1)
12781                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12782             CHECK_ERROR0;
12783             if (op->ch2 != -1)
12784                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12785             CHECK_ERROR0;
12786             ctxt->context->node = NULL;
12787             return (total);
12788         case XPATH_OP_COLLECT:{
12789                 if (op->ch1 == -1)
12790                     return (0);
12791
12792                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12793                 CHECK_ERROR0;
12794
12795                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12796                 return (total);
12797             }
12798         case XPATH_OP_VALUE:
12799             valuePush(ctxt,
12800                       xmlXPathCacheObjectCopy(ctxt->context,
12801                         (xmlXPathObjectPtr) op->value4));
12802             return (0);
12803         case XPATH_OP_SORT:
12804             if (op->ch1 != -1)
12805                 total +=
12806                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12807                                            last);
12808             CHECK_ERROR0;
12809             if ((ctxt->value != NULL)
12810                 && (ctxt->value->type == XPATH_NODESET)
12811                 && (ctxt->value->nodesetval != NULL)
12812                 && (ctxt->value->nodesetval->nodeNr > 1))
12813                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12814             return (total);
12815         default:
12816             return (xmlXPathCompOpEval(ctxt, op));
12817     }
12818 }
12819
12820 #ifdef XP_OPTIMIZED_FILTER_FIRST
12821 static int
12822 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12823                               xmlXPathStepOpPtr op, xmlNodePtr * first)
12824 {
12825     int total = 0;
12826     xmlXPathCompExprPtr comp;
12827     xmlXPathObjectPtr res;
12828     xmlXPathObjectPtr obj;
12829     xmlNodeSetPtr oldset;
12830     xmlNodePtr oldnode;
12831     xmlDocPtr oldDoc;
12832     int i;
12833
12834     CHECK_ERROR0;
12835     comp = ctxt->comp;
12836     /*
12837     * Optimization for ()[last()] selection i.e. the last elem
12838     */
12839     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12840         (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12841         (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12842         int f = comp->steps[op->ch2].ch1;
12843
12844         if ((f != -1) &&
12845             (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12846             (comp->steps[f].value5 == NULL) &&
12847             (comp->steps[f].value == 0) &&
12848             (comp->steps[f].value4 != NULL) &&
12849             (xmlStrEqual
12850             (comp->steps[f].value4, BAD_CAST "last"))) {
12851             xmlNodePtr last = NULL;
12852
12853             total +=
12854                 xmlXPathCompOpEvalLast(ctxt,
12855                     &comp->steps[op->ch1],
12856                     &last);
12857             CHECK_ERROR0;
12858             /*
12859             * The nodeset should be in document order,
12860             * Keep only the last value
12861             */
12862             if ((ctxt->value != NULL) &&
12863                 (ctxt->value->type == XPATH_NODESET) &&
12864                 (ctxt->value->nodesetval != NULL) &&
12865                 (ctxt->value->nodesetval->nodeTab != NULL) &&
12866                 (ctxt->value->nodesetval->nodeNr > 1)) {
12867                 ctxt->value->nodesetval->nodeTab[0] =
12868                     ctxt->value->nodesetval->nodeTab[ctxt->
12869                     value->
12870                     nodesetval->
12871                     nodeNr -
12872                     1];
12873                 ctxt->value->nodesetval->nodeNr = 1;
12874                 *first = *(ctxt->value->nodesetval->nodeTab);
12875             }
12876             return (total);
12877         }
12878     }
12879
12880     if (op->ch1 != -1)
12881         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12882     CHECK_ERROR0;
12883     if (op->ch2 == -1)
12884         return (total);
12885     if (ctxt->value == NULL)
12886         return (total);
12887
12888 #ifdef LIBXML_XPTR_ENABLED
12889     oldnode = ctxt->context->node;
12890     /*
12891     * Hum are we filtering the result of an XPointer expression
12892     */
12893     if (ctxt->value->type == XPATH_LOCATIONSET) {
12894         xmlXPathObjectPtr tmp = NULL;
12895         xmlLocationSetPtr newlocset = NULL;
12896         xmlLocationSetPtr oldlocset;
12897
12898         /*
12899         * Extract the old locset, and then evaluate the result of the
12900         * expression for all the element in the locset. use it to grow
12901         * up a new locset.
12902         */
12903         CHECK_TYPE0(XPATH_LOCATIONSET);
12904         obj = valuePop(ctxt);
12905         oldlocset = obj->user;
12906         ctxt->context->node = NULL;
12907
12908         if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12909             ctxt->context->contextSize = 0;
12910             ctxt->context->proximityPosition = 0;
12911             if (op->ch2 != -1)
12912                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12913             res = valuePop(ctxt);
12914             if (res != NULL) {
12915                 xmlXPathReleaseObject(ctxt->context, res);
12916             }
12917             valuePush(ctxt, obj);
12918             CHECK_ERROR0;
12919             return (total);
12920         }
12921         newlocset = xmlXPtrLocationSetCreate(NULL);
12922
12923         for (i = 0; i < oldlocset->locNr; i++) {
12924             /*
12925             * Run the evaluation with a node list made of a
12926             * single item in the nodelocset.
12927             */
12928             ctxt->context->node = oldlocset->locTab[i]->user;
12929             ctxt->context->contextSize = oldlocset->locNr;
12930             ctxt->context->proximityPosition = i + 1;
12931             if (tmp == NULL) {
12932                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12933                     ctxt->context->node);
12934             } else {
12935                 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12936                     ctxt->context->node);
12937             }
12938             valuePush(ctxt, tmp);
12939             if (op->ch2 != -1)
12940                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12941             if (ctxt->error != XPATH_EXPRESSION_OK) {
12942                 xmlXPathFreeObject(obj);
12943                 return(0);
12944             }
12945             /*
12946             * The result of the evaluation need to be tested to
12947             * decided whether the filter succeeded or not
12948             */
12949             res = valuePop(ctxt);
12950             if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12951                 xmlXPtrLocationSetAdd(newlocset,
12952                     xmlXPathCacheObjectCopy(ctxt->context,
12953                         oldlocset->locTab[i]));
12954             }
12955             /*
12956             * Cleanup
12957             */
12958             if (res != NULL) {
12959                 xmlXPathReleaseObject(ctxt->context, res);
12960             }
12961             if (ctxt->value == tmp) {
12962                 valuePop(ctxt);
12963                 xmlXPathNodeSetClear(tmp->nodesetval, 1);
12964                 /*
12965                 * REVISIT TODO: Don't create a temporary nodeset
12966                 * for everly iteration.
12967                 */
12968                 /* OLD: xmlXPathFreeObject(res); */
12969             } else
12970                 tmp = NULL;
12971             ctxt->context->node = NULL;
12972             /*
12973             * Only put the first node in the result, then leave.
12974             */
12975             if (newlocset->locNr > 0) {
12976                 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12977                 break;
12978             }
12979         }
12980         if (tmp != NULL) {
12981             xmlXPathReleaseObject(ctxt->context, tmp);
12982         }
12983         /*
12984         * The result is used as the new evaluation locset.
12985         */
12986         xmlXPathReleaseObject(ctxt->context, obj);
12987         ctxt->context->node = NULL;
12988         ctxt->context->contextSize = -1;
12989         ctxt->context->proximityPosition = -1;
12990         valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12991         ctxt->context->node = oldnode;
12992         return (total);
12993     }
12994 #endif /* LIBXML_XPTR_ENABLED */
12995
12996     /*
12997     * Extract the old set, and then evaluate the result of the
12998     * expression for all the element in the set. use it to grow
12999     * up a new set.
13000     */
13001     CHECK_TYPE0(XPATH_NODESET);
13002     obj = valuePop(ctxt);
13003     oldset = obj->nodesetval;
13004
13005     oldnode = ctxt->context->node;
13006     oldDoc = ctxt->context->doc;
13007     ctxt->context->node = NULL;
13008
13009     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13010         ctxt->context->contextSize = 0;
13011         ctxt->context->proximityPosition = 0;
13012         /* QUESTION TODO: Why was this code commented out?
13013             if (op->ch2 != -1)
13014                 total +=
13015                     xmlXPathCompOpEval(ctxt,
13016                         &comp->steps[op->ch2]);
13017             CHECK_ERROR0;
13018             res = valuePop(ctxt);
13019             if (res != NULL)
13020                 xmlXPathFreeObject(res);
13021         */
13022         valuePush(ctxt, obj);
13023         ctxt->context->node = oldnode;
13024         CHECK_ERROR0;
13025     } else {
13026         xmlNodeSetPtr newset;
13027         xmlXPathObjectPtr tmp = NULL;
13028         /*
13029         * Initialize the new set.
13030         * Also set the xpath document in case things like
13031         * key() evaluation are attempted on the predicate
13032         */
13033         newset = xmlXPathNodeSetCreate(NULL);
13034         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13035
13036         for (i = 0; i < oldset->nodeNr; i++) {
13037             /*
13038             * Run the evaluation with a node list made of
13039             * a single item in the nodeset.
13040             */
13041             ctxt->context->node = oldset->nodeTab[i];
13042             if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13043                 (oldset->nodeTab[i]->doc != NULL))
13044                 ctxt->context->doc = oldset->nodeTab[i]->doc;
13045             if (tmp == NULL) {
13046                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13047                     ctxt->context->node);
13048             } else {
13049                 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13050                     ctxt->context->node);
13051             }
13052             valuePush(ctxt, tmp);
13053             ctxt->context->contextSize = oldset->nodeNr;
13054             ctxt->context->proximityPosition = i + 1;
13055             if (op->ch2 != -1)
13056                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13057             if (ctxt->error != XPATH_EXPRESSION_OK) {
13058                 xmlXPathFreeNodeSet(newset);
13059                 xmlXPathFreeObject(obj);
13060                 return(0);
13061             }
13062             /*
13063             * The result of the evaluation needs to be tested to
13064             * decide whether the filter succeeded or not
13065             */
13066             res = valuePop(ctxt);
13067             if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13068                 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13069             }
13070             /*
13071             * Cleanup
13072             */
13073             if (res != NULL) {
13074                 xmlXPathReleaseObject(ctxt->context, res);
13075             }
13076             if (ctxt->value == tmp) {
13077                 valuePop(ctxt);
13078                 /*
13079                 * Don't free the temporary nodeset
13080                 * in order to avoid massive recreation inside this
13081                 * loop.
13082                 */
13083                 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13084             } else
13085                 tmp = NULL;
13086             ctxt->context->node = NULL;
13087             /*
13088             * Only put the first node in the result, then leave.
13089             */
13090             if (newset->nodeNr > 0) {
13091                 *first = *(newset->nodeTab);
13092                 break;
13093             }
13094         }
13095         if (tmp != NULL) {
13096             xmlXPathReleaseObject(ctxt->context, tmp);
13097         }
13098         /*
13099         * The result is used as the new evaluation set.
13100         */
13101         xmlXPathReleaseObject(ctxt->context, obj);
13102         ctxt->context->node = NULL;
13103         ctxt->context->contextSize = -1;
13104         ctxt->context->proximityPosition = -1;
13105         /* may want to move this past the '}' later */
13106         ctxt->context->doc = oldDoc;
13107         valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13108     }
13109     ctxt->context->node = oldnode;
13110     return(total);
13111 }
13112 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13113
13114 /**
13115  * xmlXPathCompOpEval:
13116  * @ctxt:  the XPath parser context with the compiled expression
13117  * @op:  an XPath compiled operation
13118  *
13119  * Evaluate the Precompiled XPath operation
13120  * Returns the number of nodes traversed
13121  */
13122 static int
13123 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13124 {
13125     int total = 0;
13126     int equal, ret;
13127     xmlXPathCompExprPtr comp;
13128     xmlXPathObjectPtr arg1, arg2;
13129     xmlNodePtr bak;
13130     xmlDocPtr bakd;
13131     int pp;
13132     int cs;
13133
13134     CHECK_ERROR0;
13135     comp = ctxt->comp;
13136     switch (op->op) {
13137         case XPATH_OP_END:
13138             return (0);
13139         case XPATH_OP_AND:
13140             bakd = ctxt->context->doc;
13141             bak = ctxt->context->node;
13142             pp = ctxt->context->proximityPosition;
13143             cs = ctxt->context->contextSize;
13144             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13145             CHECK_ERROR0;
13146             xmlXPathBooleanFunction(ctxt, 1);
13147             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13148                 return (total);
13149             arg2 = valuePop(ctxt);
13150             ctxt->context->doc = bakd;
13151             ctxt->context->node = bak;
13152             ctxt->context->proximityPosition = pp;
13153             ctxt->context->contextSize = cs;
13154             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13155             if (ctxt->error) {
13156                 xmlXPathFreeObject(arg2);
13157                 return(0);
13158             }
13159             xmlXPathBooleanFunction(ctxt, 1);
13160             arg1 = valuePop(ctxt);
13161             arg1->boolval &= arg2->boolval;
13162             valuePush(ctxt, arg1);
13163             xmlXPathReleaseObject(ctxt->context, arg2);
13164             return (total);
13165         case XPATH_OP_OR:
13166             bakd = ctxt->context->doc;
13167             bak = ctxt->context->node;
13168             pp = ctxt->context->proximityPosition;
13169             cs = ctxt->context->contextSize;
13170             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13171             CHECK_ERROR0;
13172             xmlXPathBooleanFunction(ctxt, 1);
13173             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13174                 return (total);
13175             arg2 = valuePop(ctxt);
13176             ctxt->context->doc = bakd;
13177             ctxt->context->node = bak;
13178             ctxt->context->proximityPosition = pp;
13179             ctxt->context->contextSize = cs;
13180             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13181             if (ctxt->error) {
13182                 xmlXPathFreeObject(arg2);
13183                 return(0);
13184             }
13185             xmlXPathBooleanFunction(ctxt, 1);
13186             arg1 = valuePop(ctxt);
13187             arg1->boolval |= arg2->boolval;
13188             valuePush(ctxt, arg1);
13189             xmlXPathReleaseObject(ctxt->context, arg2);
13190             return (total);
13191         case XPATH_OP_EQUAL:
13192             bakd = ctxt->context->doc;
13193             bak = ctxt->context->node;
13194             pp = ctxt->context->proximityPosition;
13195             cs = ctxt->context->contextSize;
13196             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13197             CHECK_ERROR0;
13198             ctxt->context->doc = bakd;
13199             ctxt->context->node = bak;
13200             ctxt->context->proximityPosition = pp;
13201             ctxt->context->contextSize = cs;
13202             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13203             CHECK_ERROR0;
13204             if (op->value)
13205                 equal = xmlXPathEqualValues(ctxt);
13206             else
13207                 equal = xmlXPathNotEqualValues(ctxt);
13208             valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13209             return (total);
13210         case XPATH_OP_CMP:
13211             bakd = ctxt->context->doc;
13212             bak = ctxt->context->node;
13213             pp = ctxt->context->proximityPosition;
13214             cs = ctxt->context->contextSize;
13215             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13216             CHECK_ERROR0;
13217             ctxt->context->doc = bakd;
13218             ctxt->context->node = bak;
13219             ctxt->context->proximityPosition = pp;
13220             ctxt->context->contextSize = cs;
13221             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13222             CHECK_ERROR0;
13223             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13224             valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13225             return (total);
13226         case XPATH_OP_PLUS:
13227             bakd = ctxt->context->doc;
13228             bak = ctxt->context->node;
13229             pp = ctxt->context->proximityPosition;
13230             cs = ctxt->context->contextSize;
13231             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13232             CHECK_ERROR0;
13233             if (op->ch2 != -1) {
13234                 ctxt->context->doc = bakd;
13235                 ctxt->context->node = bak;
13236                 ctxt->context->proximityPosition = pp;
13237                 ctxt->context->contextSize = cs;
13238                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13239             }
13240             CHECK_ERROR0;
13241             if (op->value == 0)
13242                 xmlXPathSubValues(ctxt);
13243             else if (op->value == 1)
13244                 xmlXPathAddValues(ctxt);
13245             else if (op->value == 2)
13246                 xmlXPathValueFlipSign(ctxt);
13247             else if (op->value == 3) {
13248                 CAST_TO_NUMBER;
13249                 CHECK_TYPE0(XPATH_NUMBER);
13250             }
13251             return (total);
13252         case XPATH_OP_MULT:
13253             bakd = ctxt->context->doc;
13254             bak = ctxt->context->node;
13255             pp = ctxt->context->proximityPosition;
13256             cs = ctxt->context->contextSize;
13257             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13258             CHECK_ERROR0;
13259             ctxt->context->doc = bakd;
13260             ctxt->context->node = bak;
13261             ctxt->context->proximityPosition = pp;
13262             ctxt->context->contextSize = cs;
13263             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13264             CHECK_ERROR0;
13265             if (op->value == 0)
13266                 xmlXPathMultValues(ctxt);
13267             else if (op->value == 1)
13268                 xmlXPathDivValues(ctxt);
13269             else if (op->value == 2)
13270                 xmlXPathModValues(ctxt);
13271             return (total);
13272         case XPATH_OP_UNION:
13273             bakd = ctxt->context->doc;
13274             bak = ctxt->context->node;
13275             pp = ctxt->context->proximityPosition;
13276             cs = ctxt->context->contextSize;
13277             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13278             CHECK_ERROR0;
13279             ctxt->context->doc = bakd;
13280             ctxt->context->node = bak;
13281             ctxt->context->proximityPosition = pp;
13282             ctxt->context->contextSize = cs;
13283             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13284             CHECK_ERROR0;
13285             CHECK_TYPE0(XPATH_NODESET);
13286             arg2 = valuePop(ctxt);
13287
13288             CHECK_TYPE0(XPATH_NODESET);
13289             arg1 = valuePop(ctxt);
13290
13291             if ((arg1->nodesetval == NULL) ||
13292                 ((arg2->nodesetval != NULL) &&
13293                  (arg2->nodesetval->nodeNr != 0)))
13294             {
13295                 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13296                                                         arg2->nodesetval);
13297             }
13298
13299             valuePush(ctxt, arg1);
13300             xmlXPathReleaseObject(ctxt->context, arg2);
13301             return (total);
13302         case XPATH_OP_ROOT:
13303             xmlXPathRoot(ctxt);
13304             return (total);
13305         case XPATH_OP_NODE:
13306             if (op->ch1 != -1)
13307                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13308             CHECK_ERROR0;
13309             if (op->ch2 != -1)
13310                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13311             CHECK_ERROR0;
13312             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13313                 ctxt->context->node));
13314             return (total);
13315         case XPATH_OP_RESET:
13316             if (op->ch1 != -1)
13317                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13318             CHECK_ERROR0;
13319             if (op->ch2 != -1)
13320                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13321             CHECK_ERROR0;
13322             ctxt->context->node = NULL;
13323             return (total);
13324         case XPATH_OP_COLLECT:{
13325                 if (op->ch1 == -1)
13326                     return (total);
13327
13328                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13329                 CHECK_ERROR0;
13330
13331                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13332                 return (total);
13333             }
13334         case XPATH_OP_VALUE:
13335             valuePush(ctxt,
13336                       xmlXPathCacheObjectCopy(ctxt->context,
13337                         (xmlXPathObjectPtr) op->value4));
13338             return (total);
13339         case XPATH_OP_VARIABLE:{
13340                 xmlXPathObjectPtr val;
13341
13342                 if (op->ch1 != -1)
13343                     total +=
13344                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13345                 if (op->value5 == NULL) {
13346                     val = xmlXPathVariableLookup(ctxt->context, op->value4);
13347                     if (val == NULL) {
13348                         ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13349                         return(0);
13350                     }
13351                     valuePush(ctxt, val);
13352                 } else {
13353                     const xmlChar *URI;
13354
13355                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13356                     if (URI == NULL) {
13357                         xmlGenericError(xmlGenericErrorContext,
13358             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13359                                     (char *) op->value4, (char *)op->value5);
13360                         return (total);
13361                     }
13362                     val = xmlXPathVariableLookupNS(ctxt->context,
13363                                                        op->value4, URI);
13364                     if (val == NULL) {
13365                         ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13366                         return(0);
13367                     }
13368                     valuePush(ctxt, val);
13369                 }
13370                 return (total);
13371             }
13372         case XPATH_OP_FUNCTION:{
13373                 xmlXPathFunction func;
13374                 const xmlChar *oldFunc, *oldFuncURI;
13375                 int i;
13376
13377                 if (op->ch1 != -1)
13378                     total +=
13379                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13380                 if (ctxt->valueNr < op->value) {
13381                     xmlGenericError(xmlGenericErrorContext,
13382                             "xmlXPathCompOpEval: parameter error\n");
13383                     ctxt->error = XPATH_INVALID_OPERAND;
13384                     return (total);
13385                 }
13386                 for (i = 0; i < op->value; i++)
13387                     if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13388                         xmlGenericError(xmlGenericErrorContext,
13389                                 "xmlXPathCompOpEval: parameter error\n");
13390                         ctxt->error = XPATH_INVALID_OPERAND;
13391                         return (total);
13392                     }
13393                 if (op->cache != NULL)
13394                     XML_CAST_FPTR(func) = op->cache;
13395                 else {
13396                     const xmlChar *URI = NULL;
13397
13398                     if (op->value5 == NULL)
13399                         func =
13400                             xmlXPathFunctionLookup(ctxt->context,
13401                                                    op->value4);
13402                     else {
13403                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13404                         if (URI == NULL) {
13405                             xmlGenericError(xmlGenericErrorContext,
13406             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13407                                     (char *)op->value4, (char *)op->value5);
13408                             return (total);
13409                         }
13410                         func = xmlXPathFunctionLookupNS(ctxt->context,
13411                                                         op->value4, URI);
13412                     }
13413                     if (func == NULL) {
13414                         xmlGenericError(xmlGenericErrorContext,
13415                                 "xmlXPathCompOpEval: function %s not found\n",
13416                                         (char *)op->value4);
13417                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13418                     }
13419                     op->cache = XML_CAST_FPTR(func);
13420                     op->cacheURI = (void *) URI;
13421                 }
13422                 oldFunc = ctxt->context->function;
13423                 oldFuncURI = ctxt->context->functionURI;
13424                 ctxt->context->function = op->value4;
13425                 ctxt->context->functionURI = op->cacheURI;
13426                 func(ctxt, op->value);
13427                 ctxt->context->function = oldFunc;
13428                 ctxt->context->functionURI = oldFuncURI;
13429                 return (total);
13430             }
13431         case XPATH_OP_ARG:
13432             bakd = ctxt->context->doc;
13433             bak = ctxt->context->node;
13434             pp = ctxt->context->proximityPosition;
13435             cs = ctxt->context->contextSize;
13436             if (op->ch1 != -1)
13437                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13438             ctxt->context->contextSize = cs;
13439             ctxt->context->proximityPosition = pp;
13440             ctxt->context->node = bak;
13441             ctxt->context->doc = bakd;
13442             CHECK_ERROR0;
13443             if (op->ch2 != -1) {
13444                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13445                 ctxt->context->doc = bakd;
13446                 ctxt->context->node = bak;
13447                 CHECK_ERROR0;
13448             }
13449             return (total);
13450         case XPATH_OP_PREDICATE:
13451         case XPATH_OP_FILTER:{
13452                 xmlXPathObjectPtr res;
13453                 xmlXPathObjectPtr obj, tmp;
13454                 xmlNodeSetPtr newset = NULL;
13455                 xmlNodeSetPtr oldset;
13456                 xmlNodePtr oldnode;
13457                 xmlDocPtr oldDoc;
13458                 int i;
13459
13460                 /*
13461                  * Optimization for ()[1] selection i.e. the first elem
13462                  */
13463                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13464 #ifdef XP_OPTIMIZED_FILTER_FIRST
13465                     /*
13466                     * FILTER TODO: Can we assume that the inner processing
13467                     *  will result in an ordered list if we have an
13468                     *  XPATH_OP_FILTER?
13469                     *  What about an additional field or flag on
13470                     *  xmlXPathObject like @sorted ? This way we wouln'd need
13471                     *  to assume anything, so it would be more robust and
13472                     *  easier to optimize.
13473                     */
13474                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13475                      (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13476 #else
13477                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13478 #endif
13479                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13480                     xmlXPathObjectPtr val;
13481
13482                     val = comp->steps[op->ch2].value4;
13483                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13484                         (val->floatval == 1.0)) {
13485                         xmlNodePtr first = NULL;
13486
13487                         total +=
13488                             xmlXPathCompOpEvalFirst(ctxt,
13489                                                     &comp->steps[op->ch1],
13490                                                     &first);
13491                         CHECK_ERROR0;
13492                         /*
13493                          * The nodeset should be in document order,
13494                          * Keep only the first value
13495                          */
13496                         if ((ctxt->value != NULL) &&
13497                             (ctxt->value->type == XPATH_NODESET) &&
13498                             (ctxt->value->nodesetval != NULL) &&
13499                             (ctxt->value->nodesetval->nodeNr > 1))
13500                             ctxt->value->nodesetval->nodeNr = 1;
13501                         return (total);
13502                     }
13503                 }
13504                 /*
13505                  * Optimization for ()[last()] selection i.e. the last elem
13506                  */
13507                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13508                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13509                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13510                     int f = comp->steps[op->ch2].ch1;
13511
13512                     if ((f != -1) &&
13513                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13514                         (comp->steps[f].value5 == NULL) &&
13515                         (comp->steps[f].value == 0) &&
13516                         (comp->steps[f].value4 != NULL) &&
13517                         (xmlStrEqual
13518                          (comp->steps[f].value4, BAD_CAST "last"))) {
13519                         xmlNodePtr last = NULL;
13520
13521                         total +=
13522                             xmlXPathCompOpEvalLast(ctxt,
13523                                                    &comp->steps[op->ch1],
13524                                                    &last);
13525                         CHECK_ERROR0;
13526                         /*
13527                          * The nodeset should be in document order,
13528                          * Keep only the last value
13529                          */
13530                         if ((ctxt->value != NULL) &&
13531                             (ctxt->value->type == XPATH_NODESET) &&
13532                             (ctxt->value->nodesetval != NULL) &&
13533                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13534                             (ctxt->value->nodesetval->nodeNr > 1)) {
13535                             ctxt->value->nodesetval->nodeTab[0] =
13536                                 ctxt->value->nodesetval->nodeTab[ctxt->
13537                                                                  value->
13538                                                                  nodesetval->
13539                                                                  nodeNr -
13540                                                                  1];
13541                             ctxt->value->nodesetval->nodeNr = 1;
13542                         }
13543                         return (total);
13544                     }
13545                 }
13546                 /*
13547                 * Process inner predicates first.
13548                 * Example "index[parent::book][1]":
13549                 * ...
13550                 *   PREDICATE   <-- we are here "[1]"
13551                 *     PREDICATE <-- process "[parent::book]" first
13552                 *       SORT
13553                 *         COLLECT  'parent' 'name' 'node' book
13554                 *           NODE
13555                 *     ELEM Object is a number : 1
13556                 */
13557                 if (op->ch1 != -1)
13558                     total +=
13559                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13560                 CHECK_ERROR0;
13561                 if (op->ch2 == -1)
13562                     return (total);
13563                 if (ctxt->value == NULL)
13564                     return (total);
13565
13566                 oldnode = ctxt->context->node;
13567
13568 #ifdef LIBXML_XPTR_ENABLED
13569                 /*
13570                  * Hum are we filtering the result of an XPointer expression
13571                  */
13572                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13573                     xmlLocationSetPtr newlocset = NULL;
13574                     xmlLocationSetPtr oldlocset;
13575
13576                     /*
13577                      * Extract the old locset, and then evaluate the result of the
13578                      * expression for all the element in the locset. use it to grow
13579                      * up a new locset.
13580                      */
13581                     CHECK_TYPE0(XPATH_LOCATIONSET);
13582                     obj = valuePop(ctxt);
13583                     oldlocset = obj->user;
13584                     ctxt->context->node = NULL;
13585
13586                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13587                         ctxt->context->contextSize = 0;
13588                         ctxt->context->proximityPosition = 0;
13589                         if (op->ch2 != -1)
13590                             total +=
13591                                 xmlXPathCompOpEval(ctxt,
13592                                                    &comp->steps[op->ch2]);
13593                         res = valuePop(ctxt);
13594                         if (res != NULL) {
13595                             xmlXPathReleaseObject(ctxt->context, res);
13596                         }
13597                         valuePush(ctxt, obj);
13598                         CHECK_ERROR0;
13599                         return (total);
13600                     }
13601                     newlocset = xmlXPtrLocationSetCreate(NULL);
13602
13603                     for (i = 0; i < oldlocset->locNr; i++) {
13604                         /*
13605                          * Run the evaluation with a node list made of a
13606                          * single item in the nodelocset.
13607                          */
13608                         ctxt->context->node = oldlocset->locTab[i]->user;
13609                         ctxt->context->contextSize = oldlocset->locNr;
13610                         ctxt->context->proximityPosition = i + 1;
13611                         tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13612                             ctxt->context->node);
13613                         valuePush(ctxt, tmp);
13614
13615                         if (op->ch2 != -1)
13616                             total +=
13617                                 xmlXPathCompOpEval(ctxt,
13618                                                    &comp->steps[op->ch2]);
13619                         if (ctxt->error != XPATH_EXPRESSION_OK) {
13620                             xmlXPathFreeObject(obj);
13621                             return(0);
13622                         }
13623
13624                         /*
13625                          * The result of the evaluation need to be tested to
13626                          * decided whether the filter succeeded or not
13627                          */
13628                         res = valuePop(ctxt);
13629                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13630                             xmlXPtrLocationSetAdd(newlocset,
13631                                                   xmlXPathObjectCopy
13632                                                   (oldlocset->locTab[i]));
13633                         }
13634
13635                         /*
13636                          * Cleanup
13637                          */
13638                         if (res != NULL) {
13639                             xmlXPathReleaseObject(ctxt->context, res);
13640                         }
13641                         if (ctxt->value == tmp) {
13642                             res = valuePop(ctxt);
13643                             xmlXPathReleaseObject(ctxt->context, res);
13644                         }
13645
13646                         ctxt->context->node = NULL;
13647                     }
13648
13649                     /*
13650                      * The result is used as the new evaluation locset.
13651                      */
13652                     xmlXPathReleaseObject(ctxt->context, obj);
13653                     ctxt->context->node = NULL;
13654                     ctxt->context->contextSize = -1;
13655                     ctxt->context->proximityPosition = -1;
13656                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13657                     ctxt->context->node = oldnode;
13658                     return (total);
13659                 }
13660 #endif /* LIBXML_XPTR_ENABLED */
13661
13662                 /*
13663                  * Extract the old set, and then evaluate the result of the
13664                  * expression for all the element in the set. use it to grow
13665                  * up a new set.
13666                  */
13667                 CHECK_TYPE0(XPATH_NODESET);
13668                 obj = valuePop(ctxt);
13669                 oldset = obj->nodesetval;
13670
13671                 oldnode = ctxt->context->node;
13672                 oldDoc = ctxt->context->doc;
13673                 ctxt->context->node = NULL;
13674
13675                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13676                     ctxt->context->contextSize = 0;
13677                     ctxt->context->proximityPosition = 0;
13678 /*
13679                     if (op->ch2 != -1)
13680                         total +=
13681                             xmlXPathCompOpEval(ctxt,
13682                                                &comp->steps[op->ch2]);
13683                     CHECK_ERROR0;
13684                     res = valuePop(ctxt);
13685                     if (res != NULL)
13686                         xmlXPathFreeObject(res);
13687 */
13688                     valuePush(ctxt, obj);
13689                     ctxt->context->node = oldnode;
13690                     CHECK_ERROR0;
13691                 } else {
13692                     tmp = NULL;
13693                     /*
13694                      * Initialize the new set.
13695                      * Also set the xpath document in case things like
13696                      * key() evaluation are attempted on the predicate
13697                      */
13698                     newset = xmlXPathNodeSetCreate(NULL);
13699                     /*
13700                     * SPEC XPath 1.0:
13701                     *  "For each node in the node-set to be filtered, the
13702                     *  PredicateExpr is evaluated with that node as the
13703                     *  context node, with the number of nodes in the
13704                     *  node-set as the context size, and with the proximity
13705                     *  position of the node in the node-set with respect to
13706                     *  the axis as the context position;"
13707                     * @oldset is the node-set" to be filtered.
13708                     *
13709                     * SPEC XPath 1.0:
13710                     *  "only predicates change the context position and
13711                     *  context size (see [2.4 Predicates])."
13712                     * Example:
13713                     *   node-set  context pos
13714                     *    nA         1
13715                     *    nB         2
13716                     *    nC         3
13717                     *   After applying predicate [position() > 1] :
13718                     *   node-set  context pos
13719                     *    nB         1
13720                     *    nC         2
13721                     *
13722                     * removed the first node in the node-set, then
13723                     * the context position of the
13724                     */
13725                     for (i = 0; i < oldset->nodeNr; i++) {
13726                         /*
13727                          * Run the evaluation with a node list made of
13728                          * a single item in the nodeset.
13729                          */
13730                         ctxt->context->node = oldset->nodeTab[i];
13731                         if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13732                             (oldset->nodeTab[i]->doc != NULL))
13733                             ctxt->context->doc = oldset->nodeTab[i]->doc;
13734                         if (tmp == NULL) {
13735                             tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13736                                 ctxt->context->node);
13737                         } else {
13738                             xmlXPathNodeSetAddUnique(tmp->nodesetval,
13739                                 ctxt->context->node);
13740                         }
13741                         valuePush(ctxt, tmp);
13742                         ctxt->context->contextSize = oldset->nodeNr;
13743                         ctxt->context->proximityPosition = i + 1;
13744                         /*
13745                         * Evaluate the predicate against the context node.
13746                         * Can/should we optimize position() predicates
13747                         * here (e.g. "[1]")?
13748                         */
13749                         if (op->ch2 != -1)
13750                             total +=
13751                                 xmlXPathCompOpEval(ctxt,
13752                                                    &comp->steps[op->ch2]);
13753                         if (ctxt->error != XPATH_EXPRESSION_OK) {
13754                             xmlXPathFreeNodeSet(newset);
13755                             xmlXPathFreeObject(obj);
13756                             return(0);
13757                         }
13758
13759                         /*
13760                          * The result of the evaluation needs to be tested to
13761                          * decide whether the filter succeeded or not
13762                          */
13763                         /*
13764                         * OPTIMIZE TODO: Can we use
13765                         * xmlXPathNodeSetAdd*Unique()* instead?
13766                         */
13767                         res = valuePop(ctxt);
13768                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13769                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13770                         }
13771
13772                         /*
13773                          * Cleanup
13774                          */
13775                         if (res != NULL) {
13776                             xmlXPathReleaseObject(ctxt->context, res);
13777                         }
13778                         if (ctxt->value == tmp) {
13779                             valuePop(ctxt);
13780                             xmlXPathNodeSetClear(tmp->nodesetval, 1);
13781                             /*
13782                             * Don't free the temporary nodeset
13783                             * in order to avoid massive recreation inside this
13784                             * loop.
13785                             */
13786                         } else
13787                             tmp = NULL;
13788                         ctxt->context->node = NULL;
13789                     }
13790                     if (tmp != NULL)
13791                         xmlXPathReleaseObject(ctxt->context, tmp);
13792                     /*
13793                      * The result is used as the new evaluation set.
13794                      */
13795                     xmlXPathReleaseObject(ctxt->context, obj);
13796                     ctxt->context->node = NULL;
13797                     ctxt->context->contextSize = -1;
13798                     ctxt->context->proximityPosition = -1;
13799                     /* may want to move this past the '}' later */
13800                     ctxt->context->doc = oldDoc;
13801                     valuePush(ctxt,
13802                         xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13803                 }
13804                 ctxt->context->node = oldnode;
13805                 return (total);
13806             }
13807         case XPATH_OP_SORT:
13808             if (op->ch1 != -1)
13809                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13810             CHECK_ERROR0;
13811             if ((ctxt->value != NULL) &&
13812                 (ctxt->value->type == XPATH_NODESET) &&
13813                 (ctxt->value->nodesetval != NULL) &&
13814                 (ctxt->value->nodesetval->nodeNr > 1))
13815             {
13816                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13817             }
13818             return (total);
13819 #ifdef LIBXML_XPTR_ENABLED
13820         case XPATH_OP_RANGETO:{
13821                 xmlXPathObjectPtr range;
13822                 xmlXPathObjectPtr res, obj;
13823                 xmlXPathObjectPtr tmp;
13824                 xmlLocationSetPtr newlocset = NULL;
13825                     xmlLocationSetPtr oldlocset;
13826                 xmlNodeSetPtr oldset;
13827                 int i, j;
13828
13829                 if (op->ch1 != -1)
13830                     total +=
13831                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13832                 if (op->ch2 == -1)
13833                     return (total);
13834
13835                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13836                     /*
13837                      * Extract the old locset, and then evaluate the result of the
13838                      * expression for all the element in the locset. use it to grow
13839                      * up a new locset.
13840                      */
13841                     CHECK_TYPE0(XPATH_LOCATIONSET);
13842                     obj = valuePop(ctxt);
13843                     oldlocset = obj->user;
13844
13845                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13846                         ctxt->context->node = NULL;
13847                         ctxt->context->contextSize = 0;
13848                         ctxt->context->proximityPosition = 0;
13849                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13850                         res = valuePop(ctxt);
13851                         if (res != NULL) {
13852                             xmlXPathReleaseObject(ctxt->context, res);
13853                         }
13854                         valuePush(ctxt, obj);
13855                         CHECK_ERROR0;
13856                         return (total);
13857                     }
13858                     newlocset = xmlXPtrLocationSetCreate(NULL);
13859
13860                     for (i = 0; i < oldlocset->locNr; i++) {
13861                         /*
13862                          * Run the evaluation with a node list made of a
13863                          * single item in the nodelocset.
13864                          */
13865                         ctxt->context->node = oldlocset->locTab[i]->user;
13866                         ctxt->context->contextSize = oldlocset->locNr;
13867                         ctxt->context->proximityPosition = i + 1;
13868                         tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13869                             ctxt->context->node);
13870                         valuePush(ctxt, tmp);
13871
13872                         if (op->ch2 != -1)
13873                             total +=
13874                                 xmlXPathCompOpEval(ctxt,
13875                                                    &comp->steps[op->ch2]);
13876                         if (ctxt->error != XPATH_EXPRESSION_OK) {
13877                             xmlXPathFreeObject(obj);
13878                             return(0);
13879                         }
13880
13881                         res = valuePop(ctxt);
13882                         if (res->type == XPATH_LOCATIONSET) {
13883                             xmlLocationSetPtr rloc =
13884                                 (xmlLocationSetPtr)res->user;
13885                             for (j=0; j<rloc->locNr; j++) {
13886                                 range = xmlXPtrNewRange(
13887                                   oldlocset->locTab[i]->user,
13888                                   oldlocset->locTab[i]->index,
13889                                   rloc->locTab[j]->user2,
13890                                   rloc->locTab[j]->index2);
13891                                 if (range != NULL) {
13892                                     xmlXPtrLocationSetAdd(newlocset, range);
13893                                 }
13894                             }
13895                         } else {
13896                             range = xmlXPtrNewRangeNodeObject(
13897                                 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13898                             if (range != NULL) {
13899                                 xmlXPtrLocationSetAdd(newlocset,range);
13900                             }
13901                         }
13902
13903                         /*
13904                          * Cleanup
13905                          */
13906                         if (res != NULL) {
13907                             xmlXPathReleaseObject(ctxt->context, res);
13908                         }
13909                         if (ctxt->value == tmp) {
13910                             res = valuePop(ctxt);
13911                             xmlXPathReleaseObject(ctxt->context, res);
13912                         }
13913
13914                         ctxt->context->node = NULL;
13915                     }
13916                 } else {        /* Not a location set */
13917                     CHECK_TYPE0(XPATH_NODESET);
13918                     obj = valuePop(ctxt);
13919                     oldset = obj->nodesetval;
13920                     ctxt->context->node = NULL;
13921
13922                     newlocset = xmlXPtrLocationSetCreate(NULL);
13923
13924                     if (oldset != NULL) {
13925                         for (i = 0; i < oldset->nodeNr; i++) {
13926                             /*
13927                              * Run the evaluation with a node list made of a single item
13928                              * in the nodeset.
13929                              */
13930                             ctxt->context->node = oldset->nodeTab[i];
13931                             /*
13932                             * OPTIMIZE TODO: Avoid recreation for every iteration.
13933                             */
13934                             tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13935                                 ctxt->context->node);
13936                             valuePush(ctxt, tmp);
13937
13938                             if (op->ch2 != -1)
13939                                 total +=
13940                                     xmlXPathCompOpEval(ctxt,
13941                                                    &comp->steps[op->ch2]);
13942                             if (ctxt->error != XPATH_EXPRESSION_OK) {
13943                                 xmlXPathFreeObject(obj);
13944                                 return(0);
13945                             }
13946
13947                             res = valuePop(ctxt);
13948                             range =
13949                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13950                                                       res);
13951                             if (range != NULL) {
13952                                 xmlXPtrLocationSetAdd(newlocset, range);
13953                             }
13954
13955                             /*
13956                              * Cleanup
13957                              */
13958                             if (res != NULL) {
13959                                 xmlXPathReleaseObject(ctxt->context, res);
13960                             }
13961                             if (ctxt->value == tmp) {
13962                                 res = valuePop(ctxt);
13963                                 xmlXPathReleaseObject(ctxt->context, res);
13964                             }
13965
13966                             ctxt->context->node = NULL;
13967                         }
13968                     }
13969                 }
13970
13971                 /*
13972                  * The result is used as the new evaluation set.
13973                  */
13974                 xmlXPathReleaseObject(ctxt->context, obj);
13975                 ctxt->context->node = NULL;
13976                 ctxt->context->contextSize = -1;
13977                 ctxt->context->proximityPosition = -1;
13978                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13979                 return (total);
13980             }
13981 #endif /* LIBXML_XPTR_ENABLED */
13982     }
13983     xmlGenericError(xmlGenericErrorContext,
13984                     "XPath: unknown precompiled operation %d\n", op->op);
13985     return (total);
13986 }
13987
13988 /**
13989  * xmlXPathCompOpEvalToBoolean:
13990  * @ctxt:  the XPath parser context
13991  *
13992  * Evaluates if the expression evaluates to true.
13993  *
13994  * Returns 1 if true, 0 if false and -1 on API or internal errors.
13995  */
13996 static int
13997 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13998                             xmlXPathStepOpPtr op,
13999                             int isPredicate)
14000 {
14001     xmlXPathObjectPtr resObj = NULL;
14002
14003 start:
14004     /* comp = ctxt->comp; */
14005     switch (op->op) {
14006         case XPATH_OP_END:
14007             return (0);
14008         case XPATH_OP_VALUE:
14009             resObj = (xmlXPathObjectPtr) op->value4;
14010             if (isPredicate)
14011                 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14012             return(xmlXPathCastToBoolean(resObj));
14013         case XPATH_OP_SORT:
14014             /*
14015             * We don't need sorting for boolean results. Skip this one.
14016             */
14017             if (op->ch1 != -1) {
14018                 op = &ctxt->comp->steps[op->ch1];
14019                 goto start;
14020             }
14021             return(0);
14022         case XPATH_OP_COLLECT:
14023             if (op->ch1 == -1)
14024                 return(0);
14025
14026             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14027             if (ctxt->error != XPATH_EXPRESSION_OK)
14028                 return(-1);
14029
14030             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14031             if (ctxt->error != XPATH_EXPRESSION_OK)
14032                 return(-1);
14033
14034             resObj = valuePop(ctxt);
14035             if (resObj == NULL)
14036                 return(-1);
14037             break;
14038         default:
14039             /*
14040             * Fallback to call xmlXPathCompOpEval().
14041             */
14042             xmlXPathCompOpEval(ctxt, op);
14043             if (ctxt->error != XPATH_EXPRESSION_OK)
14044                 return(-1);
14045
14046             resObj = valuePop(ctxt);
14047             if (resObj == NULL)
14048                 return(-1);
14049             break;
14050     }
14051
14052     if (resObj) {
14053         int res;
14054
14055         if (resObj->type == XPATH_BOOLEAN) {
14056             res = resObj->boolval;
14057         } else if (isPredicate) {
14058             /*
14059             * For predicates a result of type "number" is handled
14060             * differently:
14061             * SPEC XPath 1.0:
14062             * "If the result is a number, the result will be converted
14063             *  to true if the number is equal to the context position
14064             *  and will be converted to false otherwise;"
14065             */
14066             res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14067         } else {
14068             res = xmlXPathCastToBoolean(resObj);
14069         }
14070         xmlXPathReleaseObject(ctxt->context, resObj);
14071         return(res);
14072     }
14073
14074     return(0);
14075 }
14076
14077 #ifdef XPATH_STREAMING
14078 /**
14079  * xmlXPathRunStreamEval:
14080  * @ctxt:  the XPath parser context with the compiled expression
14081  *
14082  * Evaluate the Precompiled Streamable XPath expression in the given context.
14083  */
14084 static int
14085 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14086                       xmlXPathObjectPtr *resultSeq, int toBool)
14087 {
14088     int max_depth, min_depth;
14089     int from_root;
14090     int ret, depth;
14091     int eval_all_nodes;
14092     xmlNodePtr cur = NULL, limit = NULL;
14093     xmlStreamCtxtPtr patstream = NULL;
14094
14095     int nb_nodes = 0;
14096
14097     if ((ctxt == NULL) || (comp == NULL))
14098         return(-1);
14099     max_depth = xmlPatternMaxDepth(comp);
14100     if (max_depth == -1)
14101         return(-1);
14102     if (max_depth == -2)
14103         max_depth = 10000;
14104     min_depth = xmlPatternMinDepth(comp);
14105     if (min_depth == -1)
14106         return(-1);
14107     from_root = xmlPatternFromRoot(comp);
14108     if (from_root < 0)
14109         return(-1);
14110 #if 0
14111     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14112 #endif
14113
14114     if (! toBool) {
14115         if (resultSeq == NULL)
14116             return(-1);
14117         *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14118         if (*resultSeq == NULL)
14119             return(-1);
14120     }
14121
14122     /*
14123      * handle the special cases of "/" amd "." being matched
14124      */
14125     if (min_depth == 0) {
14126         if (from_root) {
14127             /* Select "/" */
14128             if (toBool)
14129                 return(1);
14130             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14131                 (xmlNodePtr) ctxt->doc);
14132         } else {
14133             /* Select "self::node()" */
14134             if (toBool)
14135                 return(1);
14136             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14137         }
14138     }
14139     if (max_depth == 0) {
14140         return(0);
14141     }
14142
14143     if (from_root) {
14144         cur = (xmlNodePtr)ctxt->doc;
14145     } else if (ctxt->node != NULL) {
14146         switch (ctxt->node->type) {
14147             case XML_ELEMENT_NODE:
14148             case XML_DOCUMENT_NODE:
14149             case XML_DOCUMENT_FRAG_NODE:
14150             case XML_HTML_DOCUMENT_NODE:
14151 #ifdef LIBXML_DOCB_ENABLED
14152             case XML_DOCB_DOCUMENT_NODE:
14153 #endif
14154                 cur = ctxt->node;
14155                 break;
14156             case XML_ATTRIBUTE_NODE:
14157             case XML_TEXT_NODE:
14158             case XML_CDATA_SECTION_NODE:
14159             case XML_ENTITY_REF_NODE:
14160             case XML_ENTITY_NODE:
14161             case XML_PI_NODE:
14162             case XML_COMMENT_NODE:
14163             case XML_NOTATION_NODE:
14164             case XML_DTD_NODE:
14165             case XML_DOCUMENT_TYPE_NODE:
14166             case XML_ELEMENT_DECL:
14167             case XML_ATTRIBUTE_DECL:
14168             case XML_ENTITY_DECL:
14169             case XML_NAMESPACE_DECL:
14170             case XML_XINCLUDE_START:
14171             case XML_XINCLUDE_END:
14172                 break;
14173         }
14174         limit = cur;
14175     }
14176     if (cur == NULL) {
14177         return(0);
14178     }
14179
14180     patstream = xmlPatternGetStreamCtxt(comp);
14181     if (patstream == NULL) {
14182         /*
14183         * QUESTION TODO: Is this an error?
14184         */
14185         return(0);
14186     }
14187
14188     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14189
14190     if (from_root) {
14191         ret = xmlStreamPush(patstream, NULL, NULL);
14192         if (ret < 0) {
14193         } else if (ret == 1) {
14194             if (toBool)
14195                 goto return_1;
14196             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14197         }
14198     }
14199     depth = 0;
14200     goto scan_children;
14201 next_node:
14202     do {
14203         nb_nodes++;
14204
14205         switch (cur->type) {
14206             case XML_ELEMENT_NODE:
14207             case XML_TEXT_NODE:
14208             case XML_CDATA_SECTION_NODE:
14209             case XML_COMMENT_NODE:
14210             case XML_PI_NODE:
14211                 if (cur->type == XML_ELEMENT_NODE) {
14212                     ret = xmlStreamPush(patstream, cur->name,
14213                                 (cur->ns ? cur->ns->href : NULL));
14214                 } else if (eval_all_nodes)
14215                     ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14216                 else
14217                     break;
14218
14219                 if (ret < 0) {
14220                     /* NOP. */
14221                 } else if (ret == 1) {
14222                     if (toBool)
14223                         goto return_1;
14224                     xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14225                 }
14226                 if ((cur->children == NULL) || (depth >= max_depth)) {
14227                     ret = xmlStreamPop(patstream);
14228                     while (cur->next != NULL) {
14229                         cur = cur->next;
14230                         if ((cur->type != XML_ENTITY_DECL) &&
14231                             (cur->type != XML_DTD_NODE))
14232                             goto next_node;
14233                     }
14234                 }
14235             default:
14236                 break;
14237         }
14238
14239 scan_children:
14240         if ((cur->children != NULL) && (depth < max_depth)) {
14241             /*
14242              * Do not descend on entities declarations
14243              */
14244             if (cur->children->type != XML_ENTITY_DECL) {
14245                 cur = cur->children;
14246                 depth++;
14247                 /*
14248                  * Skip DTDs
14249                  */
14250                 if (cur->type != XML_DTD_NODE)
14251                     continue;
14252             }
14253         }
14254
14255         if (cur == limit)
14256             break;
14257
14258         while (cur->next != NULL) {
14259             cur = cur->next;
14260             if ((cur->type != XML_ENTITY_DECL) &&
14261                 (cur->type != XML_DTD_NODE))
14262                 goto next_node;
14263         }
14264
14265         do {
14266             cur = cur->parent;
14267             depth--;
14268             if ((cur == NULL) || (cur == limit))
14269                 goto done;
14270             if (cur->type == XML_ELEMENT_NODE) {
14271                 ret = xmlStreamPop(patstream);
14272             } else if ((eval_all_nodes) &&
14273                 ((cur->type == XML_TEXT_NODE) ||
14274                  (cur->type == XML_CDATA_SECTION_NODE) ||
14275                  (cur->type == XML_COMMENT_NODE) ||
14276                  (cur->type == XML_PI_NODE)))
14277             {
14278                 ret = xmlStreamPop(patstream);
14279             }
14280             if (cur->next != NULL) {
14281                 cur = cur->next;
14282                 break;
14283             }
14284         } while (cur != NULL);
14285
14286     } while ((cur != NULL) && (depth >= 0));
14287
14288 done:
14289
14290 #if 0
14291     printf("stream eval: checked %d nodes selected %d\n",
14292            nb_nodes, retObj->nodesetval->nodeNr);
14293 #endif
14294
14295     if (patstream)
14296         xmlFreeStreamCtxt(patstream);
14297     return(0);
14298
14299 return_1:
14300     if (patstream)
14301         xmlFreeStreamCtxt(patstream);
14302     return(1);
14303 }
14304 #endif /* XPATH_STREAMING */
14305
14306 /**
14307  * xmlXPathRunEval:
14308  * @ctxt:  the XPath parser context with the compiled expression
14309  * @toBool:  evaluate to a boolean result
14310  *
14311  * Evaluate the Precompiled XPath expression in the given context.
14312  */
14313 static int
14314 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14315 {
14316     xmlXPathCompExprPtr comp;
14317
14318     if ((ctxt == NULL) || (ctxt->comp == NULL))
14319         return(-1);
14320
14321     if (ctxt->valueTab == NULL) {
14322         /* Allocate the value stack */
14323         ctxt->valueTab = (xmlXPathObjectPtr *)
14324                          xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14325         if (ctxt->valueTab == NULL) {
14326             xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14327             xmlFree(ctxt);
14328         }
14329         ctxt->valueNr = 0;
14330         ctxt->valueMax = 10;
14331         ctxt->value = NULL;
14332     }
14333 #ifdef XPATH_STREAMING
14334     if (ctxt->comp->stream) {
14335         int res;
14336
14337         if (toBool) {
14338             /*
14339             * Evaluation to boolean result.
14340             */
14341             res = xmlXPathRunStreamEval(ctxt->context,
14342                 ctxt->comp->stream, NULL, 1);
14343             if (res != -1)
14344                 return(res);
14345         } else {
14346             xmlXPathObjectPtr resObj = NULL;
14347
14348             /*
14349             * Evaluation to a sequence.
14350             */
14351             res = xmlXPathRunStreamEval(ctxt->context,
14352                 ctxt->comp->stream, &resObj, 0);
14353
14354             if ((res != -1) && (resObj != NULL)) {
14355                 valuePush(ctxt, resObj);
14356                 return(0);
14357             }
14358             if (resObj != NULL)
14359                 xmlXPathReleaseObject(ctxt->context, resObj);
14360         }
14361         /*
14362         * QUESTION TODO: This falls back to normal XPath evaluation
14363         * if res == -1. Is this intended?
14364         */
14365     }
14366 #endif
14367     comp = ctxt->comp;
14368     if (comp->last < 0) {
14369         xmlGenericError(xmlGenericErrorContext,
14370             "xmlXPathRunEval: last is less than zero\n");
14371         return(-1);
14372     }
14373     if (toBool)
14374         return(xmlXPathCompOpEvalToBoolean(ctxt,
14375             &comp->steps[comp->last], 0));
14376     else
14377         xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14378
14379     return(0);
14380 }
14381
14382 /************************************************************************
14383  *                                                                      *
14384  *                      Public interfaces                               *
14385  *                                                                      *
14386  ************************************************************************/
14387
14388 /**
14389  * xmlXPathEvalPredicate:
14390  * @ctxt:  the XPath context
14391  * @res:  the Predicate Expression evaluation result
14392  *
14393  * Evaluate a predicate result for the current node.
14394  * A PredicateExpr is evaluated by evaluating the Expr and converting
14395  * the result to a boolean. If the result is a number, the result will
14396  * be converted to true if the number is equal to the position of the
14397  * context node in the context node list (as returned by the position
14398  * function) and will be converted to false otherwise; if the result
14399  * is not a number, then the result will be converted as if by a call
14400  * to the boolean function.
14401  *
14402  * Returns 1 if predicate is true, 0 otherwise
14403  */
14404 int
14405 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14406     if ((ctxt == NULL) || (res == NULL)) return(0);
14407     switch (res->type) {
14408         case XPATH_BOOLEAN:
14409             return(res->boolval);
14410         case XPATH_NUMBER:
14411             return(res->floatval == ctxt->proximityPosition);
14412         case XPATH_NODESET:
14413         case XPATH_XSLT_TREE:
14414             if (res->nodesetval == NULL)
14415                 return(0);
14416             return(res->nodesetval->nodeNr != 0);
14417         case XPATH_STRING:
14418             return((res->stringval != NULL) &&
14419                    (xmlStrlen(res->stringval) != 0));
14420         default:
14421             STRANGE
14422     }
14423     return(0);
14424 }
14425
14426 /**
14427  * xmlXPathEvaluatePredicateResult:
14428  * @ctxt:  the XPath Parser context
14429  * @res:  the Predicate Expression evaluation result
14430  *
14431  * Evaluate a predicate result for the current node.
14432  * A PredicateExpr is evaluated by evaluating the Expr and converting
14433  * the result to a boolean. If the result is a number, the result will
14434  * be converted to true if the number is equal to the position of the
14435  * context node in the context node list (as returned by the position
14436  * function) and will be converted to false otherwise; if the result
14437  * is not a number, then the result will be converted as if by a call
14438  * to the boolean function.
14439  *
14440  * Returns 1 if predicate is true, 0 otherwise
14441  */
14442 int
14443 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14444                                 xmlXPathObjectPtr res) {
14445     if ((ctxt == NULL) || (res == NULL)) return(0);
14446     switch (res->type) {
14447         case XPATH_BOOLEAN:
14448             return(res->boolval);
14449         case XPATH_NUMBER:
14450 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14451             return((res->floatval == ctxt->context->proximityPosition) &&
14452                    (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14453 #else
14454             return(res->floatval == ctxt->context->proximityPosition);
14455 #endif
14456         case XPATH_NODESET:
14457         case XPATH_XSLT_TREE:
14458             if (res->nodesetval == NULL)
14459                 return(0);
14460             return(res->nodesetval->nodeNr != 0);
14461         case XPATH_STRING:
14462             return((res->stringval != NULL) && (res->stringval[0] != 0));
14463 #ifdef LIBXML_XPTR_ENABLED
14464         case XPATH_LOCATIONSET:{
14465             xmlLocationSetPtr ptr = res->user;
14466             if (ptr == NULL)
14467                 return(0);
14468             return (ptr->locNr != 0);
14469             }
14470 #endif
14471         default:
14472             STRANGE
14473     }
14474     return(0);
14475 }
14476
14477 #ifdef XPATH_STREAMING
14478 /**
14479  * xmlXPathTryStreamCompile:
14480  * @ctxt: an XPath context
14481  * @str:  the XPath expression
14482  *
14483  * Try to compile the XPath expression as a streamable subset.
14484  *
14485  * Returns the compiled expression or NULL if failed to compile.
14486  */
14487 static xmlXPathCompExprPtr
14488 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14489     /*
14490      * Optimization: use streaming patterns when the XPath expression can
14491      * be compiled to a stream lookup
14492      */
14493     xmlPatternPtr stream;
14494     xmlXPathCompExprPtr comp;
14495     xmlDictPtr dict = NULL;
14496     const xmlChar **namespaces = NULL;
14497     xmlNsPtr ns;
14498     int i, j;
14499
14500     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14501         (!xmlStrchr(str, '@'))) {
14502         const xmlChar *tmp;
14503
14504         /*
14505          * We don't try to handle expressions using the verbose axis
14506          * specifiers ("::"), just the simplied form at this point.
14507          * Additionally, if there is no list of namespaces available and
14508          *  there's a ":" in the expression, indicating a prefixed QName,
14509          *  then we won't try to compile either. xmlPatterncompile() needs
14510          *  to have a list of namespaces at compilation time in order to
14511          *  compile prefixed name tests.
14512          */
14513         tmp = xmlStrchr(str, ':');
14514         if ((tmp != NULL) &&
14515             ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14516             return(NULL);
14517
14518         if (ctxt != NULL) {
14519             dict = ctxt->dict;
14520             if (ctxt->nsNr > 0) {
14521                 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14522                 if (namespaces == NULL) {
14523                     xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14524                     return(NULL);
14525                 }
14526                 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14527                     ns = ctxt->namespaces[j];
14528                     namespaces[i++] = ns->href;
14529                     namespaces[i++] = ns->prefix;
14530                 }
14531                 namespaces[i++] = NULL;
14532                 namespaces[i] = NULL;
14533             }
14534         }
14535
14536         stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14537                         &namespaces[0]);
14538         if (namespaces != NULL) {
14539             xmlFree((xmlChar **)namespaces);
14540         }
14541         if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14542             comp = xmlXPathNewCompExpr();
14543             if (comp == NULL) {
14544                 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14545                 return(NULL);
14546             }
14547             comp->stream = stream;
14548             comp->dict = dict;
14549             if (comp->dict)
14550                 xmlDictReference(comp->dict);
14551             return(comp);
14552         }
14553         xmlFreePattern(stream);
14554     }
14555     return(NULL);
14556 }
14557 #endif /* XPATH_STREAMING */
14558
14559 static int
14560 xmlXPathCanRewriteDosExpression(xmlChar *expr)
14561 {
14562     if (expr == NULL)
14563         return(0);
14564     do {
14565         if ((*expr == '/') && (*(++expr) == '/'))
14566             return(1);
14567     } while (*expr++);
14568     return(0);
14569 }
14570 static void
14571 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14572 {
14573     /*
14574     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14575     * internal representation.
14576     */
14577     if (op->ch1 != -1) {
14578         if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14579             ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14580             ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14581             ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14582         {
14583             /*
14584             * This is a "child::foo"
14585             */
14586             xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14587
14588             if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14589                 (prevop->ch1 != -1) &&
14590                 ((xmlXPathAxisVal) prevop->value ==
14591                     AXIS_DESCENDANT_OR_SELF) &&
14592                 (prevop->ch2 == -1) &&
14593                 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14594                 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14595                 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14596             {
14597                 /*
14598                 * This is a "/descendant-or-self::node()" without predicates.
14599                 * Eliminate it.
14600                 */
14601                 op->ch1 = prevop->ch1;
14602                 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14603             }
14604         }
14605         if (op->ch1 != -1)
14606             xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14607     }
14608     if (op->ch2 != -1)
14609         xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14610 }
14611
14612 /**
14613  * xmlXPathCtxtCompile:
14614  * @ctxt: an XPath context
14615  * @str:  the XPath expression
14616  *
14617  * Compile an XPath expression
14618  *
14619  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14620  *         the caller has to free the object.
14621  */
14622 xmlXPathCompExprPtr
14623 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14624     xmlXPathParserContextPtr pctxt;
14625     xmlXPathCompExprPtr comp;
14626
14627 #ifdef XPATH_STREAMING
14628     comp = xmlXPathTryStreamCompile(ctxt, str);
14629     if (comp != NULL)
14630         return(comp);
14631 #endif
14632
14633     xmlXPathInit();
14634
14635     pctxt = xmlXPathNewParserContext(str, ctxt);
14636     if (pctxt == NULL)
14637         return NULL;
14638     xmlXPathCompileExpr(pctxt, 1);
14639
14640     if( pctxt->error != XPATH_EXPRESSION_OK )
14641     {
14642         xmlXPathFreeParserContext(pctxt);
14643         return(NULL);
14644     }
14645
14646     if (*pctxt->cur != 0) {
14647         /*
14648          * aleksey: in some cases this line prints *second* error message
14649          * (see bug #78858) and probably this should be fixed.
14650          * However, we are not sure that all error messages are printed
14651          * out in other places. It's not critical so we leave it as-is for now
14652          */
14653         xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14654         comp = NULL;
14655     } else {
14656         comp = pctxt->comp;
14657         pctxt->comp = NULL;
14658     }
14659     xmlXPathFreeParserContext(pctxt);
14660
14661     if (comp != NULL) {
14662         comp->expr = xmlStrdup(str);
14663 #ifdef DEBUG_EVAL_COUNTS
14664         comp->string = xmlStrdup(str);
14665         comp->nb = 0;
14666 #endif
14667         if ((comp->expr != NULL) &&
14668             (comp->nbStep > 2) &&
14669             (comp->last >= 0) &&
14670             (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14671         {
14672             xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14673         }
14674     }
14675     return(comp);
14676 }
14677
14678 /**
14679  * xmlXPathCompile:
14680  * @str:  the XPath expression
14681  *
14682  * Compile an XPath expression
14683  *
14684  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14685  *         the caller has to free the object.
14686  */
14687 xmlXPathCompExprPtr
14688 xmlXPathCompile(const xmlChar *str) {
14689     return(xmlXPathCtxtCompile(NULL, str));
14690 }
14691
14692 /**
14693  * xmlXPathCompiledEvalInternal:
14694  * @comp:  the compiled XPath expression
14695  * @ctxt:  the XPath context
14696  * @resObj: the resulting XPath object or NULL
14697  * @toBool: 1 if only a boolean result is requested
14698  *
14699  * Evaluate the Precompiled XPath expression in the given context.
14700  * The caller has to free @resObj.
14701  *
14702  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14703  *         the caller has to free the object.
14704  */
14705 static int
14706 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14707                              xmlXPathContextPtr ctxt,
14708                              xmlXPathObjectPtr *resObj,
14709                              int toBool)
14710 {
14711     xmlXPathParserContextPtr pctxt;
14712 #ifndef LIBXML_THREAD_ENABLED
14713     static int reentance = 0;
14714 #endif
14715     int res;
14716
14717     CHECK_CTXT_NEG(ctxt)
14718
14719     if (comp == NULL)
14720         return(-1);
14721     xmlXPathInit();
14722
14723 #ifndef LIBXML_THREAD_ENABLED
14724     reentance++;
14725     if (reentance > 1)
14726         xmlXPathDisableOptimizer = 1;
14727 #endif
14728
14729 #ifdef DEBUG_EVAL_COUNTS
14730     comp->nb++;
14731     if ((comp->string != NULL) && (comp->nb > 100)) {
14732         fprintf(stderr, "100 x %s\n", comp->string);
14733         comp->nb = 0;
14734     }
14735 #endif
14736     pctxt = xmlXPathCompParserContext(comp, ctxt);
14737     res = xmlXPathRunEval(pctxt, toBool);
14738
14739     if (resObj) {
14740         if (pctxt->value == NULL) {
14741             xmlGenericError(xmlGenericErrorContext,
14742                 "xmlXPathCompiledEval: evaluation failed\n");
14743             *resObj = NULL;
14744         } else {
14745             *resObj = valuePop(pctxt);
14746         }
14747     }
14748
14749     /*
14750     * Pop all remaining objects from the stack.
14751     */
14752     if (pctxt->valueNr > 0) {
14753         xmlXPathObjectPtr tmp;
14754         int stack = 0;
14755
14756         do {
14757             tmp = valuePop(pctxt);
14758             if (tmp != NULL) {
14759                 stack++;
14760                 xmlXPathReleaseObject(ctxt, tmp);
14761             }
14762         } while (tmp != NULL);
14763         if ((stack != 0) &&
14764             ((toBool) || ((resObj) && (*resObj))))
14765         {
14766             xmlGenericError(xmlGenericErrorContext,
14767                 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14768                 stack);
14769         }
14770     }
14771
14772     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14773         xmlXPathFreeObject(*resObj);
14774         *resObj = NULL;
14775     }
14776     pctxt->comp = NULL;
14777     xmlXPathFreeParserContext(pctxt);
14778 #ifndef LIBXML_THREAD_ENABLED
14779     reentance--;
14780 #endif
14781
14782     return(res);
14783 }
14784
14785 /**
14786  * xmlXPathCompiledEval:
14787  * @comp:  the compiled XPath expression
14788  * @ctx:  the XPath context
14789  *
14790  * Evaluate the Precompiled XPath expression in the given context.
14791  *
14792  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14793  *         the caller has to free the object.
14794  */
14795 xmlXPathObjectPtr
14796 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14797 {
14798     xmlXPathObjectPtr res = NULL;
14799
14800     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14801     return(res);
14802 }
14803
14804 /**
14805  * xmlXPathCompiledEvalToBoolean:
14806  * @comp:  the compiled XPath expression
14807  * @ctxt:  the XPath context
14808  *
14809  * Applies the XPath boolean() function on the result of the given
14810  * compiled expression.
14811  *
14812  * Returns 1 if the expression evaluated to true, 0 if to false and
14813  *         -1 in API and internal errors.
14814  */
14815 int
14816 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14817                               xmlXPathContextPtr ctxt)
14818 {
14819     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14820 }
14821
14822 /**
14823  * xmlXPathEvalExpr:
14824  * @ctxt:  the XPath Parser context
14825  *
14826  * Parse and evaluate an XPath expression in the given context,
14827  * then push the result on the context stack
14828  */
14829 void
14830 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14831 #ifdef XPATH_STREAMING
14832     xmlXPathCompExprPtr comp;
14833 #endif
14834
14835     if (ctxt == NULL) return;
14836
14837 #ifdef XPATH_STREAMING
14838     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14839     if (comp != NULL) {
14840         if (ctxt->comp != NULL)
14841             xmlXPathFreeCompExpr(ctxt->comp);
14842         ctxt->comp = comp;
14843         if (ctxt->cur != NULL)
14844             while (*ctxt->cur != 0) ctxt->cur++;
14845     } else
14846 #endif
14847     {
14848         xmlXPathCompileExpr(ctxt, 1);
14849         /*
14850         * In this scenario the expression string will sit in ctxt->base.
14851         */
14852         if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14853             (ctxt->comp != NULL) &&
14854             (ctxt->base != NULL) &&
14855             (ctxt->comp->nbStep > 2) &&
14856             (ctxt->comp->last >= 0) &&
14857             (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14858         {
14859             xmlXPathRewriteDOSExpression(ctxt->comp,
14860                 &ctxt->comp->steps[ctxt->comp->last]);
14861         }
14862     }
14863     CHECK_ERROR;
14864     xmlXPathRunEval(ctxt, 0);
14865 }
14866
14867 /**
14868  * xmlXPathEval:
14869  * @str:  the XPath expression
14870  * @ctx:  the XPath context
14871  *
14872  * Evaluate the XPath Location Path in the given context.
14873  *
14874  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14875  *         the caller has to free the object.
14876  */
14877 xmlXPathObjectPtr
14878 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14879     xmlXPathParserContextPtr ctxt;
14880     xmlXPathObjectPtr res, tmp, init = NULL;
14881     int stack = 0;
14882
14883     CHECK_CTXT(ctx)
14884
14885     xmlXPathInit();
14886
14887     ctxt = xmlXPathNewParserContext(str, ctx);
14888     if (ctxt == NULL)
14889         return NULL;
14890     xmlXPathEvalExpr(ctxt);
14891
14892     if (ctxt->value == NULL) {
14893         xmlGenericError(xmlGenericErrorContext,
14894                 "xmlXPathEval: evaluation failed\n");
14895         res = NULL;
14896     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14897 #ifdef XPATH_STREAMING
14898             && (ctxt->comp->stream == NULL)
14899 #endif
14900               ) {
14901         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14902         res = NULL;
14903     } else {
14904         res = valuePop(ctxt);
14905     }
14906
14907     do {
14908         tmp = valuePop(ctxt);
14909         if (tmp != NULL) {
14910             if (tmp != init)
14911                 stack++;
14912             xmlXPathReleaseObject(ctx, tmp);
14913         }
14914     } while (tmp != NULL);
14915     if ((stack != 0) && (res != NULL)) {
14916         xmlGenericError(xmlGenericErrorContext,
14917                 "xmlXPathEval: %d object left on the stack\n",
14918                 stack);
14919     }
14920     if (ctxt->error != XPATH_EXPRESSION_OK) {
14921         xmlXPathFreeObject(res);
14922         res = NULL;
14923     }
14924
14925     xmlXPathFreeParserContext(ctxt);
14926     return(res);
14927 }
14928
14929 /**
14930  * xmlXPathEvalExpression:
14931  * @str:  the XPath expression
14932  * @ctxt:  the XPath context
14933  *
14934  * Evaluate the XPath expression in the given context.
14935  *
14936  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14937  *         the caller has to free the object.
14938  */
14939 xmlXPathObjectPtr
14940 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14941     xmlXPathParserContextPtr pctxt;
14942     xmlXPathObjectPtr res, tmp;
14943     int stack = 0;
14944
14945     CHECK_CTXT(ctxt)
14946
14947     xmlXPathInit();
14948
14949     pctxt = xmlXPathNewParserContext(str, ctxt);
14950     if (pctxt == NULL)
14951         return NULL;
14952     xmlXPathEvalExpr(pctxt);
14953
14954     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
14955         xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14956         res = NULL;
14957     } else {
14958         res = valuePop(pctxt);
14959     }
14960     do {
14961         tmp = valuePop(pctxt);
14962         if (tmp != NULL) {
14963             xmlXPathReleaseObject(ctxt, tmp);
14964             stack++;
14965         }
14966     } while (tmp != NULL);
14967     if ((stack != 0) && (res != NULL)) {
14968         xmlGenericError(xmlGenericErrorContext,
14969                 "xmlXPathEvalExpression: %d object left on the stack\n",
14970                 stack);
14971     }
14972     xmlXPathFreeParserContext(pctxt);
14973     return(res);
14974 }
14975
14976 /************************************************************************
14977  *                                                                      *
14978  *      Extra functions not pertaining to the XPath spec                *
14979  *                                                                      *
14980  ************************************************************************/
14981 /**
14982  * xmlXPathEscapeUriFunction:
14983  * @ctxt:  the XPath Parser context
14984  * @nargs:  the number of arguments
14985  *
14986  * Implement the escape-uri() XPath function
14987  *    string escape-uri(string $str, bool $escape-reserved)
14988  *
14989  * This function applies the URI escaping rules defined in section 2 of [RFC
14990  * 2396] to the string supplied as $uri-part, which typically represents all
14991  * or part of a URI. The effect of the function is to replace any special
14992  * character in the string by an escape sequence of the form %xx%yy...,
14993  * where xxyy... is the hexadecimal representation of the octets used to
14994  * represent the character in UTF-8.
14995  *
14996  * The set of characters that are escaped depends on the setting of the
14997  * boolean argument $escape-reserved.
14998  *
14999  * If $escape-reserved is true, all characters are escaped other than lower
15000  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15001  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15002  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15003  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15004  * A-F).
15005  *
15006  * If $escape-reserved is false, the behavior differs in that characters
15007  * referred to in [RFC 2396] as reserved characters are not escaped. These
15008  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15009  *
15010  * [RFC 2396] does not define whether escaped URIs should use lower case or
15011  * upper case for hexadecimal digits. To ensure that escaped URIs can be
15012  * compared using string comparison functions, this function must always use
15013  * the upper-case letters A-F.
15014  *
15015  * Generally, $escape-reserved should be set to true when escaping a string
15016  * that is to form a single part of a URI, and to false when escaping an
15017  * entire URI or URI reference.
15018  *
15019  * In the case of non-ascii characters, the string is encoded according to
15020  * utf-8 and then converted according to RFC 2396.
15021  *
15022  * Examples
15023  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15024  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15025  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15026  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15027  *
15028  */
15029 static void
15030 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15031     xmlXPathObjectPtr str;
15032     int escape_reserved;
15033     xmlBufferPtr target;
15034     xmlChar *cptr;
15035     xmlChar escape[4];
15036
15037     CHECK_ARITY(2);
15038
15039     escape_reserved = xmlXPathPopBoolean(ctxt);
15040
15041     CAST_TO_STRING;
15042     str = valuePop(ctxt);
15043
15044     target = xmlBufferCreate();
15045
15046     escape[0] = '%';
15047     escape[3] = 0;
15048
15049     if (target) {
15050         for (cptr = str->stringval; *cptr; cptr++) {
15051             if ((*cptr >= 'A' && *cptr <= 'Z') ||
15052                 (*cptr >= 'a' && *cptr <= 'z') ||
15053                 (*cptr >= '0' && *cptr <= '9') ||
15054                 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15055                 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15056                 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15057                 (*cptr == '%' &&
15058                  ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15059                   (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15060                   (cptr[1] >= '0' && cptr[1] <= '9')) &&
15061                  ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15062                   (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15063                   (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15064                 (!escape_reserved &&
15065                  (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15066                   *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15067                   *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15068                   *cptr == ','))) {
15069                 xmlBufferAdd(target, cptr, 1);
15070             } else {
15071                 if ((*cptr >> 4) < 10)
15072                     escape[1] = '0' + (*cptr >> 4);
15073                 else
15074                     escape[1] = 'A' - 10 + (*cptr >> 4);
15075                 if ((*cptr & 0xF) < 10)
15076                     escape[2] = '0' + (*cptr & 0xF);
15077                 else
15078                     escape[2] = 'A' - 10 + (*cptr & 0xF);
15079
15080                 xmlBufferAdd(target, &escape[0], 3);
15081             }
15082         }
15083     }
15084     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15085         xmlBufferContent(target)));
15086     xmlBufferFree(target);
15087     xmlXPathReleaseObject(ctxt->context, str);
15088 }
15089
15090 /**
15091  * xmlXPathRegisterAllFunctions:
15092  * @ctxt:  the XPath context
15093  *
15094  * Registers all default XPath functions in this context
15095  */
15096 void
15097 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15098 {
15099     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15100                          xmlXPathBooleanFunction);
15101     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15102                          xmlXPathCeilingFunction);
15103     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15104                          xmlXPathCountFunction);
15105     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15106                          xmlXPathConcatFunction);
15107     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15108                          xmlXPathContainsFunction);
15109     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15110                          xmlXPathIdFunction);
15111     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15112                          xmlXPathFalseFunction);
15113     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15114                          xmlXPathFloorFunction);
15115     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15116                          xmlXPathLastFunction);
15117     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15118                          xmlXPathLangFunction);
15119     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15120                          xmlXPathLocalNameFunction);
15121     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15122                          xmlXPathNotFunction);
15123     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15124                          xmlXPathNameFunction);
15125     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15126                          xmlXPathNamespaceURIFunction);
15127     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15128                          xmlXPathNormalizeFunction);
15129     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15130                          xmlXPathNumberFunction);
15131     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15132                          xmlXPathPositionFunction);
15133     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15134                          xmlXPathRoundFunction);
15135     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15136                          xmlXPathStringFunction);
15137     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15138                          xmlXPathStringLengthFunction);
15139     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15140                          xmlXPathStartsWithFunction);
15141     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15142                          xmlXPathSubstringFunction);
15143     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15144                          xmlXPathSubstringBeforeFunction);
15145     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15146                          xmlXPathSubstringAfterFunction);
15147     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15148                          xmlXPathSumFunction);
15149     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15150                          xmlXPathTrueFunction);
15151     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15152                          xmlXPathTranslateFunction);
15153
15154     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15155          (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15156                          xmlXPathEscapeUriFunction);
15157 }
15158
15159 #endif /* LIBXML_XPATH_ENABLED */
15160 #define bottom_xpath
15161 #include "elfgcchack.h"