Imported Upstream version 2.8.0
[platform/upstream/libxml2.git] / xpath.c
1 /*
2  * xpath.c: XML Path Language implementation
3  *          XPath is a language for addressing parts of an XML document,
4  *          designed to be used by both XSLT and XPointer
5  *f
6  * Reference: W3C Recommendation 16 November 1999
7  *     http://www.w3.org/TR/1999/REC-xpath-19991116
8  * Public reference:
9  *     http://www.w3.org/TR/xpath
10  *
11  * See Copyright for the status of this software
12  *
13  * Author: daniel@veillard.com
14  *
15  */
16
17 #define IN_LIBXML
18 #include "libxml.h"
19
20 #include <string.h>
21
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
24 #endif
25 #ifdef HAVE_MATH_H
26 #include <math.h>
27 #endif
28 #ifdef HAVE_FLOAT_H
29 #include <float.h>
30 #endif
31 #ifdef HAVE_CTYPE_H
32 #include <ctype.h>
33 #endif
34 #ifdef HAVE_SIGNAL_H
35 #include <signal.h>
36 #endif
37
38 #include <libxml/xmlmemory.h>
39 #include <libxml/tree.h>
40 #include <libxml/valid.h>
41 #include <libxml/xpath.h>
42 #include <libxml/xpathInternals.h>
43 #include <libxml/parserInternals.h>
44 #include <libxml/hash.h>
45 #ifdef LIBXML_XPTR_ENABLED
46 #include <libxml/xpointer.h>
47 #endif
48 #ifdef LIBXML_DEBUG_ENABLED
49 #include <libxml/debugXML.h>
50 #endif
51 #include <libxml/xmlerror.h>
52 #include <libxml/threads.h>
53 #include <libxml/globals.h>
54 #ifdef LIBXML_PATTERN_ENABLED
55 #include <libxml/pattern.h>
56 #endif
57
58 #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     "Stack usage errror\n",
256     "?? Unknown error ??\n"     /* Must be last in the list! */
257 };
258 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
259                    sizeof(xmlXPathErrorMessages[0])) - 1)
260 /**
261  * xmlXPathErrMemory:
262  * @ctxt:  an XPath context
263  * @extra:  extra informations
264  *
265  * Handle a redefinition of attribute error
266  */
267 static void
268 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
269 {
270     if (ctxt != NULL) {
271         if (extra) {
272             xmlChar buf[200];
273
274             xmlStrPrintf(buf, 200,
275                          BAD_CAST "Memory allocation failed : %s\n",
276                          extra);
277             ctxt->lastError.message = (char *) xmlStrdup(buf);
278         } else {
279             ctxt->lastError.message = (char *)
280                xmlStrdup(BAD_CAST "Memory allocation failed\n");
281         }
282         ctxt->lastError.domain = XML_FROM_XPATH;
283         ctxt->lastError.code = XML_ERR_NO_MEMORY;
284         if (ctxt->error != NULL)
285             ctxt->error(ctxt->userData, &ctxt->lastError);
286     } else {
287         if (extra)
288             __xmlRaiseError(NULL, NULL, NULL,
289                             NULL, NULL, XML_FROM_XPATH,
290                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
291                             extra, NULL, NULL, 0, 0,
292                             "Memory allocation failed : %s\n", extra);
293         else
294             __xmlRaiseError(NULL, NULL, NULL,
295                             NULL, NULL, XML_FROM_XPATH,
296                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
297                             NULL, NULL, NULL, 0, 0,
298                             "Memory allocation failed\n");
299     }
300 }
301
302 /**
303  * xmlXPathPErrMemory:
304  * @ctxt:  an XPath parser context
305  * @extra:  extra informations
306  *
307  * Handle a redefinition of attribute error
308  */
309 static void
310 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
311 {
312     if (ctxt == NULL)
313         xmlXPathErrMemory(NULL, extra);
314     else {
315         ctxt->error = XPATH_MEMORY_ERROR;
316         xmlXPathErrMemory(ctxt->context, extra);
317     }
318 }
319
320 /**
321  * xmlXPathErr:
322  * @ctxt:  a XPath parser context
323  * @error:  the error code
324  *
325  * Handle an XPath error
326  */
327 void
328 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
329 {
330     if ((error < 0) || (error > MAXERRNO))
331         error = MAXERRNO;
332     if (ctxt == NULL) {
333         __xmlRaiseError(NULL, NULL, NULL,
334                         NULL, NULL, XML_FROM_XPATH,
335                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
336                         XML_ERR_ERROR, NULL, 0,
337                         NULL, NULL, NULL, 0, 0,
338                         "%s", xmlXPathErrorMessages[error]);
339         return;
340     }
341     ctxt->error = error;
342     if (ctxt->context == NULL) {
343         __xmlRaiseError(NULL, NULL, NULL,
344                         NULL, NULL, XML_FROM_XPATH,
345                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
346                         XML_ERR_ERROR, NULL, 0,
347                         (const char *) ctxt->base, NULL, NULL,
348                         ctxt->cur - ctxt->base, 0,
349                         "%s", xmlXPathErrorMessages[error]);
350         return;
351     }
352
353     /* cleanup current last error */
354     xmlResetError(&ctxt->context->lastError);
355
356     ctxt->context->lastError.domain = XML_FROM_XPATH;
357     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
358                            XPATH_EXPRESSION_OK;
359     ctxt->context->lastError.level = XML_ERR_ERROR;
360     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
361     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
362     ctxt->context->lastError.node = ctxt->context->debugNode;
363     if (ctxt->context->error != NULL) {
364         ctxt->context->error(ctxt->context->userData,
365                              &ctxt->context->lastError);
366     } else {
367         __xmlRaiseError(NULL, NULL, NULL,
368                         NULL, ctxt->context->debugNode, XML_FROM_XPATH,
369                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
370                         XML_ERR_ERROR, NULL, 0,
371                         (const char *) ctxt->base, NULL, NULL,
372                         ctxt->cur - ctxt->base, 0,
373                         "%s", xmlXPathErrorMessages[error]);
374     }
375
376 }
377
378 /**
379  * xmlXPatherror:
380  * @ctxt:  the XPath Parser context
381  * @file:  the file name
382  * @line:  the line number
383  * @no:  the error number
384  *
385  * Formats an error message.
386  */
387 void
388 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
389               int line ATTRIBUTE_UNUSED, int no) {
390     xmlXPathErr(ctxt, no);
391 }
392
393 /************************************************************************
394  *                                                                      *
395  *                      Utilities                                       *
396  *                                                                      *
397  ************************************************************************/
398
399 /**
400  * xsltPointerList:
401  *
402  * Pointer-list for various purposes.
403  */
404 typedef struct _xmlPointerList xmlPointerList;
405 typedef xmlPointerList *xmlPointerListPtr;
406 struct _xmlPointerList {
407     void **items;
408     int number;
409     int size;
410 };
411 /*
412 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
413 * and here, we should make the functions public.
414 */
415 static int
416 xmlPointerListAddSize(xmlPointerListPtr list,
417                        void *item,
418                        int initialSize)
419 {
420     if (list->items == NULL) {
421         if (initialSize <= 0)
422             initialSize = 1;
423         list->items = (void **) xmlMalloc(
424             initialSize * sizeof(void *));
425         if (list->items == NULL) {
426             xmlXPathErrMemory(NULL,
427                 "xmlPointerListCreate: allocating item\n");
428             return(-1);
429         }
430         list->number = 0;
431         list->size = initialSize;
432     } else if (list->size <= list->number) {
433         list->size *= 2;
434         list->items = (void **) xmlRealloc(list->items,
435             list->size * sizeof(void *));
436         if (list->items == NULL) {
437             xmlXPathErrMemory(NULL,
438                 "xmlPointerListCreate: re-allocating item\n");
439             list->size = 0;
440             return(-1);
441         }
442     }
443     list->items[list->number++] = item;
444     return(0);
445 }
446
447 /**
448  * xsltPointerListCreate:
449  *
450  * Creates an xsltPointerList structure.
451  *
452  * Returns a xsltPointerList structure or NULL in case of an error.
453  */
454 static xmlPointerListPtr
455 xmlPointerListCreate(int initialSize)
456 {
457     xmlPointerListPtr ret;
458
459     ret = xmlMalloc(sizeof(xmlPointerList));
460     if (ret == NULL) {
461         xmlXPathErrMemory(NULL,
462             "xmlPointerListCreate: allocating item\n");
463         return (NULL);
464     }
465     memset(ret, 0, sizeof(xmlPointerList));
466     if (initialSize > 0) {
467         xmlPointerListAddSize(ret, NULL, initialSize);
468         ret->number = 0;
469     }
470     return (ret);
471 }
472
473 /**
474  * xsltPointerListFree:
475  *
476  * Frees the xsltPointerList structure. This does not free
477  * the content of the list.
478  */
479 static void
480 xmlPointerListFree(xmlPointerListPtr list)
481 {
482     if (list == NULL)
483         return;
484     if (list->items != NULL)
485         xmlFree(list->items);
486     xmlFree(list);
487 }
488
489 /************************************************************************
490  *                                                                      *
491  *                      Parser Types                                    *
492  *                                                                      *
493  ************************************************************************/
494
495 /*
496  * Types are private:
497  */
498
499 typedef enum {
500     XPATH_OP_END=0,
501     XPATH_OP_AND,
502     XPATH_OP_OR,
503     XPATH_OP_EQUAL,
504     XPATH_OP_CMP,
505     XPATH_OP_PLUS,
506     XPATH_OP_MULT,
507     XPATH_OP_UNION,
508     XPATH_OP_ROOT,
509     XPATH_OP_NODE,
510     XPATH_OP_RESET, /* 10 */
511     XPATH_OP_COLLECT,
512     XPATH_OP_VALUE, /* 12 */
513     XPATH_OP_VARIABLE,
514     XPATH_OP_FUNCTION,
515     XPATH_OP_ARG,
516     XPATH_OP_PREDICATE,
517     XPATH_OP_FILTER, /* 17 */
518     XPATH_OP_SORT /* 18 */
519 #ifdef LIBXML_XPTR_ENABLED
520     ,XPATH_OP_RANGETO
521 #endif
522 } xmlXPathOp;
523
524 typedef enum {
525     AXIS_ANCESTOR = 1,
526     AXIS_ANCESTOR_OR_SELF,
527     AXIS_ATTRIBUTE,
528     AXIS_CHILD,
529     AXIS_DESCENDANT,
530     AXIS_DESCENDANT_OR_SELF,
531     AXIS_FOLLOWING,
532     AXIS_FOLLOWING_SIBLING,
533     AXIS_NAMESPACE,
534     AXIS_PARENT,
535     AXIS_PRECEDING,
536     AXIS_PRECEDING_SIBLING,
537     AXIS_SELF
538 } xmlXPathAxisVal;
539
540 typedef enum {
541     NODE_TEST_NONE = 0,
542     NODE_TEST_TYPE = 1,
543     NODE_TEST_PI = 2,
544     NODE_TEST_ALL = 3,
545     NODE_TEST_NS = 4,
546     NODE_TEST_NAME = 5
547 } xmlXPathTestVal;
548
549 typedef enum {
550     NODE_TYPE_NODE = 0,
551     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
552     NODE_TYPE_TEXT = XML_TEXT_NODE,
553     NODE_TYPE_PI = XML_PI_NODE
554 } xmlXPathTypeVal;
555
556 #define XP_REWRITE_DOS_CHILD_ELEM 1
557
558 typedef struct _xmlXPathStepOp xmlXPathStepOp;
559 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
560 struct _xmlXPathStepOp {
561     xmlXPathOp op;              /* The identifier of the operation */
562     int ch1;                    /* First child */
563     int ch2;                    /* Second child */
564     int value;
565     int value2;
566     int value3;
567     void *value4;
568     void *value5;
569     void *cache;
570     void *cacheURI;
571     int rewriteType;
572 };
573
574 struct _xmlXPathCompExpr {
575     int nbStep;                 /* Number of steps in this expression */
576     int maxStep;                /* Maximum number of steps allocated */
577     xmlXPathStepOp *steps;      /* ops for computation of this expression */
578     int last;                   /* index of last step in expression */
579     xmlChar *expr;              /* the expression being computed */
580     xmlDictPtr dict;            /* the dictionnary to use if any */
581 #ifdef DEBUG_EVAL_COUNTS
582     int nb;
583     xmlChar *string;
584 #endif
585 #ifdef XPATH_STREAMING
586     xmlPatternPtr stream;
587 #endif
588 };
589
590 /************************************************************************
591  *                                                                      *
592  *                      Forward declarations                            *
593  *                                                                      *
594  ************************************************************************/
595 static void
596 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
597 static void
598 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
599 static int
600 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
601                         xmlXPathStepOpPtr op, xmlNodePtr *first);
602 static int
603 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
604                             xmlXPathStepOpPtr op,
605                             int isPredicate);
606
607 /************************************************************************
608  *                                                                      *
609  *                      Parser Type functions                           *
610  *                                                                      *
611  ************************************************************************/
612
613 /**
614  * xmlXPathNewCompExpr:
615  *
616  * Create a new Xpath component
617  *
618  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
619  */
620 static xmlXPathCompExprPtr
621 xmlXPathNewCompExpr(void) {
622     xmlXPathCompExprPtr cur;
623
624     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
625     if (cur == NULL) {
626         xmlXPathErrMemory(NULL, "allocating component\n");
627         return(NULL);
628     }
629     memset(cur, 0, sizeof(xmlXPathCompExpr));
630     cur->maxStep = 10;
631     cur->nbStep = 0;
632     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
633                                            sizeof(xmlXPathStepOp));
634     if (cur->steps == NULL) {
635         xmlXPathErrMemory(NULL, "allocating steps\n");
636         xmlFree(cur);
637         return(NULL);
638     }
639     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
640     cur->last = -1;
641 #ifdef DEBUG_EVAL_COUNTS
642     cur->nb = 0;
643 #endif
644     return(cur);
645 }
646
647 /**
648  * xmlXPathFreeCompExpr:
649  * @comp:  an XPATH comp
650  *
651  * Free up the memory allocated by @comp
652  */
653 void
654 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
655 {
656     xmlXPathStepOpPtr op;
657     int i;
658
659     if (comp == NULL)
660         return;
661     if (comp->dict == NULL) {
662         for (i = 0; i < comp->nbStep; i++) {
663             op = &comp->steps[i];
664             if (op->value4 != NULL) {
665                 if (op->op == XPATH_OP_VALUE)
666                     xmlXPathFreeObject(op->value4);
667                 else
668                     xmlFree(op->value4);
669             }
670             if (op->value5 != NULL)
671                 xmlFree(op->value5);
672         }
673     } else {
674         for (i = 0; i < comp->nbStep; i++) {
675             op = &comp->steps[i];
676             if (op->value4 != NULL) {
677                 if (op->op == XPATH_OP_VALUE)
678                     xmlXPathFreeObject(op->value4);
679             }
680         }
681         xmlDictFree(comp->dict);
682     }
683     if (comp->steps != NULL) {
684         xmlFree(comp->steps);
685     }
686 #ifdef DEBUG_EVAL_COUNTS
687     if (comp->string != NULL) {
688         xmlFree(comp->string);
689     }
690 #endif
691 #ifdef XPATH_STREAMING
692     if (comp->stream != NULL) {
693         xmlFreePatternList(comp->stream);
694     }
695 #endif
696     if (comp->expr != NULL) {
697         xmlFree(comp->expr);
698     }
699
700     xmlFree(comp);
701 }
702
703 /**
704  * xmlXPathCompExprAdd:
705  * @comp:  the compiled expression
706  * @ch1: first child index
707  * @ch2: second child index
708  * @op:  an op
709  * @value:  the first int value
710  * @value2:  the second int value
711  * @value3:  the third int value
712  * @value4:  the first string value
713  * @value5:  the second string value
714  *
715  * Add a step to an XPath Compiled Expression
716  *
717  * Returns -1 in case of failure, the index otherwise
718  */
719 static int
720 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
721    xmlXPathOp op, int value,
722    int value2, int value3, void *value4, void *value5) {
723     if (comp->nbStep >= comp->maxStep) {
724         xmlXPathStepOp *real;
725
726         comp->maxStep *= 2;
727         real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
728                                       comp->maxStep * sizeof(xmlXPathStepOp));
729         if (real == NULL) {
730             comp->maxStep /= 2;
731             xmlXPathErrMemory(NULL, "adding step\n");
732             return(-1);
733         }
734         comp->steps = real;
735     }
736     comp->last = comp->nbStep;
737     comp->steps[comp->nbStep].rewriteType = 0;
738     comp->steps[comp->nbStep].ch1 = ch1;
739     comp->steps[comp->nbStep].ch2 = ch2;
740     comp->steps[comp->nbStep].op = op;
741     comp->steps[comp->nbStep].value = value;
742     comp->steps[comp->nbStep].value2 = value2;
743     comp->steps[comp->nbStep].value3 = value3;
744     if ((comp->dict != NULL) &&
745         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
746          (op == XPATH_OP_COLLECT))) {
747         if (value4 != NULL) {
748             comp->steps[comp->nbStep].value4 = (xmlChar *)
749                 (void *)xmlDictLookup(comp->dict, value4, -1);
750             xmlFree(value4);
751         } else
752             comp->steps[comp->nbStep].value4 = NULL;
753         if (value5 != NULL) {
754             comp->steps[comp->nbStep].value5 = (xmlChar *)
755                 (void *)xmlDictLookup(comp->dict, value5, -1);
756             xmlFree(value5);
757         } else
758             comp->steps[comp->nbStep].value5 = NULL;
759     } else {
760         comp->steps[comp->nbStep].value4 = value4;
761         comp->steps[comp->nbStep].value5 = value5;
762     }
763     comp->steps[comp->nbStep].cache = NULL;
764     return(comp->nbStep++);
765 }
766
767 /**
768  * xmlXPathCompSwap:
769  * @comp:  the compiled expression
770  * @op: operation index
771  *
772  * Swaps 2 operations in the compiled expression
773  */
774 static void
775 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
776     int tmp;
777
778 #ifndef LIBXML_THREAD_ENABLED
779     /*
780      * Since this manipulates possibly shared variables, this is
781      * disabled if one detects that the library is used in a multithreaded
782      * application
783      */
784     if (xmlXPathDisableOptimizer)
785         return;
786 #endif
787
788     tmp = op->ch1;
789     op->ch1 = op->ch2;
790     op->ch2 = tmp;
791 }
792
793 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)       \
794     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),                       \
795                         (op), (val), (val2), (val3), (val4), (val5))
796 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)                 \
797     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,               \
798                         (op), (val), (val2), (val3), (val4), (val5))
799
800 #define PUSH_LEAVE_EXPR(op, val, val2)                                  \
801 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
802
803 #define PUSH_UNARY_EXPR(op, ch, val, val2)                              \
804 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
805
806 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)                       \
807 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),                     \
808                         (val), (val2), 0 ,NULL ,NULL)
809
810 /************************************************************************
811  *                                                                      *
812  *              XPath object cache structures                           *
813  *                                                                      *
814  ************************************************************************/
815
816 /* #define XP_DEFAULT_CACHE_ON */
817
818 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
819
820 typedef struct _xmlXPathContextCache xmlXPathContextCache;
821 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
822 struct _xmlXPathContextCache {
823     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
824     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
825     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
826     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
827     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
828     int maxNodeset;
829     int maxString;
830     int maxBoolean;
831     int maxNumber;
832     int maxMisc;
833 #ifdef XP_DEBUG_OBJ_USAGE
834     int dbgCachedAll;
835     int dbgCachedNodeset;
836     int dbgCachedString;
837     int dbgCachedBool;
838     int dbgCachedNumber;
839     int dbgCachedPoint;
840     int dbgCachedRange;
841     int dbgCachedLocset;
842     int dbgCachedUsers;
843     int dbgCachedXSLTTree;
844     int dbgCachedUndefined;
845
846
847     int dbgReusedAll;
848     int dbgReusedNodeset;
849     int dbgReusedString;
850     int dbgReusedBool;
851     int dbgReusedNumber;
852     int dbgReusedPoint;
853     int dbgReusedRange;
854     int dbgReusedLocset;
855     int dbgReusedUsers;
856     int dbgReusedXSLTTree;
857     int dbgReusedUndefined;
858
859 #endif
860 };
861
862 /************************************************************************
863  *                                                                      *
864  *              Debugging related functions                             *
865  *                                                                      *
866  ************************************************************************/
867
868 #define STRANGE                                                 \
869     xmlGenericError(xmlGenericErrorContext,                             \
870             "Internal error at %s:%d\n",                                \
871             __FILE__, __LINE__);
872
873 #ifdef LIBXML_DEBUG_ENABLED
874 static void
875 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
876     int i;
877     char shift[100];
878
879     for (i = 0;((i < depth) && (i < 25));i++)
880         shift[2 * i] = shift[2 * i + 1] = ' ';
881     shift[2 * i] = shift[2 * i + 1] = 0;
882     if (cur == NULL) {
883         fprintf(output, "%s", shift);
884         fprintf(output, "Node is NULL !\n");
885         return;
886
887     }
888
889     if ((cur->type == XML_DOCUMENT_NODE) ||
890              (cur->type == XML_HTML_DOCUMENT_NODE)) {
891         fprintf(output, "%s", shift);
892         fprintf(output, " /\n");
893     } else if (cur->type == XML_ATTRIBUTE_NODE)
894         xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
895     else
896         xmlDebugDumpOneNode(output, cur, depth);
897 }
898 static void
899 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
900     xmlNodePtr tmp;
901     int i;
902     char shift[100];
903
904     for (i = 0;((i < depth) && (i < 25));i++)
905         shift[2 * i] = shift[2 * i + 1] = ' ';
906     shift[2 * i] = shift[2 * i + 1] = 0;
907     if (cur == NULL) {
908         fprintf(output, "%s", shift);
909         fprintf(output, "Node is NULL !\n");
910         return;
911
912     }
913
914     while (cur != NULL) {
915         tmp = cur;
916         cur = cur->next;
917         xmlDebugDumpOneNode(output, tmp, depth);
918     }
919 }
920
921 static void
922 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
923     int i;
924     char shift[100];
925
926     for (i = 0;((i < depth) && (i < 25));i++)
927         shift[2 * i] = shift[2 * i + 1] = ' ';
928     shift[2 * i] = shift[2 * i + 1] = 0;
929
930     if (cur == NULL) {
931         fprintf(output, "%s", shift);
932         fprintf(output, "NodeSet is NULL !\n");
933         return;
934
935     }
936
937     if (cur != NULL) {
938         fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
939         for (i = 0;i < cur->nodeNr;i++) {
940             fprintf(output, "%s", shift);
941             fprintf(output, "%d", i + 1);
942             xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
943         }
944     }
945 }
946
947 static void
948 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
949     int i;
950     char shift[100];
951
952     for (i = 0;((i < depth) && (i < 25));i++)
953         shift[2 * i] = shift[2 * i + 1] = ' ';
954     shift[2 * i] = shift[2 * i + 1] = 0;
955
956     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
957         fprintf(output, "%s", shift);
958         fprintf(output, "Value Tree is NULL !\n");
959         return;
960
961     }
962
963     fprintf(output, "%s", shift);
964     fprintf(output, "%d", i + 1);
965     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
966 }
967 #if defined(LIBXML_XPTR_ENABLED)
968 static void
969 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
970     int i;
971     char shift[100];
972
973     for (i = 0;((i < depth) && (i < 25));i++)
974         shift[2 * i] = shift[2 * i + 1] = ' ';
975     shift[2 * i] = shift[2 * i + 1] = 0;
976
977     if (cur == NULL) {
978         fprintf(output, "%s", shift);
979         fprintf(output, "LocationSet is NULL !\n");
980         return;
981
982     }
983
984     for (i = 0;i < cur->locNr;i++) {
985         fprintf(output, "%s", shift);
986         fprintf(output, "%d : ", i + 1);
987         xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
988     }
989 }
990 #endif /* LIBXML_XPTR_ENABLED */
991
992 /**
993  * xmlXPathDebugDumpObject:
994  * @output:  the FILE * to dump the output
995  * @cur:  the object to inspect
996  * @depth:  indentation level
997  *
998  * Dump the content of the object for debugging purposes
999  */
1000 void
1001 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1002     int i;
1003     char shift[100];
1004
1005     if (output == NULL) return;
1006
1007     for (i = 0;((i < depth) && (i < 25));i++)
1008         shift[2 * i] = shift[2 * i + 1] = ' ';
1009     shift[2 * i] = shift[2 * i + 1] = 0;
1010
1011
1012     fprintf(output, "%s", shift);
1013
1014     if (cur == NULL) {
1015         fprintf(output, "Object is empty (NULL)\n");
1016         return;
1017     }
1018     switch(cur->type) {
1019         case XPATH_UNDEFINED:
1020             fprintf(output, "Object is uninitialized\n");
1021             break;
1022         case XPATH_NODESET:
1023             fprintf(output, "Object is a Node Set :\n");
1024             xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1025             break;
1026         case XPATH_XSLT_TREE:
1027             fprintf(output, "Object is an XSLT value tree :\n");
1028             xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1029             break;
1030         case XPATH_BOOLEAN:
1031             fprintf(output, "Object is a Boolean : ");
1032             if (cur->boolval) fprintf(output, "true\n");
1033             else fprintf(output, "false\n");
1034             break;
1035         case XPATH_NUMBER:
1036             switch (xmlXPathIsInf(cur->floatval)) {
1037             case 1:
1038                 fprintf(output, "Object is a number : Infinity\n");
1039                 break;
1040             case -1:
1041                 fprintf(output, "Object is a number : -Infinity\n");
1042                 break;
1043             default:
1044                 if (xmlXPathIsNaN(cur->floatval)) {
1045                     fprintf(output, "Object is a number : NaN\n");
1046                 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1047                     fprintf(output, "Object is a number : 0\n");
1048                 } else {
1049                     fprintf(output, "Object is a number : %0g\n", cur->floatval);
1050                 }
1051             }
1052             break;
1053         case XPATH_STRING:
1054             fprintf(output, "Object is a string : ");
1055             xmlDebugDumpString(output, cur->stringval);
1056             fprintf(output, "\n");
1057             break;
1058         case XPATH_POINT:
1059             fprintf(output, "Object is a point : index %d in node", cur->index);
1060             xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1061             fprintf(output, "\n");
1062             break;
1063         case XPATH_RANGE:
1064             if ((cur->user2 == NULL) ||
1065                 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1066                 fprintf(output, "Object is a collapsed range :\n");
1067                 fprintf(output, "%s", shift);
1068                 if (cur->index >= 0)
1069                     fprintf(output, "index %d in ", cur->index);
1070                 fprintf(output, "node\n");
1071                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1072                                       depth + 1);
1073             } else  {
1074                 fprintf(output, "Object is a range :\n");
1075                 fprintf(output, "%s", shift);
1076                 fprintf(output, "From ");
1077                 if (cur->index >= 0)
1078                     fprintf(output, "index %d in ", cur->index);
1079                 fprintf(output, "node\n");
1080                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1081                                       depth + 1);
1082                 fprintf(output, "%s", shift);
1083                 fprintf(output, "To ");
1084                 if (cur->index2 >= 0)
1085                     fprintf(output, "index %d in ", cur->index2);
1086                 fprintf(output, "node\n");
1087                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1088                                       depth + 1);
1089                 fprintf(output, "\n");
1090             }
1091             break;
1092         case XPATH_LOCATIONSET:
1093 #if defined(LIBXML_XPTR_ENABLED)
1094             fprintf(output, "Object is a Location Set:\n");
1095             xmlXPathDebugDumpLocationSet(output,
1096                     (xmlLocationSetPtr) cur->user, depth);
1097 #endif
1098             break;
1099         case XPATH_USERS:
1100             fprintf(output, "Object is user defined\n");
1101             break;
1102     }
1103 }
1104
1105 static void
1106 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1107                              xmlXPathStepOpPtr op, int depth) {
1108     int i;
1109     char shift[100];
1110
1111     for (i = 0;((i < depth) && (i < 25));i++)
1112         shift[2 * i] = shift[2 * i + 1] = ' ';
1113     shift[2 * i] = shift[2 * i + 1] = 0;
1114
1115     fprintf(output, "%s", shift);
1116     if (op == NULL) {
1117         fprintf(output, "Step is NULL\n");
1118         return;
1119     }
1120     switch (op->op) {
1121         case XPATH_OP_END:
1122             fprintf(output, "END"); break;
1123         case XPATH_OP_AND:
1124             fprintf(output, "AND"); break;
1125         case XPATH_OP_OR:
1126             fprintf(output, "OR"); break;
1127         case XPATH_OP_EQUAL:
1128              if (op->value)
1129                  fprintf(output, "EQUAL =");
1130              else
1131                  fprintf(output, "EQUAL !=");
1132              break;
1133         case XPATH_OP_CMP:
1134              if (op->value)
1135                  fprintf(output, "CMP <");
1136              else
1137                  fprintf(output, "CMP >");
1138              if (!op->value2)
1139                  fprintf(output, "=");
1140              break;
1141         case XPATH_OP_PLUS:
1142              if (op->value == 0)
1143                  fprintf(output, "PLUS -");
1144              else if (op->value == 1)
1145                  fprintf(output, "PLUS +");
1146              else if (op->value == 2)
1147                  fprintf(output, "PLUS unary -");
1148              else if (op->value == 3)
1149                  fprintf(output, "PLUS unary - -");
1150              break;
1151         case XPATH_OP_MULT:
1152              if (op->value == 0)
1153                  fprintf(output, "MULT *");
1154              else if (op->value == 1)
1155                  fprintf(output, "MULT div");
1156              else
1157                  fprintf(output, "MULT mod");
1158              break;
1159         case XPATH_OP_UNION:
1160              fprintf(output, "UNION"); break;
1161         case XPATH_OP_ROOT:
1162              fprintf(output, "ROOT"); break;
1163         case XPATH_OP_NODE:
1164              fprintf(output, "NODE"); break;
1165         case XPATH_OP_RESET:
1166              fprintf(output, "RESET"); break;
1167         case XPATH_OP_SORT:
1168              fprintf(output, "SORT"); break;
1169         case XPATH_OP_COLLECT: {
1170             xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1171             xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1172             xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1173             const xmlChar *prefix = op->value4;
1174             const xmlChar *name = op->value5;
1175
1176             fprintf(output, "COLLECT ");
1177             switch (axis) {
1178                 case AXIS_ANCESTOR:
1179                     fprintf(output, " 'ancestors' "); break;
1180                 case AXIS_ANCESTOR_OR_SELF:
1181                     fprintf(output, " 'ancestors-or-self' "); break;
1182                 case AXIS_ATTRIBUTE:
1183                     fprintf(output, " 'attributes' "); break;
1184                 case AXIS_CHILD:
1185                     fprintf(output, " 'child' "); break;
1186                 case AXIS_DESCENDANT:
1187                     fprintf(output, " 'descendant' "); break;
1188                 case AXIS_DESCENDANT_OR_SELF:
1189                     fprintf(output, " 'descendant-or-self' "); break;
1190                 case AXIS_FOLLOWING:
1191                     fprintf(output, " 'following' "); break;
1192                 case AXIS_FOLLOWING_SIBLING:
1193                     fprintf(output, " 'following-siblings' "); break;
1194                 case AXIS_NAMESPACE:
1195                     fprintf(output, " 'namespace' "); break;
1196                 case AXIS_PARENT:
1197                     fprintf(output, " 'parent' "); break;
1198                 case AXIS_PRECEDING:
1199                     fprintf(output, " 'preceding' "); break;
1200                 case AXIS_PRECEDING_SIBLING:
1201                     fprintf(output, " 'preceding-sibling' "); break;
1202                 case AXIS_SELF:
1203                     fprintf(output, " 'self' "); break;
1204             }
1205             switch (test) {
1206                 case NODE_TEST_NONE:
1207                     fprintf(output, "'none' "); break;
1208                 case NODE_TEST_TYPE:
1209                     fprintf(output, "'type' "); break;
1210                 case NODE_TEST_PI:
1211                     fprintf(output, "'PI' "); break;
1212                 case NODE_TEST_ALL:
1213                     fprintf(output, "'all' "); break;
1214                 case NODE_TEST_NS:
1215                     fprintf(output, "'namespace' "); break;
1216                 case NODE_TEST_NAME:
1217                     fprintf(output, "'name' "); break;
1218             }
1219             switch (type) {
1220                 case NODE_TYPE_NODE:
1221                     fprintf(output, "'node' "); break;
1222                 case NODE_TYPE_COMMENT:
1223                     fprintf(output, "'comment' "); break;
1224                 case NODE_TYPE_TEXT:
1225                     fprintf(output, "'text' "); break;
1226                 case NODE_TYPE_PI:
1227                     fprintf(output, "'PI' "); break;
1228             }
1229             if (prefix != NULL)
1230                 fprintf(output, "%s:", prefix);
1231             if (name != NULL)
1232                 fprintf(output, "%s", (const char *) name);
1233             break;
1234
1235         }
1236         case XPATH_OP_VALUE: {
1237             xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1238
1239             fprintf(output, "ELEM ");
1240             xmlXPathDebugDumpObject(output, object, 0);
1241             goto finish;
1242         }
1243         case XPATH_OP_VARIABLE: {
1244             const xmlChar *prefix = op->value5;
1245             const xmlChar *name = op->value4;
1246
1247             if (prefix != NULL)
1248                 fprintf(output, "VARIABLE %s:%s", prefix, name);
1249             else
1250                 fprintf(output, "VARIABLE %s", name);
1251             break;
1252         }
1253         case XPATH_OP_FUNCTION: {
1254             int nbargs = op->value;
1255             const xmlChar *prefix = op->value5;
1256             const xmlChar *name = op->value4;
1257
1258             if (prefix != NULL)
1259                 fprintf(output, "FUNCTION %s:%s(%d args)",
1260                         prefix, name, nbargs);
1261             else
1262                 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1263             break;
1264         }
1265         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1266         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1267         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1268 #ifdef LIBXML_XPTR_ENABLED
1269         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1270 #endif
1271         default:
1272         fprintf(output, "UNKNOWN %d\n", op->op); return;
1273     }
1274     fprintf(output, "\n");
1275 finish:
1276     if (op->ch1 >= 0)
1277         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1278     if (op->ch2 >= 0)
1279         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1280 }
1281
1282 /**
1283  * xmlXPathDebugDumpCompExpr:
1284  * @output:  the FILE * for the output
1285  * @comp:  the precompiled XPath expression
1286  * @depth:  the indentation level.
1287  *
1288  * Dumps the tree of the compiled XPath expression.
1289  */
1290 void
1291 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1292                           int depth) {
1293     int i;
1294     char shift[100];
1295
1296     if ((output == NULL) || (comp == NULL)) return;
1297
1298     for (i = 0;((i < depth) && (i < 25));i++)
1299         shift[2 * i] = shift[2 * i + 1] = ' ';
1300     shift[2 * i] = shift[2 * i + 1] = 0;
1301
1302     fprintf(output, "%s", shift);
1303
1304     fprintf(output, "Compiled Expression : %d elements\n",
1305             comp->nbStep);
1306     i = comp->last;
1307     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1308 }
1309
1310 #ifdef XP_DEBUG_OBJ_USAGE
1311
1312 /*
1313 * XPath object usage related debugging variables.
1314 */
1315 static int xmlXPathDebugObjCounterUndefined = 0;
1316 static int xmlXPathDebugObjCounterNodeset = 0;
1317 static int xmlXPathDebugObjCounterBool = 0;
1318 static int xmlXPathDebugObjCounterNumber = 0;
1319 static int xmlXPathDebugObjCounterString = 0;
1320 static int xmlXPathDebugObjCounterPoint = 0;
1321 static int xmlXPathDebugObjCounterRange = 0;
1322 static int xmlXPathDebugObjCounterLocset = 0;
1323 static int xmlXPathDebugObjCounterUsers = 0;
1324 static int xmlXPathDebugObjCounterXSLTTree = 0;
1325 static int xmlXPathDebugObjCounterAll = 0;
1326
1327 static int xmlXPathDebugObjTotalUndefined = 0;
1328 static int xmlXPathDebugObjTotalNodeset = 0;
1329 static int xmlXPathDebugObjTotalBool = 0;
1330 static int xmlXPathDebugObjTotalNumber = 0;
1331 static int xmlXPathDebugObjTotalString = 0;
1332 static int xmlXPathDebugObjTotalPoint = 0;
1333 static int xmlXPathDebugObjTotalRange = 0;
1334 static int xmlXPathDebugObjTotalLocset = 0;
1335 static int xmlXPathDebugObjTotalUsers = 0;
1336 static int xmlXPathDebugObjTotalXSLTTree = 0;
1337 static int xmlXPathDebugObjTotalAll = 0;
1338
1339 static int xmlXPathDebugObjMaxUndefined = 0;
1340 static int xmlXPathDebugObjMaxNodeset = 0;
1341 static int xmlXPathDebugObjMaxBool = 0;
1342 static int xmlXPathDebugObjMaxNumber = 0;
1343 static int xmlXPathDebugObjMaxString = 0;
1344 static int xmlXPathDebugObjMaxPoint = 0;
1345 static int xmlXPathDebugObjMaxRange = 0;
1346 static int xmlXPathDebugObjMaxLocset = 0;
1347 static int xmlXPathDebugObjMaxUsers = 0;
1348 static int xmlXPathDebugObjMaxXSLTTree = 0;
1349 static int xmlXPathDebugObjMaxAll = 0;
1350
1351 /* REVISIT TODO: Make this static when committing */
1352 static void
1353 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1354 {
1355     if (ctxt != NULL) {
1356         if (ctxt->cache != NULL) {
1357             xmlXPathContextCachePtr cache =
1358                 (xmlXPathContextCachePtr) ctxt->cache;
1359
1360             cache->dbgCachedAll = 0;
1361             cache->dbgCachedNodeset = 0;
1362             cache->dbgCachedString = 0;
1363             cache->dbgCachedBool = 0;
1364             cache->dbgCachedNumber = 0;
1365             cache->dbgCachedPoint = 0;
1366             cache->dbgCachedRange = 0;
1367             cache->dbgCachedLocset = 0;
1368             cache->dbgCachedUsers = 0;
1369             cache->dbgCachedXSLTTree = 0;
1370             cache->dbgCachedUndefined = 0;
1371
1372             cache->dbgReusedAll = 0;
1373             cache->dbgReusedNodeset = 0;
1374             cache->dbgReusedString = 0;
1375             cache->dbgReusedBool = 0;
1376             cache->dbgReusedNumber = 0;
1377             cache->dbgReusedPoint = 0;
1378             cache->dbgReusedRange = 0;
1379             cache->dbgReusedLocset = 0;
1380             cache->dbgReusedUsers = 0;
1381             cache->dbgReusedXSLTTree = 0;
1382             cache->dbgReusedUndefined = 0;
1383         }
1384     }
1385
1386     xmlXPathDebugObjCounterUndefined = 0;
1387     xmlXPathDebugObjCounterNodeset = 0;
1388     xmlXPathDebugObjCounterBool = 0;
1389     xmlXPathDebugObjCounterNumber = 0;
1390     xmlXPathDebugObjCounterString = 0;
1391     xmlXPathDebugObjCounterPoint = 0;
1392     xmlXPathDebugObjCounterRange = 0;
1393     xmlXPathDebugObjCounterLocset = 0;
1394     xmlXPathDebugObjCounterUsers = 0;
1395     xmlXPathDebugObjCounterXSLTTree = 0;
1396     xmlXPathDebugObjCounterAll = 0;
1397
1398     xmlXPathDebugObjTotalUndefined = 0;
1399     xmlXPathDebugObjTotalNodeset = 0;
1400     xmlXPathDebugObjTotalBool = 0;
1401     xmlXPathDebugObjTotalNumber = 0;
1402     xmlXPathDebugObjTotalString = 0;
1403     xmlXPathDebugObjTotalPoint = 0;
1404     xmlXPathDebugObjTotalRange = 0;
1405     xmlXPathDebugObjTotalLocset = 0;
1406     xmlXPathDebugObjTotalUsers = 0;
1407     xmlXPathDebugObjTotalXSLTTree = 0;
1408     xmlXPathDebugObjTotalAll = 0;
1409
1410     xmlXPathDebugObjMaxUndefined = 0;
1411     xmlXPathDebugObjMaxNodeset = 0;
1412     xmlXPathDebugObjMaxBool = 0;
1413     xmlXPathDebugObjMaxNumber = 0;
1414     xmlXPathDebugObjMaxString = 0;
1415     xmlXPathDebugObjMaxPoint = 0;
1416     xmlXPathDebugObjMaxRange = 0;
1417     xmlXPathDebugObjMaxLocset = 0;
1418     xmlXPathDebugObjMaxUsers = 0;
1419     xmlXPathDebugObjMaxXSLTTree = 0;
1420     xmlXPathDebugObjMaxAll = 0;
1421
1422 }
1423
1424 static void
1425 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1426                               xmlXPathObjectType objType)
1427 {
1428     int isCached = 0;
1429
1430     if (ctxt != NULL) {
1431         if (ctxt->cache != NULL) {
1432             xmlXPathContextCachePtr cache =
1433                 (xmlXPathContextCachePtr) ctxt->cache;
1434
1435             isCached = 1;
1436
1437             cache->dbgReusedAll++;
1438             switch (objType) {
1439                 case XPATH_UNDEFINED:
1440                     cache->dbgReusedUndefined++;
1441                     break;
1442                 case XPATH_NODESET:
1443                     cache->dbgReusedNodeset++;
1444                     break;
1445                 case XPATH_BOOLEAN:
1446                     cache->dbgReusedBool++;
1447                     break;
1448                 case XPATH_NUMBER:
1449                     cache->dbgReusedNumber++;
1450                     break;
1451                 case XPATH_STRING:
1452                     cache->dbgReusedString++;
1453                     break;
1454                 case XPATH_POINT:
1455                     cache->dbgReusedPoint++;
1456                     break;
1457                 case XPATH_RANGE:
1458                     cache->dbgReusedRange++;
1459                     break;
1460                 case XPATH_LOCATIONSET:
1461                     cache->dbgReusedLocset++;
1462                     break;
1463                 case XPATH_USERS:
1464                     cache->dbgReusedUsers++;
1465                     break;
1466                 case XPATH_XSLT_TREE:
1467                     cache->dbgReusedXSLTTree++;
1468                     break;
1469                 default:
1470                     break;
1471             }
1472         }
1473     }
1474
1475     switch (objType) {
1476         case XPATH_UNDEFINED:
1477             if (! isCached)
1478                 xmlXPathDebugObjTotalUndefined++;
1479             xmlXPathDebugObjCounterUndefined++;
1480             if (xmlXPathDebugObjCounterUndefined >
1481                 xmlXPathDebugObjMaxUndefined)
1482                 xmlXPathDebugObjMaxUndefined =
1483                     xmlXPathDebugObjCounterUndefined;
1484             break;
1485         case XPATH_NODESET:
1486             if (! isCached)
1487                 xmlXPathDebugObjTotalNodeset++;
1488             xmlXPathDebugObjCounterNodeset++;
1489             if (xmlXPathDebugObjCounterNodeset >
1490                 xmlXPathDebugObjMaxNodeset)
1491                 xmlXPathDebugObjMaxNodeset =
1492                     xmlXPathDebugObjCounterNodeset;
1493             break;
1494         case XPATH_BOOLEAN:
1495             if (! isCached)
1496                 xmlXPathDebugObjTotalBool++;
1497             xmlXPathDebugObjCounterBool++;
1498             if (xmlXPathDebugObjCounterBool >
1499                 xmlXPathDebugObjMaxBool)
1500                 xmlXPathDebugObjMaxBool =
1501                     xmlXPathDebugObjCounterBool;
1502             break;
1503         case XPATH_NUMBER:
1504             if (! isCached)
1505                 xmlXPathDebugObjTotalNumber++;
1506             xmlXPathDebugObjCounterNumber++;
1507             if (xmlXPathDebugObjCounterNumber >
1508                 xmlXPathDebugObjMaxNumber)
1509                 xmlXPathDebugObjMaxNumber =
1510                     xmlXPathDebugObjCounterNumber;
1511             break;
1512         case XPATH_STRING:
1513             if (! isCached)
1514                 xmlXPathDebugObjTotalString++;
1515             xmlXPathDebugObjCounterString++;
1516             if (xmlXPathDebugObjCounterString >
1517                 xmlXPathDebugObjMaxString)
1518                 xmlXPathDebugObjMaxString =
1519                     xmlXPathDebugObjCounterString;
1520             break;
1521         case XPATH_POINT:
1522             if (! isCached)
1523                 xmlXPathDebugObjTotalPoint++;
1524             xmlXPathDebugObjCounterPoint++;
1525             if (xmlXPathDebugObjCounterPoint >
1526                 xmlXPathDebugObjMaxPoint)
1527                 xmlXPathDebugObjMaxPoint =
1528                     xmlXPathDebugObjCounterPoint;
1529             break;
1530         case XPATH_RANGE:
1531             if (! isCached)
1532                 xmlXPathDebugObjTotalRange++;
1533             xmlXPathDebugObjCounterRange++;
1534             if (xmlXPathDebugObjCounterRange >
1535                 xmlXPathDebugObjMaxRange)
1536                 xmlXPathDebugObjMaxRange =
1537                     xmlXPathDebugObjCounterRange;
1538             break;
1539         case XPATH_LOCATIONSET:
1540             if (! isCached)
1541                 xmlXPathDebugObjTotalLocset++;
1542             xmlXPathDebugObjCounterLocset++;
1543             if (xmlXPathDebugObjCounterLocset >
1544                 xmlXPathDebugObjMaxLocset)
1545                 xmlXPathDebugObjMaxLocset =
1546                     xmlXPathDebugObjCounterLocset;
1547             break;
1548         case XPATH_USERS:
1549             if (! isCached)
1550                 xmlXPathDebugObjTotalUsers++;
1551             xmlXPathDebugObjCounterUsers++;
1552             if (xmlXPathDebugObjCounterUsers >
1553                 xmlXPathDebugObjMaxUsers)
1554                 xmlXPathDebugObjMaxUsers =
1555                     xmlXPathDebugObjCounterUsers;
1556             break;
1557         case XPATH_XSLT_TREE:
1558             if (! isCached)
1559                 xmlXPathDebugObjTotalXSLTTree++;
1560             xmlXPathDebugObjCounterXSLTTree++;
1561             if (xmlXPathDebugObjCounterXSLTTree >
1562                 xmlXPathDebugObjMaxXSLTTree)
1563                 xmlXPathDebugObjMaxXSLTTree =
1564                     xmlXPathDebugObjCounterXSLTTree;
1565             break;
1566         default:
1567             break;
1568     }
1569     if (! isCached)
1570         xmlXPathDebugObjTotalAll++;
1571     xmlXPathDebugObjCounterAll++;
1572     if (xmlXPathDebugObjCounterAll >
1573         xmlXPathDebugObjMaxAll)
1574         xmlXPathDebugObjMaxAll =
1575             xmlXPathDebugObjCounterAll;
1576 }
1577
1578 static void
1579 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1580                               xmlXPathObjectType objType)
1581 {
1582     int isCached = 0;
1583
1584     if (ctxt != NULL) {
1585         if (ctxt->cache != NULL) {
1586             xmlXPathContextCachePtr cache =
1587                 (xmlXPathContextCachePtr) ctxt->cache;
1588
1589             isCached = 1;
1590
1591             cache->dbgCachedAll++;
1592             switch (objType) {
1593                 case XPATH_UNDEFINED:
1594                     cache->dbgCachedUndefined++;
1595                     break;
1596                 case XPATH_NODESET:
1597                     cache->dbgCachedNodeset++;
1598                     break;
1599                 case XPATH_BOOLEAN:
1600                     cache->dbgCachedBool++;
1601                     break;
1602                 case XPATH_NUMBER:
1603                     cache->dbgCachedNumber++;
1604                     break;
1605                 case XPATH_STRING:
1606                     cache->dbgCachedString++;
1607                     break;
1608                 case XPATH_POINT:
1609                     cache->dbgCachedPoint++;
1610                     break;
1611                 case XPATH_RANGE:
1612                     cache->dbgCachedRange++;
1613                     break;
1614                 case XPATH_LOCATIONSET:
1615                     cache->dbgCachedLocset++;
1616                     break;
1617                 case XPATH_USERS:
1618                     cache->dbgCachedUsers++;
1619                     break;
1620                 case XPATH_XSLT_TREE:
1621                     cache->dbgCachedXSLTTree++;
1622                     break;
1623                 default:
1624                     break;
1625             }
1626
1627         }
1628     }
1629     switch (objType) {
1630         case XPATH_UNDEFINED:
1631             xmlXPathDebugObjCounterUndefined--;
1632             break;
1633         case XPATH_NODESET:
1634             xmlXPathDebugObjCounterNodeset--;
1635             break;
1636         case XPATH_BOOLEAN:
1637             xmlXPathDebugObjCounterBool--;
1638             break;
1639         case XPATH_NUMBER:
1640             xmlXPathDebugObjCounterNumber--;
1641             break;
1642         case XPATH_STRING:
1643             xmlXPathDebugObjCounterString--;
1644             break;
1645         case XPATH_POINT:
1646             xmlXPathDebugObjCounterPoint--;
1647             break;
1648         case XPATH_RANGE:
1649             xmlXPathDebugObjCounterRange--;
1650             break;
1651         case XPATH_LOCATIONSET:
1652             xmlXPathDebugObjCounterLocset--;
1653             break;
1654         case XPATH_USERS:
1655             xmlXPathDebugObjCounterUsers--;
1656             break;
1657         case XPATH_XSLT_TREE:
1658             xmlXPathDebugObjCounterXSLTTree--;
1659             break;
1660         default:
1661             break;
1662     }
1663     xmlXPathDebugObjCounterAll--;
1664 }
1665
1666 /* REVISIT TODO: Make this static when committing */
1667 static void
1668 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1669 {
1670     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1671         reqXSLTTree, reqUndefined;
1672     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1673         caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1674     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1675         reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1676     int leftObjs = xmlXPathDebugObjCounterAll;
1677
1678     reqAll = xmlXPathDebugObjTotalAll;
1679     reqNodeset = xmlXPathDebugObjTotalNodeset;
1680     reqString = xmlXPathDebugObjTotalString;
1681     reqBool = xmlXPathDebugObjTotalBool;
1682     reqNumber = xmlXPathDebugObjTotalNumber;
1683     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1684     reqUndefined = xmlXPathDebugObjTotalUndefined;
1685
1686     printf("# XPath object usage:\n");
1687
1688     if (ctxt != NULL) {
1689         if (ctxt->cache != NULL) {
1690             xmlXPathContextCachePtr cache =
1691                 (xmlXPathContextCachePtr) ctxt->cache;
1692
1693             reAll = cache->dbgReusedAll;
1694             reqAll += reAll;
1695             reNodeset = cache->dbgReusedNodeset;
1696             reqNodeset += reNodeset;
1697             reString = cache->dbgReusedString;
1698             reqString += reString;
1699             reBool = cache->dbgReusedBool;
1700             reqBool += reBool;
1701             reNumber = cache->dbgReusedNumber;
1702             reqNumber += reNumber;
1703             reXSLTTree = cache->dbgReusedXSLTTree;
1704             reqXSLTTree += reXSLTTree;
1705             reUndefined = cache->dbgReusedUndefined;
1706             reqUndefined += reUndefined;
1707
1708             caAll = cache->dbgCachedAll;
1709             caBool = cache->dbgCachedBool;
1710             caNodeset = cache->dbgCachedNodeset;
1711             caString = cache->dbgCachedString;
1712             caNumber = cache->dbgCachedNumber;
1713             caXSLTTree = cache->dbgCachedXSLTTree;
1714             caUndefined = cache->dbgCachedUndefined;
1715
1716             if (cache->nodesetObjs)
1717                 leftObjs -= cache->nodesetObjs->number;
1718             if (cache->stringObjs)
1719                 leftObjs -= cache->stringObjs->number;
1720             if (cache->booleanObjs)
1721                 leftObjs -= cache->booleanObjs->number;
1722             if (cache->numberObjs)
1723                 leftObjs -= cache->numberObjs->number;
1724             if (cache->miscObjs)
1725                 leftObjs -= cache->miscObjs->number;
1726         }
1727     }
1728
1729     printf("# all\n");
1730     printf("#   total  : %d\n", reqAll);
1731     printf("#   left  : %d\n", leftObjs);
1732     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
1733     printf("#   reused : %d\n", reAll);
1734     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
1735
1736     printf("# node-sets\n");
1737     printf("#   total  : %d\n", reqNodeset);
1738     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
1739     printf("#   reused : %d\n", reNodeset);
1740     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
1741
1742     printf("# strings\n");
1743     printf("#   total  : %d\n", reqString);
1744     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
1745     printf("#   reused : %d\n", reString);
1746     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
1747
1748     printf("# booleans\n");
1749     printf("#   total  : %d\n", reqBool);
1750     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
1751     printf("#   reused : %d\n", reBool);
1752     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
1753
1754     printf("# numbers\n");
1755     printf("#   total  : %d\n", reqNumber);
1756     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
1757     printf("#   reused : %d\n", reNumber);
1758     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
1759
1760     printf("# XSLT result tree fragments\n");
1761     printf("#   total  : %d\n", reqXSLTTree);
1762     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1763     printf("#   reused : %d\n", reXSLTTree);
1764     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
1765
1766     printf("# undefined\n");
1767     printf("#   total  : %d\n", reqUndefined);
1768     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
1769     printf("#   reused : %d\n", reUndefined);
1770     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
1771
1772 }
1773
1774 #endif /* XP_DEBUG_OBJ_USAGE */
1775
1776 #endif /* LIBXML_DEBUG_ENABLED */
1777
1778 /************************************************************************
1779  *                                                                      *
1780  *                      XPath object caching                            *
1781  *                                                                      *
1782  ************************************************************************/
1783
1784 /**
1785  * xmlXPathNewCache:
1786  *
1787  * Create a new object cache
1788  *
1789  * Returns the xmlXPathCache just allocated.
1790  */
1791 static xmlXPathContextCachePtr
1792 xmlXPathNewCache(void)
1793 {
1794     xmlXPathContextCachePtr ret;
1795
1796     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1797     if (ret == NULL) {
1798         xmlXPathErrMemory(NULL, "creating object cache\n");
1799         return(NULL);
1800     }
1801     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1802     ret->maxNodeset = 100;
1803     ret->maxString = 100;
1804     ret->maxBoolean = 100;
1805     ret->maxNumber = 100;
1806     ret->maxMisc = 100;
1807     return(ret);
1808 }
1809
1810 static void
1811 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1812 {
1813     int i;
1814     xmlXPathObjectPtr obj;
1815
1816     if (list == NULL)
1817         return;
1818
1819     for (i = 0; i < list->number; i++) {
1820         obj = list->items[i];
1821         /*
1822         * Note that it is already assured that we don't need to
1823         * look out for namespace nodes in the node-set.
1824         */
1825         if (obj->nodesetval != NULL) {
1826             if (obj->nodesetval->nodeTab != NULL)
1827                 xmlFree(obj->nodesetval->nodeTab);
1828             xmlFree(obj->nodesetval);
1829         }
1830         xmlFree(obj);
1831 #ifdef XP_DEBUG_OBJ_USAGE
1832         xmlXPathDebugObjCounterAll--;
1833 #endif
1834     }
1835     xmlPointerListFree(list);
1836 }
1837
1838 static void
1839 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1840 {
1841     if (cache == NULL)
1842         return;
1843     if (cache->nodesetObjs)
1844         xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1845     if (cache->stringObjs)
1846         xmlXPathCacheFreeObjectList(cache->stringObjs);
1847     if (cache->booleanObjs)
1848         xmlXPathCacheFreeObjectList(cache->booleanObjs);
1849     if (cache->numberObjs)
1850         xmlXPathCacheFreeObjectList(cache->numberObjs);
1851     if (cache->miscObjs)
1852         xmlXPathCacheFreeObjectList(cache->miscObjs);
1853     xmlFree(cache);
1854 }
1855
1856 /**
1857  * xmlXPathContextSetCache:
1858  *
1859  * @ctxt:  the XPath context
1860  * @active: enables/disables (creates/frees) the cache
1861  * @value: a value with semantics dependant on @options
1862  * @options: options (currently only the value 0 is used)
1863  *
1864  * Creates/frees an object cache on the XPath context.
1865  * If activates XPath objects (xmlXPathObject) will be cached internally
1866  * to be reused.
1867  * @options:
1868  *   0: This will set the XPath object caching:
1869  *      @value:
1870  *        This will set the maximum number of XPath objects
1871  *        to be cached per slot
1872  *        There are 5 slots for: node-set, string, number, boolean, and
1873  *        misc objects. Use <0 for the default number (100).
1874  *   Other values for @options have currently no effect.
1875  *
1876  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1877  */
1878 int
1879 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1880                         int active,
1881                         int value,
1882                         int options)
1883 {
1884     if (ctxt == NULL)
1885         return(-1);
1886     if (active) {
1887         xmlXPathContextCachePtr cache;
1888
1889         if (ctxt->cache == NULL) {
1890             ctxt->cache = xmlXPathNewCache();
1891             if (ctxt->cache == NULL)
1892                 return(-1);
1893         }
1894         cache = (xmlXPathContextCachePtr) ctxt->cache;
1895         if (options == 0) {
1896             if (value < 0)
1897                 value = 100;
1898             cache->maxNodeset = value;
1899             cache->maxString = value;
1900             cache->maxNumber = value;
1901             cache->maxBoolean = value;
1902             cache->maxMisc = value;
1903         }
1904     } else if (ctxt->cache != NULL) {
1905         xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1906         ctxt->cache = NULL;
1907     }
1908     return(0);
1909 }
1910
1911 /**
1912  * xmlXPathCacheWrapNodeSet:
1913  * @ctxt: the XPath context
1914  * @val:  the NodePtr value
1915  *
1916  * This is the cached version of xmlXPathWrapNodeSet().
1917  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1918  *
1919  * Returns the created or reused object.
1920  */
1921 static xmlXPathObjectPtr
1922 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1923 {
1924     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1925         xmlXPathContextCachePtr cache =
1926             (xmlXPathContextCachePtr) ctxt->cache;
1927
1928         if ((cache->miscObjs != NULL) &&
1929             (cache->miscObjs->number != 0))
1930         {
1931             xmlXPathObjectPtr ret;
1932
1933             ret = (xmlXPathObjectPtr)
1934                 cache->miscObjs->items[--cache->miscObjs->number];
1935             ret->type = XPATH_NODESET;
1936             ret->nodesetval = val;
1937 #ifdef XP_DEBUG_OBJ_USAGE
1938             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1939 #endif
1940             return(ret);
1941         }
1942     }
1943
1944     return(xmlXPathWrapNodeSet(val));
1945
1946 }
1947
1948 /**
1949  * xmlXPathCacheWrapString:
1950  * @ctxt: the XPath context
1951  * @val:  the xmlChar * value
1952  *
1953  * This is the cached version of xmlXPathWrapString().
1954  * Wraps the @val string into an XPath object.
1955  *
1956  * Returns the created or reused object.
1957  */
1958 static xmlXPathObjectPtr
1959 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1960 {
1961     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1962         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1963
1964         if ((cache->stringObjs != NULL) &&
1965             (cache->stringObjs->number != 0))
1966         {
1967
1968             xmlXPathObjectPtr ret;
1969
1970             ret = (xmlXPathObjectPtr)
1971                 cache->stringObjs->items[--cache->stringObjs->number];
1972             ret->type = XPATH_STRING;
1973             ret->stringval = val;
1974 #ifdef XP_DEBUG_OBJ_USAGE
1975             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1976 #endif
1977             return(ret);
1978         } else if ((cache->miscObjs != NULL) &&
1979             (cache->miscObjs->number != 0))
1980         {
1981             xmlXPathObjectPtr ret;
1982             /*
1983             * Fallback to misc-cache.
1984             */
1985             ret = (xmlXPathObjectPtr)
1986                 cache->miscObjs->items[--cache->miscObjs->number];
1987
1988             ret->type = XPATH_STRING;
1989             ret->stringval = val;
1990 #ifdef XP_DEBUG_OBJ_USAGE
1991             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1992 #endif
1993             return(ret);
1994         }
1995     }
1996     return(xmlXPathWrapString(val));
1997 }
1998
1999 /**
2000  * xmlXPathCacheNewNodeSet:
2001  * @ctxt: the XPath context
2002  * @val:  the NodePtr value
2003  *
2004  * This is the cached version of xmlXPathNewNodeSet().
2005  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2006  * it with the single Node @val
2007  *
2008  * Returns the created or reused object.
2009  */
2010 static xmlXPathObjectPtr
2011 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2012 {
2013     if ((ctxt != NULL) && (ctxt->cache)) {
2014         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2015
2016         if ((cache->nodesetObjs != NULL) &&
2017             (cache->nodesetObjs->number != 0))
2018         {
2019             xmlXPathObjectPtr ret;
2020             /*
2021             * Use the nodset-cache.
2022             */
2023             ret = (xmlXPathObjectPtr)
2024                 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2025             ret->type = XPATH_NODESET;
2026             ret->boolval = 0;
2027             if (val) {
2028                 if ((ret->nodesetval->nodeMax == 0) ||
2029                     (val->type == XML_NAMESPACE_DECL))
2030                 {
2031                     xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2032                 } else {
2033                     ret->nodesetval->nodeTab[0] = val;
2034                     ret->nodesetval->nodeNr = 1;
2035                 }
2036             }
2037 #ifdef XP_DEBUG_OBJ_USAGE
2038             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2039 #endif
2040             return(ret);
2041         } else if ((cache->miscObjs != NULL) &&
2042             (cache->miscObjs->number != 0))
2043         {
2044             xmlXPathObjectPtr ret;
2045             /*
2046             * Fallback to misc-cache.
2047             */
2048
2049             ret = (xmlXPathObjectPtr)
2050                 cache->miscObjs->items[--cache->miscObjs->number];
2051
2052             ret->type = XPATH_NODESET;
2053             ret->boolval = 0;
2054             ret->nodesetval = xmlXPathNodeSetCreate(val);
2055 #ifdef XP_DEBUG_OBJ_USAGE
2056             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2057 #endif
2058             return(ret);
2059         }
2060     }
2061     return(xmlXPathNewNodeSet(val));
2062 }
2063
2064 /**
2065  * xmlXPathCacheNewCString:
2066  * @ctxt: the XPath context
2067  * @val:  the char * value
2068  *
2069  * This is the cached version of xmlXPathNewCString().
2070  * Acquire an xmlXPathObjectPtr of type string and of value @val
2071  *
2072  * Returns the created or reused object.
2073  */
2074 static xmlXPathObjectPtr
2075 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2076 {
2077     if ((ctxt != NULL) && (ctxt->cache)) {
2078         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2079
2080         if ((cache->stringObjs != NULL) &&
2081             (cache->stringObjs->number != 0))
2082         {
2083             xmlXPathObjectPtr ret;
2084
2085             ret = (xmlXPathObjectPtr)
2086                 cache->stringObjs->items[--cache->stringObjs->number];
2087
2088             ret->type = XPATH_STRING;
2089             ret->stringval = xmlStrdup(BAD_CAST val);
2090 #ifdef XP_DEBUG_OBJ_USAGE
2091             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2092 #endif
2093             return(ret);
2094         } else if ((cache->miscObjs != NULL) &&
2095             (cache->miscObjs->number != 0))
2096         {
2097             xmlXPathObjectPtr ret;
2098
2099             ret = (xmlXPathObjectPtr)
2100                 cache->miscObjs->items[--cache->miscObjs->number];
2101
2102             ret->type = XPATH_STRING;
2103             ret->stringval = xmlStrdup(BAD_CAST val);
2104 #ifdef XP_DEBUG_OBJ_USAGE
2105             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2106 #endif
2107             return(ret);
2108         }
2109     }
2110     return(xmlXPathNewCString(val));
2111 }
2112
2113 /**
2114  * xmlXPathCacheNewString:
2115  * @ctxt: the XPath context
2116  * @val:  the xmlChar * value
2117  *
2118  * This is the cached version of xmlXPathNewString().
2119  * Acquire an xmlXPathObjectPtr of type string and of value @val
2120  *
2121  * Returns the created or reused object.
2122  */
2123 static xmlXPathObjectPtr
2124 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2125 {
2126     if ((ctxt != NULL) && (ctxt->cache)) {
2127         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2128
2129         if ((cache->stringObjs != NULL) &&
2130             (cache->stringObjs->number != 0))
2131         {
2132             xmlXPathObjectPtr ret;
2133
2134             ret = (xmlXPathObjectPtr)
2135                 cache->stringObjs->items[--cache->stringObjs->number];
2136             ret->type = XPATH_STRING;
2137             if (val != NULL)
2138                 ret->stringval = xmlStrdup(val);
2139             else
2140                 ret->stringval = xmlStrdup((const xmlChar *)"");
2141 #ifdef XP_DEBUG_OBJ_USAGE
2142             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2143 #endif
2144             return(ret);
2145         } else if ((cache->miscObjs != NULL) &&
2146             (cache->miscObjs->number != 0))
2147         {
2148             xmlXPathObjectPtr ret;
2149
2150             ret = (xmlXPathObjectPtr)
2151                 cache->miscObjs->items[--cache->miscObjs->number];
2152
2153             ret->type = XPATH_STRING;
2154             if (val != NULL)
2155                 ret->stringval = xmlStrdup(val);
2156             else
2157                 ret->stringval = xmlStrdup((const xmlChar *)"");
2158 #ifdef XP_DEBUG_OBJ_USAGE
2159             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2160 #endif
2161             return(ret);
2162         }
2163     }
2164     return(xmlXPathNewString(val));
2165 }
2166
2167 /**
2168  * xmlXPathCacheNewBoolean:
2169  * @ctxt: the XPath context
2170  * @val:  the boolean value
2171  *
2172  * This is the cached version of xmlXPathNewBoolean().
2173  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2174  *
2175  * Returns the created or reused object.
2176  */
2177 static xmlXPathObjectPtr
2178 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2179 {
2180     if ((ctxt != NULL) && (ctxt->cache)) {
2181         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2182
2183         if ((cache->booleanObjs != NULL) &&
2184             (cache->booleanObjs->number != 0))
2185         {
2186             xmlXPathObjectPtr ret;
2187
2188             ret = (xmlXPathObjectPtr)
2189                 cache->booleanObjs->items[--cache->booleanObjs->number];
2190             ret->type = XPATH_BOOLEAN;
2191             ret->boolval = (val != 0);
2192 #ifdef XP_DEBUG_OBJ_USAGE
2193             xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2194 #endif
2195             return(ret);
2196         } else if ((cache->miscObjs != NULL) &&
2197             (cache->miscObjs->number != 0))
2198         {
2199             xmlXPathObjectPtr ret;
2200
2201             ret = (xmlXPathObjectPtr)
2202                 cache->miscObjs->items[--cache->miscObjs->number];
2203
2204             ret->type = XPATH_BOOLEAN;
2205             ret->boolval = (val != 0);
2206 #ifdef XP_DEBUG_OBJ_USAGE
2207             xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2208 #endif
2209             return(ret);
2210         }
2211     }
2212     return(xmlXPathNewBoolean(val));
2213 }
2214
2215 /**
2216  * xmlXPathCacheNewFloat:
2217  * @ctxt: the XPath context
2218  * @val:  the double value
2219  *
2220  * This is the cached version of xmlXPathNewFloat().
2221  * Acquires an xmlXPathObjectPtr of type double and of value @val
2222  *
2223  * Returns the created or reused object.
2224  */
2225 static xmlXPathObjectPtr
2226 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2227 {
2228      if ((ctxt != NULL) && (ctxt->cache)) {
2229         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2230
2231         if ((cache->numberObjs != NULL) &&
2232             (cache->numberObjs->number != 0))
2233         {
2234             xmlXPathObjectPtr ret;
2235
2236             ret = (xmlXPathObjectPtr)
2237                 cache->numberObjs->items[--cache->numberObjs->number];
2238             ret->type = XPATH_NUMBER;
2239             ret->floatval = val;
2240 #ifdef XP_DEBUG_OBJ_USAGE
2241             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2242 #endif
2243             return(ret);
2244         } else if ((cache->miscObjs != NULL) &&
2245             (cache->miscObjs->number != 0))
2246         {
2247             xmlXPathObjectPtr ret;
2248
2249             ret = (xmlXPathObjectPtr)
2250                 cache->miscObjs->items[--cache->miscObjs->number];
2251
2252             ret->type = XPATH_NUMBER;
2253             ret->floatval = val;
2254 #ifdef XP_DEBUG_OBJ_USAGE
2255             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2256 #endif
2257             return(ret);
2258         }
2259     }
2260     return(xmlXPathNewFloat(val));
2261 }
2262
2263 /**
2264  * xmlXPathCacheConvertString:
2265  * @ctxt: the XPath context
2266  * @val:  an XPath object
2267  *
2268  * This is the cached version of xmlXPathConvertString().
2269  * Converts an existing object to its string() equivalent
2270  *
2271  * Returns a created or reused object, the old one is freed (cached)
2272  *         (or the operation is done directly on @val)
2273  */
2274
2275 static xmlXPathObjectPtr
2276 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2277     xmlChar *res = NULL;
2278
2279     if (val == NULL)
2280         return(xmlXPathCacheNewCString(ctxt, ""));
2281
2282     switch (val->type) {
2283     case XPATH_UNDEFINED:
2284 #ifdef DEBUG_EXPR
2285         xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2286 #endif
2287         break;
2288     case XPATH_NODESET:
2289     case XPATH_XSLT_TREE:
2290         res = xmlXPathCastNodeSetToString(val->nodesetval);
2291         break;
2292     case XPATH_STRING:
2293         return(val);
2294     case XPATH_BOOLEAN:
2295         res = xmlXPathCastBooleanToString(val->boolval);
2296         break;
2297     case XPATH_NUMBER:
2298         res = xmlXPathCastNumberToString(val->floatval);
2299         break;
2300     case XPATH_USERS:
2301     case XPATH_POINT:
2302     case XPATH_RANGE:
2303     case XPATH_LOCATIONSET:
2304         TODO;
2305         break;
2306     }
2307     xmlXPathReleaseObject(ctxt, val);
2308     if (res == NULL)
2309         return(xmlXPathCacheNewCString(ctxt, ""));
2310     return(xmlXPathCacheWrapString(ctxt, res));
2311 }
2312
2313 /**
2314  * xmlXPathCacheObjectCopy:
2315  * @ctxt: the XPath context
2316  * @val:  the original object
2317  *
2318  * This is the cached version of xmlXPathObjectCopy().
2319  * Acquire a copy of a given object
2320  *
2321  * Returns a created or reused created object.
2322  */
2323 static xmlXPathObjectPtr
2324 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2325 {
2326     if (val == NULL)
2327         return(NULL);
2328
2329     if (XP_HAS_CACHE(ctxt)) {
2330         switch (val->type) {
2331             case XPATH_NODESET:
2332                 return(xmlXPathCacheWrapNodeSet(ctxt,
2333                     xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2334             case XPATH_STRING:
2335                 return(xmlXPathCacheNewString(ctxt, val->stringval));
2336             case XPATH_BOOLEAN:
2337                 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2338             case XPATH_NUMBER:
2339                 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2340             default:
2341                 break;
2342         }
2343     }
2344     return(xmlXPathObjectCopy(val));
2345 }
2346
2347 /**
2348  * xmlXPathCacheConvertBoolean:
2349  * @ctxt: the XPath context
2350  * @val:  an XPath object
2351  *
2352  * This is the cached version of xmlXPathConvertBoolean().
2353  * Converts an existing object to its boolean() equivalent
2354  *
2355  * Returns a created or reused object, the old one is freed (or the operation
2356  *         is done directly on @val)
2357  */
2358 static xmlXPathObjectPtr
2359 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2360     xmlXPathObjectPtr ret;
2361
2362     if (val == NULL)
2363         return(xmlXPathCacheNewBoolean(ctxt, 0));
2364     if (val->type == XPATH_BOOLEAN)
2365         return(val);
2366     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2367     xmlXPathReleaseObject(ctxt, val);
2368     return(ret);
2369 }
2370
2371 /**
2372  * xmlXPathCacheConvertNumber:
2373  * @ctxt: the XPath context
2374  * @val:  an XPath object
2375  *
2376  * This is the cached version of xmlXPathConvertNumber().
2377  * Converts an existing object to its number() equivalent
2378  *
2379  * Returns a created or reused object, the old one is freed (or the operation
2380  *         is done directly on @val)
2381  */
2382 static xmlXPathObjectPtr
2383 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2384     xmlXPathObjectPtr ret;
2385
2386     if (val == NULL)
2387         return(xmlXPathCacheNewFloat(ctxt, 0.0));
2388     if (val->type == XPATH_NUMBER)
2389         return(val);
2390     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2391     xmlXPathReleaseObject(ctxt, val);
2392     return(ret);
2393 }
2394
2395 /************************************************************************
2396  *                                                                      *
2397  *              Parser stacks related functions and macros              *
2398  *                                                                      *
2399  ************************************************************************/
2400
2401 /**
2402  * xmlXPathSetFrame:
2403  * @ctxt: an XPath parser context
2404  *
2405  * Set the callee evaluation frame
2406  *
2407  * Returns the previous frame value to be restored once done
2408  */
2409 static int
2410 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2411     int ret;
2412
2413     if (ctxt == NULL)
2414         return(0);
2415     ret = ctxt->valueFrame;
2416     ctxt->valueFrame = ctxt->valueNr;
2417     return(ret);
2418 }
2419
2420 /**
2421  * xmlXPathPopFrame:
2422  * @ctxt: an XPath parser context
2423  * @frame: the previous frame value
2424  *
2425  * Remove the callee evaluation frame
2426  */
2427 static void
2428 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2429     if (ctxt == NULL)
2430         return;
2431     if (ctxt->valueNr < ctxt->valueFrame) {
2432         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2433     }
2434     ctxt->valueFrame = frame;
2435 }
2436
2437 /**
2438  * valuePop:
2439  * @ctxt: an XPath evaluation context
2440  *
2441  * Pops the top XPath object from the value stack
2442  *
2443  * Returns the XPath object just removed
2444  */
2445 xmlXPathObjectPtr
2446 valuePop(xmlXPathParserContextPtr ctxt)
2447 {
2448     xmlXPathObjectPtr ret;
2449
2450     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2451         return (NULL);
2452
2453     if (ctxt->valueNr <= ctxt->valueFrame) {
2454         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2455         return (NULL);
2456     }
2457
2458     ctxt->valueNr--;
2459     if (ctxt->valueNr > 0)
2460         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2461     else
2462         ctxt->value = NULL;
2463     ret = ctxt->valueTab[ctxt->valueNr];
2464     ctxt->valueTab[ctxt->valueNr] = NULL;
2465     return (ret);
2466 }
2467 /**
2468  * valuePush:
2469  * @ctxt:  an XPath evaluation context
2470  * @value:  the XPath object
2471  *
2472  * Pushes a new XPath object on top of the value stack
2473  *
2474  * returns the number of items on the value stack
2475  */
2476 int
2477 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2478 {
2479     if ((ctxt == NULL) || (value == NULL)) return(-1);
2480     if (ctxt->valueNr >= ctxt->valueMax) {
2481         xmlXPathObjectPtr *tmp;
2482
2483         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2484                                              2 * ctxt->valueMax *
2485                                              sizeof(ctxt->valueTab[0]));
2486         if (tmp == NULL) {
2487             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2488             ctxt->error = XPATH_MEMORY_ERROR;
2489             return (0);
2490         }
2491         ctxt->valueMax *= 2;
2492         ctxt->valueTab = tmp;
2493     }
2494     ctxt->valueTab[ctxt->valueNr] = value;
2495     ctxt->value = value;
2496     return (ctxt->valueNr++);
2497 }
2498
2499 /**
2500  * xmlXPathPopBoolean:
2501  * @ctxt:  an XPath parser context
2502  *
2503  * Pops a boolean from the stack, handling conversion if needed.
2504  * Check error with #xmlXPathCheckError.
2505  *
2506  * Returns the boolean
2507  */
2508 int
2509 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2510     xmlXPathObjectPtr obj;
2511     int ret;
2512
2513     obj = valuePop(ctxt);
2514     if (obj == NULL) {
2515         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2516         return(0);
2517     }
2518     if (obj->type != XPATH_BOOLEAN)
2519         ret = xmlXPathCastToBoolean(obj);
2520     else
2521         ret = obj->boolval;
2522     xmlXPathReleaseObject(ctxt->context, obj);
2523     return(ret);
2524 }
2525
2526 /**
2527  * xmlXPathPopNumber:
2528  * @ctxt:  an XPath parser context
2529  *
2530  * Pops a number from the stack, handling conversion if needed.
2531  * Check error with #xmlXPathCheckError.
2532  *
2533  * Returns the number
2534  */
2535 double
2536 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2537     xmlXPathObjectPtr obj;
2538     double ret;
2539
2540     obj = valuePop(ctxt);
2541     if (obj == NULL) {
2542         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2543         return(0);
2544     }
2545     if (obj->type != XPATH_NUMBER)
2546         ret = xmlXPathCastToNumber(obj);
2547     else
2548         ret = obj->floatval;
2549     xmlXPathReleaseObject(ctxt->context, obj);
2550     return(ret);
2551 }
2552
2553 /**
2554  * xmlXPathPopString:
2555  * @ctxt:  an XPath parser context
2556  *
2557  * Pops a string from the stack, handling conversion if needed.
2558  * Check error with #xmlXPathCheckError.
2559  *
2560  * Returns the string
2561  */
2562 xmlChar *
2563 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2564     xmlXPathObjectPtr obj;
2565     xmlChar * ret;
2566
2567     obj = valuePop(ctxt);
2568     if (obj == NULL) {
2569         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2570         return(NULL);
2571     }
2572     ret = xmlXPathCastToString(obj);    /* this does required strdup */
2573     /* TODO: needs refactoring somewhere else */
2574     if (obj->stringval == ret)
2575         obj->stringval = NULL;
2576     xmlXPathReleaseObject(ctxt->context, obj);
2577     return(ret);
2578 }
2579
2580 /**
2581  * xmlXPathPopNodeSet:
2582  * @ctxt:  an XPath parser context
2583  *
2584  * Pops a node-set from the stack, handling conversion if needed.
2585  * Check error with #xmlXPathCheckError.
2586  *
2587  * Returns the node-set
2588  */
2589 xmlNodeSetPtr
2590 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2591     xmlXPathObjectPtr obj;
2592     xmlNodeSetPtr ret;
2593
2594     if (ctxt == NULL) return(NULL);
2595     if (ctxt->value == NULL) {
2596         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2597         return(NULL);
2598     }
2599     if (!xmlXPathStackIsNodeSet(ctxt)) {
2600         xmlXPathSetTypeError(ctxt);
2601         return(NULL);
2602     }
2603     obj = valuePop(ctxt);
2604     ret = obj->nodesetval;
2605 #if 0
2606     /* to fix memory leak of not clearing obj->user */
2607     if (obj->boolval && obj->user != NULL)
2608         xmlFreeNodeList((xmlNodePtr) obj->user);
2609 #endif
2610     obj->nodesetval = NULL;
2611     xmlXPathReleaseObject(ctxt->context, obj);
2612     return(ret);
2613 }
2614
2615 /**
2616  * xmlXPathPopExternal:
2617  * @ctxt:  an XPath parser context
2618  *
2619  * Pops an external object from the stack, handling conversion if needed.
2620  * Check error with #xmlXPathCheckError.
2621  *
2622  * Returns the object
2623  */
2624 void *
2625 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2626     xmlXPathObjectPtr obj;
2627     void * ret;
2628
2629     if ((ctxt == NULL) || (ctxt->value == NULL)) {
2630         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2631         return(NULL);
2632     }
2633     if (ctxt->value->type != XPATH_USERS) {
2634         xmlXPathSetTypeError(ctxt);
2635         return(NULL);
2636     }
2637     obj = valuePop(ctxt);
2638     ret = obj->user;
2639     obj->user = NULL;
2640     xmlXPathReleaseObject(ctxt->context, obj);
2641     return(ret);
2642 }
2643
2644 /*
2645  * Macros for accessing the content. Those should be used only by the parser,
2646  * and not exported.
2647  *
2648  * Dirty macros, i.e. one need to make assumption on the context to use them
2649  *
2650  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2651  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2652  *           in ISO-Latin or UTF-8.
2653  *           This should be used internally by the parser
2654  *           only to compare to ASCII values otherwise it would break when
2655  *           running with UTF-8 encoding.
2656  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2657  *           to compare on ASCII based substring.
2658  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2659  *           strings within the parser.
2660  *   CURRENT Returns the current char value, with the full decoding of
2661  *           UTF-8 if we are using this mode. It returns an int.
2662  *   NEXT    Skip to the next character, this does the proper decoding
2663  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2664  *           It returns the pointer to the current xmlChar.
2665  */
2666
2667 #define CUR (*ctxt->cur)
2668 #define SKIP(val) ctxt->cur += (val)
2669 #define NXT(val) ctxt->cur[(val)]
2670 #define CUR_PTR ctxt->cur
2671 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2672
2673 #define COPY_BUF(l,b,i,v)                                              \
2674     if (l == 1) b[i++] = (xmlChar) v;                                  \
2675     else i += xmlCopyChar(l,&b[i],v)
2676
2677 #define NEXTL(l)  ctxt->cur += l
2678
2679 #define SKIP_BLANKS                                                     \
2680     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2681
2682 #define CURRENT (*ctxt->cur)
2683 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2684
2685
2686 #ifndef DBL_DIG
2687 #define DBL_DIG 16
2688 #endif
2689 #ifndef DBL_EPSILON
2690 #define DBL_EPSILON 1E-9
2691 #endif
2692
2693 #define UPPER_DOUBLE 1E9
2694 #define LOWER_DOUBLE 1E-5
2695 #define LOWER_DOUBLE_EXP 5
2696
2697 #define INTEGER_DIGITS DBL_DIG
2698 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2699 #define EXPONENT_DIGITS (3 + 2)
2700
2701 /**
2702  * xmlXPathFormatNumber:
2703  * @number:     number to format
2704  * @buffer:     output buffer
2705  * @buffersize: size of output buffer
2706  *
2707  * Convert the number into a string representation.
2708  */
2709 static void
2710 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2711 {
2712     switch (xmlXPathIsInf(number)) {
2713     case 1:
2714         if (buffersize > (int)sizeof("Infinity"))
2715             snprintf(buffer, buffersize, "Infinity");
2716         break;
2717     case -1:
2718         if (buffersize > (int)sizeof("-Infinity"))
2719             snprintf(buffer, buffersize, "-Infinity");
2720         break;
2721     default:
2722         if (xmlXPathIsNaN(number)) {
2723             if (buffersize > (int)sizeof("NaN"))
2724                 snprintf(buffer, buffersize, "NaN");
2725         } else if (number == 0 && xmlXPathGetSign(number) != 0) {
2726             snprintf(buffer, buffersize, "0");
2727         } else if (number == ((int) number)) {
2728             char work[30];
2729             char *ptr, *cur;
2730             int value = (int) number;
2731
2732             ptr = &buffer[0];
2733             if (value == 0) {
2734                 *ptr++ = '0';
2735             } else {
2736                 snprintf(work, 29, "%d", value);
2737                 cur = &work[0];
2738                 while ((*cur) && (ptr - buffer < buffersize)) {
2739                     *ptr++ = *cur++;
2740                 }
2741             }
2742             if (ptr - buffer < buffersize) {
2743                 *ptr = 0;
2744             } else if (buffersize > 0) {
2745                 ptr--;
2746                 *ptr = 0;
2747             }
2748         } else {
2749             /*
2750               For the dimension of work,
2751                   DBL_DIG is number of significant digits
2752                   EXPONENT is only needed for "scientific notation"
2753                   3 is sign, decimal point, and terminating zero
2754                   LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2755               Note that this dimension is slightly (a few characters)
2756               larger than actually necessary.
2757             */
2758             char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2759             int integer_place, fraction_place;
2760             char *ptr;
2761             char *after_fraction;
2762             double absolute_value;
2763             int size;
2764
2765             absolute_value = fabs(number);
2766
2767             /*
2768              * First choose format - scientific or regular floating point.
2769              * In either case, result is in work, and after_fraction points
2770              * just past the fractional part.
2771             */
2772             if ( ((absolute_value > UPPER_DOUBLE) ||
2773                   (absolute_value < LOWER_DOUBLE)) &&
2774                  (absolute_value != 0.0) ) {
2775                 /* Use scientific notation */
2776                 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2777                 fraction_place = DBL_DIG - 1;
2778                 size = snprintf(work, sizeof(work),"%*.*e",
2779                          integer_place, fraction_place, number);
2780                 while ((size > 0) && (work[size] != 'e')) size--;
2781
2782             }
2783             else {
2784                 /* Use regular notation */
2785                 if (absolute_value > 0.0) {
2786                     integer_place = (int)log10(absolute_value);
2787                     if (integer_place > 0)
2788                         fraction_place = DBL_DIG - integer_place - 1;
2789                     else
2790                         fraction_place = DBL_DIG - integer_place;
2791                 } else {
2792                     fraction_place = 1;
2793                 }
2794                 size = snprintf(work, sizeof(work), "%0.*f",
2795                                 fraction_place, number);
2796             }
2797
2798             /* Remove fractional trailing zeroes */
2799             after_fraction = work + size;
2800             ptr = after_fraction;
2801             while (*(--ptr) == '0')
2802                 ;
2803             if (*ptr != '.')
2804                 ptr++;
2805             while ((*ptr++ = *after_fraction++) != 0);
2806
2807             /* Finally copy result back to caller */
2808             size = strlen(work) + 1;
2809             if (size > buffersize) {
2810                 work[buffersize - 1] = 0;
2811                 size = buffersize;
2812             }
2813             memmove(buffer, work, size);
2814         }
2815         break;
2816     }
2817 }
2818
2819
2820 /************************************************************************
2821  *                                                                      *
2822  *                      Routines to handle NodeSets                     *
2823  *                                                                      *
2824  ************************************************************************/
2825
2826 /**
2827  * xmlXPathOrderDocElems:
2828  * @doc:  an input document
2829  *
2830  * Call this routine to speed up XPath computation on static documents.
2831  * This stamps all the element nodes with the document order
2832  * Like for line information, the order is kept in the element->content
2833  * field, the value stored is actually - the node number (starting at -1)
2834  * to be able to differentiate from line numbers.
2835  *
2836  * Returns the number of elements found in the document or -1 in case
2837  *    of error.
2838  */
2839 long
2840 xmlXPathOrderDocElems(xmlDocPtr doc) {
2841     long count = 0;
2842     xmlNodePtr cur;
2843
2844     if (doc == NULL)
2845         return(-1);
2846     cur = doc->children;
2847     while (cur != NULL) {
2848         if (cur->type == XML_ELEMENT_NODE) {
2849             cur->content = (void *) (-(++count));
2850             if (cur->children != NULL) {
2851                 cur = cur->children;
2852                 continue;
2853             }
2854         }
2855         if (cur->next != NULL) {
2856             cur = cur->next;
2857             continue;
2858         }
2859         do {
2860             cur = cur->parent;
2861             if (cur == NULL)
2862                 break;
2863             if (cur == (xmlNodePtr) doc) {
2864                 cur = NULL;
2865                 break;
2866             }
2867             if (cur->next != NULL) {
2868                 cur = cur->next;
2869                 break;
2870             }
2871         } while (cur != NULL);
2872     }
2873     return(count);
2874 }
2875
2876 /**
2877  * xmlXPathCmpNodes:
2878  * @node1:  the first node
2879  * @node2:  the second node
2880  *
2881  * Compare two nodes w.r.t document order
2882  *
2883  * Returns -2 in case of error 1 if first point < second point, 0 if
2884  *         it's the same node, -1 otherwise
2885  */
2886 int
2887 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2888     int depth1, depth2;
2889     int attr1 = 0, attr2 = 0;
2890     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2891     xmlNodePtr cur, root;
2892
2893     if ((node1 == NULL) || (node2 == NULL))
2894         return(-2);
2895     /*
2896      * a couple of optimizations which will avoid computations in most cases
2897      */
2898     if (node1 == node2)         /* trivial case */
2899         return(0);
2900     if (node1->type == XML_ATTRIBUTE_NODE) {
2901         attr1 = 1;
2902         attrNode1 = node1;
2903         node1 = node1->parent;
2904     }
2905     if (node2->type == XML_ATTRIBUTE_NODE) {
2906         attr2 = 1;
2907         attrNode2 = node2;
2908         node2 = node2->parent;
2909     }
2910     if (node1 == node2) {
2911         if (attr1 == attr2) {
2912             /* not required, but we keep attributes in order */
2913             if (attr1 != 0) {
2914                 cur = attrNode2->prev;
2915                 while (cur != NULL) {
2916                     if (cur == attrNode1)
2917                         return (1);
2918                     cur = cur->prev;
2919                 }
2920                 return (-1);
2921             }
2922             return(0);
2923         }
2924         if (attr2 == 1)
2925             return(1);
2926         return(-1);
2927     }
2928     if ((node1->type == XML_NAMESPACE_DECL) ||
2929         (node2->type == XML_NAMESPACE_DECL))
2930         return(1);
2931     if (node1 == node2->prev)
2932         return(1);
2933     if (node1 == node2->next)
2934         return(-1);
2935
2936     /*
2937      * Speedup using document order if availble.
2938      */
2939     if ((node1->type == XML_ELEMENT_NODE) &&
2940         (node2->type == XML_ELEMENT_NODE) &&
2941         (0 > (long) node1->content) &&
2942         (0 > (long) node2->content) &&
2943         (node1->doc == node2->doc)) {
2944         long l1, l2;
2945
2946         l1 = -((long) node1->content);
2947         l2 = -((long) node2->content);
2948         if (l1 < l2)
2949             return(1);
2950         if (l1 > l2)
2951             return(-1);
2952     }
2953
2954     /*
2955      * compute depth to root
2956      */
2957     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2958         if (cur == node1)
2959             return(1);
2960         depth2++;
2961     }
2962     root = cur;
2963     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2964         if (cur == node2)
2965             return(-1);
2966         depth1++;
2967     }
2968     /*
2969      * Distinct document (or distinct entities :-( ) case.
2970      */
2971     if (root != cur) {
2972         return(-2);
2973     }
2974     /*
2975      * get the nearest common ancestor.
2976      */
2977     while (depth1 > depth2) {
2978         depth1--;
2979         node1 = node1->parent;
2980     }
2981     while (depth2 > depth1) {
2982         depth2--;
2983         node2 = node2->parent;
2984     }
2985     while (node1->parent != node2->parent) {
2986         node1 = node1->parent;
2987         node2 = node2->parent;
2988         /* should not happen but just in case ... */
2989         if ((node1 == NULL) || (node2 == NULL))
2990             return(-2);
2991     }
2992     /*
2993      * Find who's first.
2994      */
2995     if (node1 == node2->prev)
2996         return(1);
2997     if (node1 == node2->next)
2998         return(-1);
2999     /*
3000      * Speedup using document order if availble.
3001      */
3002     if ((node1->type == XML_ELEMENT_NODE) &&
3003         (node2->type == XML_ELEMENT_NODE) &&
3004         (0 > (long) node1->content) &&
3005         (0 > (long) node2->content) &&
3006         (node1->doc == node2->doc)) {
3007         long l1, l2;
3008
3009         l1 = -((long) node1->content);
3010         l2 = -((long) node2->content);
3011         if (l1 < l2)
3012             return(1);
3013         if (l1 > l2)
3014             return(-1);
3015     }
3016
3017     for (cur = node1->next;cur != NULL;cur = cur->next)
3018         if (cur == node2)
3019             return(1);
3020     return(-1); /* assume there is no sibling list corruption */
3021 }
3022
3023 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3024 /**
3025  * xmlXPathCmpNodesExt:
3026  * @node1:  the first node
3027  * @node2:  the second node
3028  *
3029  * Compare two nodes w.r.t document order.
3030  * This one is optimized for handling of non-element nodes.
3031  *
3032  * Returns -2 in case of error 1 if first point < second point, 0 if
3033  *         it's the same node, -1 otherwise
3034  */
3035 static int
3036 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
3037     int depth1, depth2;
3038     int misc = 0, precedence1 = 0, precedence2 = 0;
3039     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
3040     xmlNodePtr cur, root;
3041     long l1, l2;
3042
3043     if ((node1 == NULL) || (node2 == NULL))
3044         return(-2);
3045
3046     if (node1 == node2)
3047         return(0);
3048
3049     /*
3050      * a couple of optimizations which will avoid computations in most cases
3051      */
3052     switch (node1->type) {
3053         case XML_ELEMENT_NODE:
3054             if (node2->type == XML_ELEMENT_NODE) {
3055                 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3056                     (0 > (long) node2->content) &&
3057                     (node1->doc == node2->doc))
3058                 {
3059                     l1 = -((long) node1->content);
3060                     l2 = -((long) node2->content);
3061                     if (l1 < l2)
3062                         return(1);
3063                     if (l1 > l2)
3064                         return(-1);
3065                 } else
3066                     goto turtle_comparison;
3067             }
3068             break;
3069         case XML_ATTRIBUTE_NODE:
3070             precedence1 = 1; /* element is owner */
3071             miscNode1 = node1;
3072             node1 = node1->parent;
3073             misc = 1;
3074             break;
3075         case XML_TEXT_NODE:
3076         case XML_CDATA_SECTION_NODE:
3077         case XML_COMMENT_NODE:
3078         case XML_PI_NODE: {
3079             miscNode1 = node1;
3080             /*
3081             * Find nearest element node.
3082             */
3083             if (node1->prev != NULL) {
3084                 do {
3085                     node1 = node1->prev;
3086                     if (node1->type == XML_ELEMENT_NODE) {
3087                         precedence1 = 3; /* element in prev-sibl axis */
3088                         break;
3089                     }
3090                     if (node1->prev == NULL) {
3091                         precedence1 = 2; /* element is parent */
3092                         /*
3093                         * URGENT TODO: Are there any cases, where the
3094                         * parent of such a node is not an element node?
3095                         */
3096                         node1 = node1->parent;
3097                         break;
3098                     }
3099                 } while (1);
3100             } else {
3101                 precedence1 = 2; /* element is parent */
3102                 node1 = node1->parent;
3103             }
3104             if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3105                 (0 <= (long) node1->content)) {
3106                 /*
3107                 * Fallback for whatever case.
3108                 */
3109                 node1 = miscNode1;
3110                 precedence1 = 0;
3111             } else
3112                 misc = 1;
3113         }
3114             break;
3115         case XML_NAMESPACE_DECL:
3116             /*
3117             * TODO: why do we return 1 for namespace nodes?
3118             */
3119             return(1);
3120         default:
3121             break;
3122     }
3123     switch (node2->type) {
3124         case XML_ELEMENT_NODE:
3125             break;
3126         case XML_ATTRIBUTE_NODE:
3127             precedence2 = 1; /* element is owner */
3128             miscNode2 = node2;
3129             node2 = node2->parent;
3130             misc = 1;
3131             break;
3132         case XML_TEXT_NODE:
3133         case XML_CDATA_SECTION_NODE:
3134         case XML_COMMENT_NODE:
3135         case XML_PI_NODE: {
3136             miscNode2 = node2;
3137             if (node2->prev != NULL) {
3138                 do {
3139                     node2 = node2->prev;
3140                     if (node2->type == XML_ELEMENT_NODE) {
3141                         precedence2 = 3; /* element in prev-sibl axis */
3142                         break;
3143                     }
3144                     if (node2->prev == NULL) {
3145                         precedence2 = 2; /* element is parent */
3146                         node2 = node2->parent;
3147                         break;
3148                     }
3149                 } while (1);
3150             } else {
3151                 precedence2 = 2; /* element is parent */
3152                 node2 = node2->parent;
3153             }
3154             if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3155                 (0 <= (long) node1->content))
3156             {
3157                 node2 = miscNode2;
3158                 precedence2 = 0;
3159             } else
3160                 misc = 1;
3161         }
3162             break;
3163         case XML_NAMESPACE_DECL:
3164             return(1);
3165         default:
3166             break;
3167     }
3168     if (misc) {
3169         if (node1 == node2) {
3170             if (precedence1 == precedence2) {
3171                 /*
3172                 * The ugly case; but normally there aren't many
3173                 * adjacent non-element nodes around.
3174                 */
3175                 cur = miscNode2->prev;
3176                 while (cur != NULL) {
3177                     if (cur == miscNode1)
3178                         return(1);
3179                     if (cur->type == XML_ELEMENT_NODE)
3180                         return(-1);
3181                     cur = cur->prev;
3182                 }
3183                 return (-1);
3184             } else {
3185                 /*
3186                 * Evaluate based on higher precedence wrt to the element.
3187                 * TODO: This assumes attributes are sorted before content.
3188                 *   Is this 100% correct?
3189                 */
3190                 if (precedence1 < precedence2)
3191                     return(1);
3192                 else
3193                     return(-1);
3194             }
3195         }
3196         /*
3197         * Special case: One of the helper-elements is contained by the other.
3198         * <foo>
3199         *   <node2>
3200         *     <node1>Text-1(precedence1 == 2)</node1>
3201         *   </node2>
3202         *   Text-6(precedence2 == 3)
3203         * </foo>
3204         */
3205         if ((precedence2 == 3) && (precedence1 > 1)) {
3206             cur = node1->parent;
3207             while (cur) {
3208                 if (cur == node2)
3209                     return(1);
3210                 cur = cur->parent;
3211             }
3212         }
3213         if ((precedence1 == 3) && (precedence2 > 1)) {
3214             cur = node2->parent;
3215             while (cur) {
3216                 if (cur == node1)
3217                     return(-1);
3218                 cur = cur->parent;
3219             }
3220         }
3221     }
3222
3223     /*
3224      * Speedup using document order if availble.
3225      */
3226     if ((node1->type == XML_ELEMENT_NODE) &&
3227         (node2->type == XML_ELEMENT_NODE) &&
3228         (0 > (long) node1->content) &&
3229         (0 > (long) node2->content) &&
3230         (node1->doc == node2->doc)) {
3231
3232         l1 = -((long) node1->content);
3233         l2 = -((long) node2->content);
3234         if (l1 < l2)
3235             return(1);
3236         if (l1 > l2)
3237             return(-1);
3238     }
3239
3240 turtle_comparison:
3241
3242     if (node1 == node2->prev)
3243         return(1);
3244     if (node1 == node2->next)
3245         return(-1);
3246     /*
3247      * compute depth to root
3248      */
3249     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3250         if (cur == node1)
3251             return(1);
3252         depth2++;
3253     }
3254     root = cur;
3255     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3256         if (cur == node2)
3257             return(-1);
3258         depth1++;
3259     }
3260     /*
3261      * Distinct document (or distinct entities :-( ) case.
3262      */
3263     if (root != cur) {
3264         return(-2);
3265     }
3266     /*
3267      * get the nearest common ancestor.
3268      */
3269     while (depth1 > depth2) {
3270         depth1--;
3271         node1 = node1->parent;
3272     }
3273     while (depth2 > depth1) {
3274         depth2--;
3275         node2 = node2->parent;
3276     }
3277     while (node1->parent != node2->parent) {
3278         node1 = node1->parent;
3279         node2 = node2->parent;
3280         /* should not happen but just in case ... */
3281         if ((node1 == NULL) || (node2 == NULL))
3282             return(-2);
3283     }
3284     /*
3285      * Find who's first.
3286      */
3287     if (node1 == node2->prev)
3288         return(1);
3289     if (node1 == node2->next)
3290         return(-1);
3291     /*
3292      * Speedup using document order if availble.
3293      */
3294     if ((node1->type == XML_ELEMENT_NODE) &&
3295         (node2->type == XML_ELEMENT_NODE) &&
3296         (0 > (long) node1->content) &&
3297         (0 > (long) node2->content) &&
3298         (node1->doc == node2->doc)) {
3299
3300         l1 = -((long) node1->content);
3301         l2 = -((long) node2->content);
3302         if (l1 < l2)
3303             return(1);
3304         if (l1 > l2)
3305             return(-1);
3306     }
3307
3308     for (cur = node1->next;cur != NULL;cur = cur->next)
3309         if (cur == node2)
3310             return(1);
3311     return(-1); /* assume there is no sibling list corruption */
3312 }
3313 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3314
3315 /**
3316  * xmlXPathNodeSetSort:
3317  * @set:  the node set
3318  *
3319  * Sort the node set in document order
3320  */
3321 void
3322 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3323     int i, j, incr, len;
3324     xmlNodePtr tmp;
3325
3326     if (set == NULL)
3327         return;
3328
3329     /* Use Shell's sort to sort the node-set */
3330     len = set->nodeNr;
3331     for (incr = len / 2; incr > 0; incr /= 2) {
3332         for (i = incr; i < len; i++) {
3333             j = i - incr;
3334             while (j >= 0) {
3335 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3336                 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3337                         set->nodeTab[j + incr]) == -1)
3338 #else
3339                 if (xmlXPathCmpNodes(set->nodeTab[j],
3340                         set->nodeTab[j + incr]) == -1)
3341 #endif
3342                 {
3343                     tmp = set->nodeTab[j];
3344                     set->nodeTab[j] = set->nodeTab[j + incr];
3345                     set->nodeTab[j + incr] = tmp;
3346                     j -= incr;
3347                 } else
3348                     break;
3349             }
3350         }
3351     }
3352 }
3353
3354 #define XML_NODESET_DEFAULT     10
3355 /**
3356  * xmlXPathNodeSetDupNs:
3357  * @node:  the parent node of the namespace XPath node
3358  * @ns:  the libxml namespace declaration node.
3359  *
3360  * Namespace node in libxml don't match the XPath semantic. In a node set
3361  * the namespace nodes are duplicated and the next pointer is set to the
3362  * parent node in the XPath semantic.
3363  *
3364  * Returns the newly created object.
3365  */
3366 static xmlNodePtr
3367 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3368     xmlNsPtr cur;
3369
3370     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3371         return(NULL);
3372     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3373         return((xmlNodePtr) ns);
3374
3375     /*
3376      * Allocate a new Namespace and fill the fields.
3377      */
3378     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3379     if (cur == NULL) {
3380         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3381         return(NULL);
3382     }
3383     memset(cur, 0, sizeof(xmlNs));
3384     cur->type = XML_NAMESPACE_DECL;
3385     if (ns->href != NULL)
3386         cur->href = xmlStrdup(ns->href);
3387     if (ns->prefix != NULL)
3388         cur->prefix = xmlStrdup(ns->prefix);
3389     cur->next = (xmlNsPtr) node;
3390     return((xmlNodePtr) cur);
3391 }
3392
3393 /**
3394  * xmlXPathNodeSetFreeNs:
3395  * @ns:  the XPath namespace node found in a nodeset.
3396  *
3397  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3398  * the namespace nodes are duplicated and the next pointer is set to the
3399  * parent node in the XPath semantic. Check if such a node needs to be freed
3400  */
3401 void
3402 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3403     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3404         return;
3405
3406     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3407         if (ns->href != NULL)
3408             xmlFree((xmlChar *)ns->href);
3409         if (ns->prefix != NULL)
3410             xmlFree((xmlChar *)ns->prefix);
3411         xmlFree(ns);
3412     }
3413 }
3414
3415 /**
3416  * xmlXPathNodeSetCreate:
3417  * @val:  an initial xmlNodePtr, or NULL
3418  *
3419  * Create a new xmlNodeSetPtr of type double and of value @val
3420  *
3421  * Returns the newly created object.
3422  */
3423 xmlNodeSetPtr
3424 xmlXPathNodeSetCreate(xmlNodePtr val) {
3425     xmlNodeSetPtr ret;
3426
3427     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3428     if (ret == NULL) {
3429         xmlXPathErrMemory(NULL, "creating nodeset\n");
3430         return(NULL);
3431     }
3432     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3433     if (val != NULL) {
3434         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3435                                              sizeof(xmlNodePtr));
3436         if (ret->nodeTab == NULL) {
3437             xmlXPathErrMemory(NULL, "creating nodeset\n");
3438             xmlFree(ret);
3439             return(NULL);
3440         }
3441         memset(ret->nodeTab, 0 ,
3442                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3443         ret->nodeMax = XML_NODESET_DEFAULT;
3444         if (val->type == XML_NAMESPACE_DECL) {
3445             xmlNsPtr ns = (xmlNsPtr) val;
3446
3447             ret->nodeTab[ret->nodeNr++] =
3448                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3449         } else
3450             ret->nodeTab[ret->nodeNr++] = val;
3451     }
3452     return(ret);
3453 }
3454
3455 /**
3456  * xmlXPathNodeSetCreateSize:
3457  * @size:  the initial size of the set
3458  *
3459  * Create a new xmlNodeSetPtr of type double and of value @val
3460  *
3461  * Returns the newly created object.
3462  */
3463 static xmlNodeSetPtr
3464 xmlXPathNodeSetCreateSize(int size) {
3465     xmlNodeSetPtr ret;
3466
3467     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3468     if (ret == NULL) {
3469         xmlXPathErrMemory(NULL, "creating nodeset\n");
3470         return(NULL);
3471     }
3472     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3473     if (size < XML_NODESET_DEFAULT)
3474         size = XML_NODESET_DEFAULT;
3475     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3476     if (ret->nodeTab == NULL) {
3477         xmlXPathErrMemory(NULL, "creating nodeset\n");
3478         xmlFree(ret);
3479         return(NULL);
3480     }
3481     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3482     ret->nodeMax = size;
3483     return(ret);
3484 }
3485
3486 /**
3487  * xmlXPathNodeSetContains:
3488  * @cur:  the node-set
3489  * @val:  the node
3490  *
3491  * checks whether @cur contains @val
3492  *
3493  * Returns true (1) if @cur contains @val, false (0) otherwise
3494  */
3495 int
3496 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3497     int i;
3498
3499     if ((cur == NULL) || (val == NULL)) return(0);
3500     if (val->type == XML_NAMESPACE_DECL) {
3501         for (i = 0; i < cur->nodeNr; i++) {
3502             if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3503                 xmlNsPtr ns1, ns2;
3504
3505                 ns1 = (xmlNsPtr) val;
3506                 ns2 = (xmlNsPtr) cur->nodeTab[i];
3507                 if (ns1 == ns2)
3508                     return(1);
3509                 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3510                     (xmlStrEqual(ns1->prefix, ns2->prefix)))
3511                     return(1);
3512             }
3513         }
3514     } else {
3515         for (i = 0; i < cur->nodeNr; i++) {
3516             if (cur->nodeTab[i] == val)
3517                 return(1);
3518         }
3519     }
3520     return(0);
3521 }
3522
3523 /**
3524  * xmlXPathNodeSetAddNs:
3525  * @cur:  the initial node set
3526  * @node:  the hosting node
3527  * @ns:  a the namespace node
3528  *
3529  * add a new namespace node to an existing NodeSet
3530  */
3531 void
3532 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3533     int i;
3534
3535
3536     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3537         (ns->type != XML_NAMESPACE_DECL) ||
3538         (node->type != XML_ELEMENT_NODE))
3539         return;
3540
3541     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3542     /*
3543      * prevent duplicates
3544      */
3545     for (i = 0;i < cur->nodeNr;i++) {
3546         if ((cur->nodeTab[i] != NULL) &&
3547             (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3548             (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3549             (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3550             return;
3551     }
3552
3553     /*
3554      * grow the nodeTab if needed
3555      */
3556     if (cur->nodeMax == 0) {
3557         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3558                                              sizeof(xmlNodePtr));
3559         if (cur->nodeTab == NULL) {
3560             xmlXPathErrMemory(NULL, "growing nodeset\n");
3561             return;
3562         }
3563         memset(cur->nodeTab, 0 ,
3564                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3565         cur->nodeMax = XML_NODESET_DEFAULT;
3566     } else if (cur->nodeNr == cur->nodeMax) {
3567         xmlNodePtr *temp;
3568
3569         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3570                                       sizeof(xmlNodePtr));
3571         if (temp == NULL) {
3572             xmlXPathErrMemory(NULL, "growing nodeset\n");
3573             return;
3574         }
3575         cur->nodeMax *= 2;
3576         cur->nodeTab = temp;
3577     }
3578     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3579 }
3580
3581 /**
3582  * xmlXPathNodeSetAdd:
3583  * @cur:  the initial node set
3584  * @val:  a new xmlNodePtr
3585  *
3586  * add a new xmlNodePtr to an existing NodeSet
3587  */
3588 void
3589 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3590     int i;
3591
3592     if ((cur == NULL) || (val == NULL)) return;
3593
3594 #if 0
3595     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3596         return; /* an XSLT fake node */
3597 #endif
3598
3599     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3600     /*
3601      * prevent duplcates
3602      */
3603     for (i = 0;i < cur->nodeNr;i++)
3604         if (cur->nodeTab[i] == val) return;
3605
3606     /*
3607      * grow the nodeTab if needed
3608      */
3609     if (cur->nodeMax == 0) {
3610         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3611                                              sizeof(xmlNodePtr));
3612         if (cur->nodeTab == NULL) {
3613             xmlXPathErrMemory(NULL, "growing nodeset\n");
3614             return;
3615         }
3616         memset(cur->nodeTab, 0 ,
3617                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3618         cur->nodeMax = XML_NODESET_DEFAULT;
3619     } else if (cur->nodeNr == cur->nodeMax) {
3620         xmlNodePtr *temp;
3621
3622         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3623                                       sizeof(xmlNodePtr));
3624         if (temp == NULL) {
3625             xmlXPathErrMemory(NULL, "growing nodeset\n");
3626             return;
3627         }
3628         cur->nodeMax *= 2;
3629         cur->nodeTab = temp;
3630     }
3631     if (val->type == XML_NAMESPACE_DECL) {
3632         xmlNsPtr ns = (xmlNsPtr) val;
3633
3634         cur->nodeTab[cur->nodeNr++] =
3635             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3636     } else
3637         cur->nodeTab[cur->nodeNr++] = val;
3638 }
3639
3640 /**
3641  * xmlXPathNodeSetAddUnique:
3642  * @cur:  the initial node set
3643  * @val:  a new xmlNodePtr
3644  *
3645  * add a new xmlNodePtr to an existing NodeSet, optimized version
3646  * when we are sure the node is not already in the set.
3647  */
3648 void
3649 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3650     if ((cur == NULL) || (val == NULL)) return;
3651
3652 #if 0
3653     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3654         return; /* an XSLT fake node */
3655 #endif
3656
3657     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3658     /*
3659      * grow the nodeTab if needed
3660      */
3661     if (cur->nodeMax == 0) {
3662         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3663                                              sizeof(xmlNodePtr));
3664         if (cur->nodeTab == NULL) {
3665             xmlXPathErrMemory(NULL, "growing nodeset\n");
3666             return;
3667         }
3668         memset(cur->nodeTab, 0 ,
3669                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3670         cur->nodeMax = XML_NODESET_DEFAULT;
3671     } else if (cur->nodeNr == cur->nodeMax) {
3672         xmlNodePtr *temp;
3673
3674         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3675                                       sizeof(xmlNodePtr));
3676         if (temp == NULL) {
3677             xmlXPathErrMemory(NULL, "growing nodeset\n");
3678             return;
3679         }
3680         cur->nodeTab = temp;
3681         cur->nodeMax *= 2;
3682     }
3683     if (val->type == XML_NAMESPACE_DECL) {
3684         xmlNsPtr ns = (xmlNsPtr) val;
3685
3686         cur->nodeTab[cur->nodeNr++] =
3687             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3688     } else
3689         cur->nodeTab[cur->nodeNr++] = val;
3690 }
3691
3692 /**
3693  * xmlXPathNodeSetMerge:
3694  * @val1:  the first NodeSet or NULL
3695  * @val2:  the second NodeSet
3696  *
3697  * Merges two nodesets, all nodes from @val2 are added to @val1
3698  * if @val1 is NULL, a new set is created and copied from @val2
3699  *
3700  * Returns @val1 once extended or NULL in case of error.
3701  */
3702 xmlNodeSetPtr
3703 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3704     int i, j, initNr, skip;
3705     xmlNodePtr n1, n2;
3706
3707     if (val2 == NULL) return(val1);
3708     if (val1 == NULL) {
3709         val1 = xmlXPathNodeSetCreate(NULL);
3710     if (val1 == NULL)
3711         return (NULL);
3712 #if 0
3713         /*
3714         * TODO: The optimization won't work in every case, since
3715         *  those nasty namespace nodes need to be added with
3716         *  xmlXPathNodeSetDupNs() to the set; thus a pure
3717         *  memcpy is not possible.
3718         *  If there was a flag on the nodesetval, indicating that
3719         *  some temporary nodes are in, that would be helpfull.
3720         */
3721         /*
3722         * Optimization: Create an equally sized node-set
3723         * and memcpy the content.
3724         */
3725         val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3726         if (val1 == NULL)
3727             return(NULL);
3728         if (val2->nodeNr != 0) {
3729             if (val2->nodeNr == 1)
3730                 *(val1->nodeTab) = *(val2->nodeTab);
3731             else {
3732                 memcpy(val1->nodeTab, val2->nodeTab,
3733                     val2->nodeNr * sizeof(xmlNodePtr));
3734             }
3735             val1->nodeNr = val2->nodeNr;
3736         }
3737         return(val1);
3738 #endif
3739     }
3740
3741     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3742     initNr = val1->nodeNr;
3743
3744     for (i = 0;i < val2->nodeNr;i++) {
3745         n2 = val2->nodeTab[i];
3746         /*
3747          * check against duplicates
3748          */
3749         skip = 0;
3750         for (j = 0; j < initNr; j++) {
3751             n1 = val1->nodeTab[j];
3752             if (n1 == n2) {
3753                 skip = 1;
3754                 break;
3755             } else if ((n1->type == XML_NAMESPACE_DECL) &&
3756                        (n2->type == XML_NAMESPACE_DECL)) {
3757                 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3758                     (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3759                         ((xmlNsPtr) n2)->prefix)))
3760                 {
3761                     skip = 1;
3762                     break;
3763                 }
3764             }
3765         }
3766         if (skip)
3767             continue;
3768
3769         /*
3770          * grow the nodeTab if needed
3771          */
3772         if (val1->nodeMax == 0) {
3773             val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3774                                                     sizeof(xmlNodePtr));
3775             if (val1->nodeTab == NULL) {
3776                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3777                 return(NULL);
3778             }
3779             memset(val1->nodeTab, 0 ,
3780                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3781             val1->nodeMax = XML_NODESET_DEFAULT;
3782         } else if (val1->nodeNr == val1->nodeMax) {
3783             xmlNodePtr *temp;
3784
3785             temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3786                                              sizeof(xmlNodePtr));
3787             if (temp == NULL) {
3788                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3789                 return(NULL);
3790             }
3791             val1->nodeTab = temp;
3792             val1->nodeMax *= 2;
3793         }
3794         if (n2->type == XML_NAMESPACE_DECL) {
3795             xmlNsPtr ns = (xmlNsPtr) n2;
3796
3797             val1->nodeTab[val1->nodeNr++] =
3798                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3799         } else
3800             val1->nodeTab[val1->nodeNr++] = n2;
3801     }
3802
3803     return(val1);
3804 }
3805
3806 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3807 /**
3808  * xmlXPathNodeSetMergeUnique:
3809  * @val1:  the first NodeSet or NULL
3810  * @val2:  the second NodeSet
3811  *
3812  * Merges two nodesets, all nodes from @val2 are added to @val1
3813  * if @val1 is NULL, a new set is created and copied from @val2
3814  *
3815  * Returns @val1 once extended or NULL in case of error.
3816  */
3817 static xmlNodeSetPtr
3818 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3819     int i;
3820
3821     if (val2 == NULL) return(val1);
3822     if (val1 == NULL) {
3823         val1 = xmlXPathNodeSetCreate(NULL);
3824     }
3825     if (val1 == NULL)
3826         return (NULL);
3827
3828     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3829
3830     for (i = 0;i < val2->nodeNr;i++) {
3831         /*
3832          * grow the nodeTab if needed
3833          */
3834         if (val1->nodeMax == 0) {
3835             val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3836                                                     sizeof(xmlNodePtr));
3837             if (val1->nodeTab == NULL) {
3838                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3839                 return(NULL);
3840             }
3841             memset(val1->nodeTab, 0 ,
3842                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3843             val1->nodeMax = XML_NODESET_DEFAULT;
3844         } else if (val1->nodeNr == val1->nodeMax) {
3845             xmlNodePtr *temp;
3846
3847             val1->nodeMax *= 2;
3848             temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3849                                              sizeof(xmlNodePtr));
3850             if (temp == NULL) {
3851                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3852                 return(NULL);
3853             }
3854             val1->nodeTab = temp;
3855         }
3856         if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3857             xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3858
3859             val1->nodeTab[val1->nodeNr++] =
3860                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3861         } else
3862             val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3863     }
3864
3865     return(val1);
3866 }
3867 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3868
3869 /**
3870  * xmlXPathNodeSetMergeAndClear:
3871  * @set1:  the first NodeSet or NULL
3872  * @set2:  the second NodeSet
3873  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3874  *
3875  * Merges two nodesets, all nodes from @set2 are added to @set1
3876  * if @set1 is NULL, a new set is created and copied from @set2.
3877  * Checks for duplicate nodes. Clears set2.
3878  *
3879  * Returns @set1 once extended or NULL in case of error.
3880  */
3881 static xmlNodeSetPtr
3882 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3883                              int hasNullEntries)
3884 {
3885     if ((set1 == NULL) && (hasNullEntries == 0)) {
3886         /*
3887         * Note that doing a memcpy of the list, namespace nodes are
3888         * just assigned to set1, since set2 is cleared anyway.
3889         */
3890         set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3891         if (set1 == NULL)
3892             return(NULL);
3893         if (set2->nodeNr != 0) {
3894             memcpy(set1->nodeTab, set2->nodeTab,
3895                 set2->nodeNr * sizeof(xmlNodePtr));
3896             set1->nodeNr = set2->nodeNr;
3897         }
3898     } else {
3899         int i, j, initNbSet1;
3900         xmlNodePtr n1, n2;
3901
3902         if (set1 == NULL)
3903             set1 = xmlXPathNodeSetCreate(NULL);
3904         if (set1 == NULL)
3905             return (NULL);
3906
3907         initNbSet1 = set1->nodeNr;
3908         for (i = 0;i < set2->nodeNr;i++) {
3909             n2 = set2->nodeTab[i];
3910             /*
3911             * Skip NULLed entries.
3912             */
3913             if (n2 == NULL)
3914                 continue;
3915             /*
3916             * Skip duplicates.
3917             */
3918             for (j = 0; j < initNbSet1; j++) {
3919                 n1 = set1->nodeTab[j];
3920                 if (n1 == n2) {
3921                     goto skip_node;
3922                 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3923                     (n2->type == XML_NAMESPACE_DECL))
3924                 {
3925                     if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3926                         (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3927                         ((xmlNsPtr) n2)->prefix)))
3928                     {
3929                         /*
3930                         * Free the namespace node.
3931                         */
3932                         set2->nodeTab[i] = NULL;
3933                         xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3934                         goto skip_node;
3935                     }
3936                 }
3937             }
3938             /*
3939             * grow the nodeTab if needed
3940             */
3941             if (set1->nodeMax == 0) {
3942                 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3943                     XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3944                 if (set1->nodeTab == NULL) {
3945                     xmlXPathErrMemory(NULL, "merging nodeset\n");
3946                     return(NULL);
3947                 }
3948                 memset(set1->nodeTab, 0,
3949                     XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3950                 set1->nodeMax = XML_NODESET_DEFAULT;
3951             } else if (set1->nodeNr >= set1->nodeMax) {
3952                 xmlNodePtr *temp;
3953
3954                 temp = (xmlNodePtr *) xmlRealloc(
3955                     set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3956                 if (temp == NULL) {
3957                     xmlXPathErrMemory(NULL, "merging nodeset\n");
3958                     return(NULL);
3959                 }
3960                 set1->nodeTab = temp;
3961                 set1->nodeMax *= 2;
3962             }
3963             if (n2->type == XML_NAMESPACE_DECL) {
3964                 xmlNsPtr ns = (xmlNsPtr) n2;
3965
3966                 set1->nodeTab[set1->nodeNr++] =
3967                     xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3968             } else
3969                 set1->nodeTab[set1->nodeNr++] = n2;
3970 skip_node:
3971             {}
3972         }
3973     }
3974     set2->nodeNr = 0;
3975     return(set1);
3976 }
3977
3978 /**
3979  * xmlXPathNodeSetMergeAndClearNoDupls:
3980  * @set1:  the first NodeSet or NULL
3981  * @set2:  the second NodeSet
3982  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3983  *
3984  * Merges two nodesets, all nodes from @set2 are added to @set1
3985  * if @set1 is NULL, a new set is created and copied from @set2.
3986  * Doesn't chack for duplicate nodes. Clears set2.
3987  *
3988  * Returns @set1 once extended or NULL in case of error.
3989  */
3990 static xmlNodeSetPtr
3991 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3992                                     int hasNullEntries)
3993 {
3994     if (set2 == NULL)
3995         return(set1);
3996     if ((set1 == NULL) && (hasNullEntries == 0)) {
3997         /*
3998         * Note that doing a memcpy of the list, namespace nodes are
3999         * just assigned to set1, since set2 is cleared anyway.
4000         */
4001         set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4002         if (set1 == NULL)
4003             return(NULL);
4004         if (set2->nodeNr != 0) {
4005             memcpy(set1->nodeTab, set2->nodeTab,
4006                 set2->nodeNr * sizeof(xmlNodePtr));
4007             set1->nodeNr = set2->nodeNr;
4008         }
4009     } else {
4010         int i;
4011         xmlNodePtr n2;
4012
4013         if (set1 == NULL)
4014             set1 = xmlXPathNodeSetCreate(NULL);
4015         if (set1 == NULL)
4016             return (NULL);
4017
4018         for (i = 0;i < set2->nodeNr;i++) {
4019             n2 = set2->nodeTab[i];
4020             /*
4021             * Skip NULLed entries.
4022             */
4023             if (n2 == NULL)
4024                 continue;
4025             if (set1->nodeMax == 0) {
4026                 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4027                     XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4028                 if (set1->nodeTab == NULL) {
4029                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4030                     return(NULL);
4031                 }
4032                 memset(set1->nodeTab, 0,
4033                     XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4034                 set1->nodeMax = XML_NODESET_DEFAULT;
4035             } else if (set1->nodeNr >= set1->nodeMax) {
4036                 xmlNodePtr *temp;
4037
4038                 temp = (xmlNodePtr *) xmlRealloc(
4039                     set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4040                 if (temp == NULL) {
4041                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4042                     return(NULL);
4043                 }
4044                 set1->nodeTab = temp;
4045                 set1->nodeMax *= 2;
4046             }
4047             set1->nodeTab[set1->nodeNr++] = n2;
4048         }
4049     }
4050     set2->nodeNr = 0;
4051     return(set1);
4052 }
4053
4054 /**
4055  * xmlXPathNodeSetDel:
4056  * @cur:  the initial node set
4057  * @val:  an xmlNodePtr
4058  *
4059  * Removes an xmlNodePtr from an existing NodeSet
4060  */
4061 void
4062 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4063     int i;
4064
4065     if (cur == NULL) return;
4066     if (val == NULL) return;
4067
4068     /*
4069      * find node in nodeTab
4070      */
4071     for (i = 0;i < cur->nodeNr;i++)
4072         if (cur->nodeTab[i] == val) break;
4073
4074     if (i >= cur->nodeNr) {     /* not found */
4075 #ifdef DEBUG
4076         xmlGenericError(xmlGenericErrorContext,
4077                 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4078                 val->name);
4079 #endif
4080         return;
4081     }
4082     if ((cur->nodeTab[i] != NULL) &&
4083         (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4084         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4085     cur->nodeNr--;
4086     for (;i < cur->nodeNr;i++)
4087         cur->nodeTab[i] = cur->nodeTab[i + 1];
4088     cur->nodeTab[cur->nodeNr] = NULL;
4089 }
4090
4091 /**
4092  * xmlXPathNodeSetRemove:
4093  * @cur:  the initial node set
4094  * @val:  the index to remove
4095  *
4096  * Removes an entry from an existing NodeSet list.
4097  */
4098 void
4099 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4100     if (cur == NULL) return;
4101     if (val >= cur->nodeNr) return;
4102     if ((cur->nodeTab[val] != NULL) &&
4103         (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4104         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4105     cur->nodeNr--;
4106     for (;val < cur->nodeNr;val++)
4107         cur->nodeTab[val] = cur->nodeTab[val + 1];
4108     cur->nodeTab[cur->nodeNr] = NULL;
4109 }
4110
4111 /**
4112  * xmlXPathFreeNodeSet:
4113  * @obj:  the xmlNodeSetPtr to free
4114  *
4115  * Free the NodeSet compound (not the actual nodes !).
4116  */
4117 void
4118 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4119     if (obj == NULL) return;
4120     if (obj->nodeTab != NULL) {
4121         int i;
4122
4123         /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4124         for (i = 0;i < obj->nodeNr;i++)
4125             if ((obj->nodeTab[i] != NULL) &&
4126                 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4127                 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4128         xmlFree(obj->nodeTab);
4129     }
4130     xmlFree(obj);
4131 }
4132
4133 /**
4134  * xmlXPathNodeSetClear:
4135  * @set:  the node set to clear
4136  *
4137  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4138  * are feed), but does *not* free the list itself. Sets the length of the
4139  * list to 0.
4140  */
4141 static void
4142 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4143 {
4144     if ((set == NULL) || (set->nodeNr <= 0))
4145         return;
4146     else if (hasNsNodes) {
4147         int i;
4148         xmlNodePtr node;
4149
4150         for (i = 0; i < set->nodeNr; i++) {
4151             node = set->nodeTab[i];
4152             if ((node != NULL) &&
4153                 (node->type == XML_NAMESPACE_DECL))
4154                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4155         }
4156     }
4157     set->nodeNr = 0;
4158 }
4159
4160 /**
4161  * xmlXPathNodeSetClearFromPos:
4162  * @set: the node set to be cleared
4163  * @pos: the start position to clear from
4164  *
4165  * Clears the list from temporary XPath objects (e.g. namespace nodes
4166  * are feed) starting with the entry at @pos, but does *not* free the list
4167  * itself. Sets the length of the list to @pos.
4168  */
4169 static void
4170 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4171 {
4172     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4173         return;
4174     else if ((hasNsNodes)) {
4175         int i;
4176         xmlNodePtr node;
4177
4178         for (i = pos; i < set->nodeNr; i++) {
4179             node = set->nodeTab[i];
4180             if ((node != NULL) &&
4181                 (node->type == XML_NAMESPACE_DECL))
4182                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4183         }
4184     }
4185     set->nodeNr = pos;
4186 }
4187
4188 /**
4189  * xmlXPathFreeValueTree:
4190  * @obj:  the xmlNodeSetPtr to free
4191  *
4192  * Free the NodeSet compound and the actual tree, this is different
4193  * from xmlXPathFreeNodeSet()
4194  */
4195 static void
4196 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4197     int i;
4198
4199     if (obj == NULL) return;
4200
4201     if (obj->nodeTab != NULL) {
4202         for (i = 0;i < obj->nodeNr;i++) {
4203             if (obj->nodeTab[i] != NULL) {
4204                 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4205                     xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4206                 } else {
4207                     xmlFreeNodeList(obj->nodeTab[i]);
4208                 }
4209             }
4210         }
4211         xmlFree(obj->nodeTab);
4212     }
4213     xmlFree(obj);
4214 }
4215
4216 #if defined(DEBUG) || defined(DEBUG_STEP)
4217 /**
4218  * xmlGenericErrorContextNodeSet:
4219  * @output:  a FILE * for the output
4220  * @obj:  the xmlNodeSetPtr to display
4221  *
4222  * Quick display of a NodeSet
4223  */
4224 void
4225 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4226     int i;
4227
4228     if (output == NULL) output = xmlGenericErrorContext;
4229     if (obj == NULL)  {
4230         fprintf(output, "NodeSet == NULL !\n");
4231         return;
4232     }
4233     if (obj->nodeNr == 0) {
4234         fprintf(output, "NodeSet is empty\n");
4235         return;
4236     }
4237     if (obj->nodeTab == NULL) {
4238         fprintf(output, " nodeTab == NULL !\n");
4239         return;
4240     }
4241     for (i = 0; i < obj->nodeNr; i++) {
4242         if (obj->nodeTab[i] == NULL) {
4243             fprintf(output, " NULL !\n");
4244             return;
4245         }
4246         if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4247             (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4248             fprintf(output, " /");
4249         else if (obj->nodeTab[i]->name == NULL)
4250             fprintf(output, " noname!");
4251         else fprintf(output, " %s", obj->nodeTab[i]->name);
4252     }
4253     fprintf(output, "\n");
4254 }
4255 #endif
4256
4257 /**
4258  * xmlXPathNewNodeSet:
4259  * @val:  the NodePtr value
4260  *
4261  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4262  * it with the single Node @val
4263  *
4264  * Returns the newly created object.
4265  */
4266 xmlXPathObjectPtr
4267 xmlXPathNewNodeSet(xmlNodePtr val) {
4268     xmlXPathObjectPtr ret;
4269
4270     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4271     if (ret == NULL) {
4272         xmlXPathErrMemory(NULL, "creating nodeset\n");
4273         return(NULL);
4274     }
4275     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4276     ret->type = XPATH_NODESET;
4277     ret->boolval = 0;
4278     ret->nodesetval = xmlXPathNodeSetCreate(val);
4279     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4280 #ifdef XP_DEBUG_OBJ_USAGE
4281     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4282 #endif
4283     return(ret);
4284 }
4285
4286 /**
4287  * xmlXPathNewValueTree:
4288  * @val:  the NodePtr value
4289  *
4290  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4291  * it with the tree root @val
4292  *
4293  * Returns the newly created object.
4294  */
4295 xmlXPathObjectPtr
4296 xmlXPathNewValueTree(xmlNodePtr val) {
4297     xmlXPathObjectPtr ret;
4298
4299     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4300     if (ret == NULL) {
4301         xmlXPathErrMemory(NULL, "creating result value tree\n");
4302         return(NULL);
4303     }
4304     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4305     ret->type = XPATH_XSLT_TREE;
4306     ret->boolval = 1;
4307     ret->user = (void *) val;
4308     ret->nodesetval = xmlXPathNodeSetCreate(val);
4309 #ifdef XP_DEBUG_OBJ_USAGE
4310     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4311 #endif
4312     return(ret);
4313 }
4314
4315 /**
4316  * xmlXPathNewNodeSetList:
4317  * @val:  an existing NodeSet
4318  *
4319  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4320  * it with the Nodeset @val
4321  *
4322  * Returns the newly created object.
4323  */
4324 xmlXPathObjectPtr
4325 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4326 {
4327     xmlXPathObjectPtr ret;
4328     int i;
4329
4330     if (val == NULL)
4331         ret = NULL;
4332     else if (val->nodeTab == NULL)
4333         ret = xmlXPathNewNodeSet(NULL);
4334     else {
4335         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4336         if (ret)
4337             for (i = 1; i < val->nodeNr; ++i)
4338                 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4339     }
4340
4341     return (ret);
4342 }
4343
4344 /**
4345  * xmlXPathWrapNodeSet:
4346  * @val:  the NodePtr value
4347  *
4348  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4349  *
4350  * Returns the newly created object.
4351  */
4352 xmlXPathObjectPtr
4353 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4354     xmlXPathObjectPtr ret;
4355
4356     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4357     if (ret == NULL) {
4358         xmlXPathErrMemory(NULL, "creating node set object\n");
4359         return(NULL);
4360     }
4361     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4362     ret->type = XPATH_NODESET;
4363     ret->nodesetval = val;
4364 #ifdef XP_DEBUG_OBJ_USAGE
4365     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4366 #endif
4367     return(ret);
4368 }
4369
4370 /**
4371  * xmlXPathFreeNodeSetList:
4372  * @obj:  an existing NodeSetList object
4373  *
4374  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4375  * the list contrary to xmlXPathFreeObject().
4376  */
4377 void
4378 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4379     if (obj == NULL) return;
4380 #ifdef XP_DEBUG_OBJ_USAGE
4381     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4382 #endif
4383     xmlFree(obj);
4384 }
4385
4386 /**
4387  * xmlXPathDifference:
4388  * @nodes1:  a node-set
4389  * @nodes2:  a node-set
4390  *
4391  * Implements the EXSLT - Sets difference() function:
4392  *    node-set set:difference (node-set, node-set)
4393  *
4394  * Returns the difference between the two node sets, or nodes1 if
4395  *         nodes2 is empty
4396  */
4397 xmlNodeSetPtr
4398 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4399     xmlNodeSetPtr ret;
4400     int i, l1;
4401     xmlNodePtr cur;
4402
4403     if (xmlXPathNodeSetIsEmpty(nodes2))
4404         return(nodes1);
4405
4406     ret = xmlXPathNodeSetCreate(NULL);
4407     if (xmlXPathNodeSetIsEmpty(nodes1))
4408         return(ret);
4409
4410     l1 = xmlXPathNodeSetGetLength(nodes1);
4411
4412     for (i = 0; i < l1; i++) {
4413         cur = xmlXPathNodeSetItem(nodes1, i);
4414         if (!xmlXPathNodeSetContains(nodes2, cur))
4415             xmlXPathNodeSetAddUnique(ret, cur);
4416     }
4417     return(ret);
4418 }
4419
4420 /**
4421  * xmlXPathIntersection:
4422  * @nodes1:  a node-set
4423  * @nodes2:  a node-set
4424  *
4425  * Implements the EXSLT - Sets intersection() function:
4426  *    node-set set:intersection (node-set, node-set)
4427  *
4428  * Returns a node set comprising the nodes that are within both the
4429  *         node sets passed as arguments
4430  */
4431 xmlNodeSetPtr
4432 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4433     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4434     int i, l1;
4435     xmlNodePtr cur;
4436
4437     if (ret == NULL)
4438         return(ret);
4439     if (xmlXPathNodeSetIsEmpty(nodes1))
4440         return(ret);
4441     if (xmlXPathNodeSetIsEmpty(nodes2))
4442         return(ret);
4443
4444     l1 = xmlXPathNodeSetGetLength(nodes1);
4445
4446     for (i = 0; i < l1; i++) {
4447         cur = xmlXPathNodeSetItem(nodes1, i);
4448         if (xmlXPathNodeSetContains(nodes2, cur))
4449             xmlXPathNodeSetAddUnique(ret, cur);
4450     }
4451     return(ret);
4452 }
4453
4454 /**
4455  * xmlXPathDistinctSorted:
4456  * @nodes:  a node-set, sorted by document order
4457  *
4458  * Implements the EXSLT - Sets distinct() function:
4459  *    node-set set:distinct (node-set)
4460  *
4461  * Returns a subset of the nodes contained in @nodes, or @nodes if
4462  *         it is empty
4463  */
4464 xmlNodeSetPtr
4465 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4466     xmlNodeSetPtr ret;
4467     xmlHashTablePtr hash;
4468     int i, l;
4469     xmlChar * strval;
4470     xmlNodePtr cur;
4471
4472     if (xmlXPathNodeSetIsEmpty(nodes))
4473         return(nodes);
4474
4475     ret = xmlXPathNodeSetCreate(NULL);
4476     if (ret == NULL)
4477         return(ret);
4478     l = xmlXPathNodeSetGetLength(nodes);
4479     hash = xmlHashCreate (l);
4480     for (i = 0; i < l; i++) {
4481         cur = xmlXPathNodeSetItem(nodes, i);
4482         strval = xmlXPathCastNodeToString(cur);
4483         if (xmlHashLookup(hash, strval) == NULL) {
4484             xmlHashAddEntry(hash, strval, strval);
4485             xmlXPathNodeSetAddUnique(ret, cur);
4486         } else {
4487             xmlFree(strval);
4488         }
4489     }
4490     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4491     return(ret);
4492 }
4493
4494 /**
4495  * xmlXPathDistinct:
4496  * @nodes:  a node-set
4497  *
4498  * Implements the EXSLT - Sets distinct() function:
4499  *    node-set set:distinct (node-set)
4500  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4501  * is called with the sorted node-set
4502  *
4503  * Returns a subset of the nodes contained in @nodes, or @nodes if
4504  *         it is empty
4505  */
4506 xmlNodeSetPtr
4507 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4508     if (xmlXPathNodeSetIsEmpty(nodes))
4509         return(nodes);
4510
4511     xmlXPathNodeSetSort(nodes);
4512     return(xmlXPathDistinctSorted(nodes));
4513 }
4514
4515 /**
4516  * xmlXPathHasSameNodes:
4517  * @nodes1:  a node-set
4518  * @nodes2:  a node-set
4519  *
4520  * Implements the EXSLT - Sets has-same-nodes function:
4521  *    boolean set:has-same-node(node-set, node-set)
4522  *
4523  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4524  *         otherwise
4525  */
4526 int
4527 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4528     int i, l;
4529     xmlNodePtr cur;
4530
4531     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4532         xmlXPathNodeSetIsEmpty(nodes2))
4533         return(0);
4534
4535     l = xmlXPathNodeSetGetLength(nodes1);
4536     for (i = 0; i < l; i++) {
4537         cur = xmlXPathNodeSetItem(nodes1, i);
4538         if (xmlXPathNodeSetContains(nodes2, cur))
4539             return(1);
4540     }
4541     return(0);
4542 }
4543
4544 /**
4545  * xmlXPathNodeLeadingSorted:
4546  * @nodes: a node-set, sorted by document order
4547  * @node: a node
4548  *
4549  * Implements the EXSLT - Sets leading() function:
4550  *    node-set set:leading (node-set, node-set)
4551  *
4552  * Returns the nodes in @nodes that precede @node in document order,
4553  *         @nodes if @node is NULL or an empty node-set if @nodes
4554  *         doesn't contain @node
4555  */
4556 xmlNodeSetPtr
4557 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4558     int i, l;
4559     xmlNodePtr cur;
4560     xmlNodeSetPtr ret;
4561
4562     if (node == NULL)
4563         return(nodes);
4564
4565     ret = xmlXPathNodeSetCreate(NULL);
4566     if (ret == NULL)
4567         return(ret);
4568     if (xmlXPathNodeSetIsEmpty(nodes) ||
4569         (!xmlXPathNodeSetContains(nodes, node)))
4570         return(ret);
4571
4572     l = xmlXPathNodeSetGetLength(nodes);
4573     for (i = 0; i < l; i++) {
4574         cur = xmlXPathNodeSetItem(nodes, i);
4575         if (cur == node)
4576             break;
4577         xmlXPathNodeSetAddUnique(ret, cur);
4578     }
4579     return(ret);
4580 }
4581
4582 /**
4583  * xmlXPathNodeLeading:
4584  * @nodes:  a node-set
4585  * @node:  a node
4586  *
4587  * Implements the EXSLT - Sets leading() function:
4588  *    node-set set:leading (node-set, node-set)
4589  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4590  * is called.
4591  *
4592  * Returns the nodes in @nodes that precede @node in document order,
4593  *         @nodes if @node is NULL or an empty node-set if @nodes
4594  *         doesn't contain @node
4595  */
4596 xmlNodeSetPtr
4597 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4598     xmlXPathNodeSetSort(nodes);
4599     return(xmlXPathNodeLeadingSorted(nodes, node));
4600 }
4601
4602 /**
4603  * xmlXPathLeadingSorted:
4604  * @nodes1:  a node-set, sorted by document order
4605  * @nodes2:  a node-set, sorted by document order
4606  *
4607  * Implements the EXSLT - Sets leading() function:
4608  *    node-set set:leading (node-set, node-set)
4609  *
4610  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4611  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4612  *         an empty node-set if @nodes1 doesn't contain @nodes2
4613  */
4614 xmlNodeSetPtr
4615 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4616     if (xmlXPathNodeSetIsEmpty(nodes2))
4617         return(nodes1);
4618     return(xmlXPathNodeLeadingSorted(nodes1,
4619                                      xmlXPathNodeSetItem(nodes2, 1)));
4620 }
4621
4622 /**
4623  * xmlXPathLeading:
4624  * @nodes1:  a node-set
4625  * @nodes2:  a node-set
4626  *
4627  * Implements the EXSLT - Sets leading() function:
4628  *    node-set set:leading (node-set, node-set)
4629  * @nodes1 and @nodes2 are sorted by document order, then
4630  * #exslSetsLeadingSorted is called.
4631  *
4632  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4633  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4634  *         an empty node-set if @nodes1 doesn't contain @nodes2
4635  */
4636 xmlNodeSetPtr
4637 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4638     if (xmlXPathNodeSetIsEmpty(nodes2))
4639         return(nodes1);
4640     if (xmlXPathNodeSetIsEmpty(nodes1))
4641         return(xmlXPathNodeSetCreate(NULL));
4642     xmlXPathNodeSetSort(nodes1);
4643     xmlXPathNodeSetSort(nodes2);
4644     return(xmlXPathNodeLeadingSorted(nodes1,
4645                                      xmlXPathNodeSetItem(nodes2, 1)));
4646 }
4647
4648 /**
4649  * xmlXPathNodeTrailingSorted:
4650  * @nodes: a node-set, sorted by document order
4651  * @node: a node
4652  *
4653  * Implements the EXSLT - Sets trailing() function:
4654  *    node-set set:trailing (node-set, node-set)
4655  *
4656  * Returns the nodes in @nodes that follow @node in document order,
4657  *         @nodes if @node is NULL or an empty node-set if @nodes
4658  *         doesn't contain @node
4659  */
4660 xmlNodeSetPtr
4661 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4662     int i, l;
4663     xmlNodePtr cur;
4664     xmlNodeSetPtr ret;
4665
4666     if (node == NULL)
4667         return(nodes);
4668
4669     ret = xmlXPathNodeSetCreate(NULL);
4670     if (ret == NULL)
4671         return(ret);
4672     if (xmlXPathNodeSetIsEmpty(nodes) ||
4673         (!xmlXPathNodeSetContains(nodes, node)))
4674         return(ret);
4675
4676     l = xmlXPathNodeSetGetLength(nodes);
4677     for (i = l - 1; i >= 0; i--) {
4678         cur = xmlXPathNodeSetItem(nodes, i);
4679         if (cur == node)
4680             break;
4681         xmlXPathNodeSetAddUnique(ret, cur);
4682     }
4683     xmlXPathNodeSetSort(ret);   /* bug 413451 */
4684     return(ret);
4685 }
4686
4687 /**
4688  * xmlXPathNodeTrailing:
4689  * @nodes:  a node-set
4690  * @node:  a node
4691  *
4692  * Implements the EXSLT - Sets trailing() function:
4693  *    node-set set:trailing (node-set, node-set)
4694  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4695  * is called.
4696  *
4697  * Returns the nodes in @nodes that follow @node in document order,
4698  *         @nodes if @node is NULL or an empty node-set if @nodes
4699  *         doesn't contain @node
4700  */
4701 xmlNodeSetPtr
4702 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4703     xmlXPathNodeSetSort(nodes);
4704     return(xmlXPathNodeTrailingSorted(nodes, node));
4705 }
4706
4707 /**
4708  * xmlXPathTrailingSorted:
4709  * @nodes1:  a node-set, sorted by document order
4710  * @nodes2:  a node-set, sorted by document order
4711  *
4712  * Implements the EXSLT - Sets trailing() function:
4713  *    node-set set:trailing (node-set, node-set)
4714  *
4715  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4716  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4717  *         an empty node-set if @nodes1 doesn't contain @nodes2
4718  */
4719 xmlNodeSetPtr
4720 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4721     if (xmlXPathNodeSetIsEmpty(nodes2))
4722         return(nodes1);
4723     return(xmlXPathNodeTrailingSorted(nodes1,
4724                                       xmlXPathNodeSetItem(nodes2, 0)));
4725 }
4726
4727 /**
4728  * xmlXPathTrailing:
4729  * @nodes1:  a node-set
4730  * @nodes2:  a node-set
4731  *
4732  * Implements the EXSLT - Sets trailing() function:
4733  *    node-set set:trailing (node-set, node-set)
4734  * @nodes1 and @nodes2 are sorted by document order, then
4735  * #xmlXPathTrailingSorted is called.
4736  *
4737  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4738  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4739  *         an empty node-set if @nodes1 doesn't contain @nodes2
4740  */
4741 xmlNodeSetPtr
4742 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4743     if (xmlXPathNodeSetIsEmpty(nodes2))
4744         return(nodes1);
4745     if (xmlXPathNodeSetIsEmpty(nodes1))
4746         return(xmlXPathNodeSetCreate(NULL));
4747     xmlXPathNodeSetSort(nodes1);
4748     xmlXPathNodeSetSort(nodes2);
4749     return(xmlXPathNodeTrailingSorted(nodes1,
4750                                       xmlXPathNodeSetItem(nodes2, 0)));
4751 }
4752
4753 /************************************************************************
4754  *                                                                      *
4755  *              Routines to handle extra functions                      *
4756  *                                                                      *
4757  ************************************************************************/
4758
4759 /**
4760  * xmlXPathRegisterFunc:
4761  * @ctxt:  the XPath context
4762  * @name:  the function name
4763  * @f:  the function implementation or NULL
4764  *
4765  * Register a new function. If @f is NULL it unregisters the function
4766  *
4767  * Returns 0 in case of success, -1 in case of error
4768  */
4769 int
4770 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4771                      xmlXPathFunction f) {
4772     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4773 }
4774
4775 /**
4776  * xmlXPathRegisterFuncNS:
4777  * @ctxt:  the XPath context
4778  * @name:  the function name
4779  * @ns_uri:  the function namespace URI
4780  * @f:  the function implementation or NULL
4781  *
4782  * Register a new function. If @f is NULL it unregisters the function
4783  *
4784  * Returns 0 in case of success, -1 in case of error
4785  */
4786 int
4787 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4788                        const xmlChar *ns_uri, xmlXPathFunction f) {
4789     if (ctxt == NULL)
4790         return(-1);
4791     if (name == NULL)
4792         return(-1);
4793
4794     if (ctxt->funcHash == NULL)
4795         ctxt->funcHash = xmlHashCreate(0);
4796     if (ctxt->funcHash == NULL)
4797         return(-1);
4798     if (f == NULL)
4799         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4800     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4801 }
4802
4803 /**
4804  * xmlXPathRegisterFuncLookup:
4805  * @ctxt:  the XPath context
4806  * @f:  the lookup function
4807  * @funcCtxt:  the lookup data
4808  *
4809  * Registers an external mechanism to do function lookup.
4810  */
4811 void
4812 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4813                             xmlXPathFuncLookupFunc f,
4814                             void *funcCtxt) {
4815     if (ctxt == NULL)
4816         return;
4817     ctxt->funcLookupFunc = f;
4818     ctxt->funcLookupData = funcCtxt;
4819 }
4820
4821 /**
4822  * xmlXPathFunctionLookup:
4823  * @ctxt:  the XPath context
4824  * @name:  the function name
4825  *
4826  * Search in the Function array of the context for the given
4827  * function.
4828  *
4829  * Returns the xmlXPathFunction or NULL if not found
4830  */
4831 xmlXPathFunction
4832 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4833     if (ctxt == NULL)
4834         return (NULL);
4835
4836     if (ctxt->funcLookupFunc != NULL) {
4837         xmlXPathFunction ret;
4838         xmlXPathFuncLookupFunc f;
4839
4840         f = ctxt->funcLookupFunc;
4841         ret = f(ctxt->funcLookupData, name, NULL);
4842         if (ret != NULL)
4843             return(ret);
4844     }
4845     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4846 }
4847
4848 /**
4849  * xmlXPathFunctionLookupNS:
4850  * @ctxt:  the XPath context
4851  * @name:  the function name
4852  * @ns_uri:  the function namespace URI
4853  *
4854  * Search in the Function array of the context for the given
4855  * function.
4856  *
4857  * Returns the xmlXPathFunction or NULL if not found
4858  */
4859 xmlXPathFunction
4860 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4861                          const xmlChar *ns_uri) {
4862     xmlXPathFunction ret;
4863
4864     if (ctxt == NULL)
4865         return(NULL);
4866     if (name == NULL)
4867         return(NULL);
4868
4869     if (ctxt->funcLookupFunc != NULL) {
4870         xmlXPathFuncLookupFunc f;
4871
4872         f = ctxt->funcLookupFunc;
4873         ret = f(ctxt->funcLookupData, name, ns_uri);
4874         if (ret != NULL)
4875             return(ret);
4876     }
4877
4878     if (ctxt->funcHash == NULL)
4879         return(NULL);
4880
4881     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4882     return(ret);
4883 }
4884
4885 /**
4886  * xmlXPathRegisteredFuncsCleanup:
4887  * @ctxt:  the XPath context
4888  *
4889  * Cleanup the XPath context data associated to registered functions
4890  */
4891 void
4892 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4893     if (ctxt == NULL)
4894         return;
4895
4896     xmlHashFree(ctxt->funcHash, NULL);
4897     ctxt->funcHash = NULL;
4898 }
4899
4900 /************************************************************************
4901  *                                                                      *
4902  *                      Routines to handle Variables                    *
4903  *                                                                      *
4904  ************************************************************************/
4905
4906 /**
4907  * xmlXPathRegisterVariable:
4908  * @ctxt:  the XPath context
4909  * @name:  the variable name
4910  * @value:  the variable value or NULL
4911  *
4912  * Register a new variable value. If @value is NULL it unregisters
4913  * the variable
4914  *
4915  * Returns 0 in case of success, -1 in case of error
4916  */
4917 int
4918 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4919                          xmlXPathObjectPtr value) {
4920     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4921 }
4922
4923 /**
4924  * xmlXPathRegisterVariableNS:
4925  * @ctxt:  the XPath context
4926  * @name:  the variable name
4927  * @ns_uri:  the variable namespace URI
4928  * @value:  the variable value or NULL
4929  *
4930  * Register a new variable value. If @value is NULL it unregisters
4931  * the variable
4932  *
4933  * Returns 0 in case of success, -1 in case of error
4934  */
4935 int
4936 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4937                            const xmlChar *ns_uri,
4938                            xmlXPathObjectPtr value) {
4939     if (ctxt == NULL)
4940         return(-1);
4941     if (name == NULL)
4942         return(-1);
4943
4944     if (ctxt->varHash == NULL)
4945         ctxt->varHash = xmlHashCreate(0);
4946     if (ctxt->varHash == NULL)
4947         return(-1);
4948     if (value == NULL)
4949         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4950                                    (xmlHashDeallocator)xmlXPathFreeObject));
4951     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4952                                (void *) value,
4953                                (xmlHashDeallocator)xmlXPathFreeObject));
4954 }
4955
4956 /**
4957  * xmlXPathRegisterVariableLookup:
4958  * @ctxt:  the XPath context
4959  * @f:  the lookup function
4960  * @data:  the lookup data
4961  *
4962  * register an external mechanism to do variable lookup
4963  */
4964 void
4965 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4966          xmlXPathVariableLookupFunc f, void *data) {
4967     if (ctxt == NULL)
4968         return;
4969     ctxt->varLookupFunc = f;
4970     ctxt->varLookupData = data;
4971 }
4972
4973 /**
4974  * xmlXPathVariableLookup:
4975  * @ctxt:  the XPath context
4976  * @name:  the variable name
4977  *
4978  * Search in the Variable array of the context for the given
4979  * variable value.
4980  *
4981  * Returns a copy of the value or NULL if not found
4982  */
4983 xmlXPathObjectPtr
4984 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4985     if (ctxt == NULL)
4986         return(NULL);
4987
4988     if (ctxt->varLookupFunc != NULL) {
4989         xmlXPathObjectPtr ret;
4990
4991         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4992                 (ctxt->varLookupData, name, NULL);
4993         return(ret);
4994     }
4995     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4996 }
4997
4998 /**
4999  * xmlXPathVariableLookupNS:
5000  * @ctxt:  the XPath context
5001  * @name:  the variable name
5002  * @ns_uri:  the variable namespace URI
5003  *
5004  * Search in the Variable array of the context for the given
5005  * variable value.
5006  *
5007  * Returns the a copy of the value or NULL if not found
5008  */
5009 xmlXPathObjectPtr
5010 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5011                          const xmlChar *ns_uri) {
5012     if (ctxt == NULL)
5013         return(NULL);
5014
5015     if (ctxt->varLookupFunc != NULL) {
5016         xmlXPathObjectPtr ret;
5017
5018         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5019                 (ctxt->varLookupData, name, ns_uri);
5020         if (ret != NULL) return(ret);
5021     }
5022
5023     if (ctxt->varHash == NULL)
5024         return(NULL);
5025     if (name == NULL)
5026         return(NULL);
5027
5028     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5029                 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5030 }
5031
5032 /**
5033  * xmlXPathRegisteredVariablesCleanup:
5034  * @ctxt:  the XPath context
5035  *
5036  * Cleanup the XPath context data associated to registered variables
5037  */
5038 void
5039 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5040     if (ctxt == NULL)
5041         return;
5042
5043     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5044     ctxt->varHash = NULL;
5045 }
5046
5047 /**
5048  * xmlXPathRegisterNs:
5049  * @ctxt:  the XPath context
5050  * @prefix:  the namespace prefix cannot be NULL or empty string
5051  * @ns_uri:  the namespace name
5052  *
5053  * Register a new namespace. If @ns_uri is NULL it unregisters
5054  * the namespace
5055  *
5056  * Returns 0 in case of success, -1 in case of error
5057  */
5058 int
5059 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5060                            const xmlChar *ns_uri) {
5061     if (ctxt == NULL)
5062         return(-1);
5063     if (prefix == NULL)
5064         return(-1);
5065     if (prefix[0] == 0)
5066         return(-1);
5067
5068     if (ctxt->nsHash == NULL)
5069         ctxt->nsHash = xmlHashCreate(10);
5070     if (ctxt->nsHash == NULL)
5071         return(-1);
5072     if (ns_uri == NULL)
5073         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5074                                   (xmlHashDeallocator)xmlFree));
5075     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5076                               (xmlHashDeallocator)xmlFree));
5077 }
5078
5079 /**
5080  * xmlXPathNsLookup:
5081  * @ctxt:  the XPath context
5082  * @prefix:  the namespace prefix value
5083  *
5084  * Search in the namespace declaration array of the context for the given
5085  * namespace name associated to the given prefix
5086  *
5087  * Returns the value or NULL if not found
5088  */
5089 const xmlChar *
5090 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5091     if (ctxt == NULL)
5092         return(NULL);
5093     if (prefix == NULL)
5094         return(NULL);
5095
5096 #ifdef XML_XML_NAMESPACE
5097     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5098         return(XML_XML_NAMESPACE);
5099 #endif
5100
5101     if (ctxt->namespaces != NULL) {
5102         int i;
5103
5104         for (i = 0;i < ctxt->nsNr;i++) {
5105             if ((ctxt->namespaces[i] != NULL) &&
5106                 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5107                 return(ctxt->namespaces[i]->href);
5108         }
5109     }
5110
5111     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5112 }
5113
5114 /**
5115  * xmlXPathRegisteredNsCleanup:
5116  * @ctxt:  the XPath context
5117  *
5118  * Cleanup the XPath context data associated to registered variables
5119  */
5120 void
5121 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5122     if (ctxt == NULL)
5123         return;
5124
5125     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5126     ctxt->nsHash = NULL;
5127 }
5128
5129 /************************************************************************
5130  *                                                                      *
5131  *                      Routines to handle Values                       *
5132  *                                                                      *
5133  ************************************************************************/
5134
5135 /* Allocations are terrible, one needs to optimize all this !!! */
5136
5137 /**
5138  * xmlXPathNewFloat:
5139  * @val:  the double value
5140  *
5141  * Create a new xmlXPathObjectPtr of type double and of value @val
5142  *
5143  * Returns the newly created object.
5144  */
5145 xmlXPathObjectPtr
5146 xmlXPathNewFloat(double val) {
5147     xmlXPathObjectPtr ret;
5148
5149     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5150     if (ret == NULL) {
5151         xmlXPathErrMemory(NULL, "creating float object\n");
5152         return(NULL);
5153     }
5154     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5155     ret->type = XPATH_NUMBER;
5156     ret->floatval = val;
5157 #ifdef XP_DEBUG_OBJ_USAGE
5158     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5159 #endif
5160     return(ret);
5161 }
5162
5163 /**
5164  * xmlXPathNewBoolean:
5165  * @val:  the boolean value
5166  *
5167  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5168  *
5169  * Returns the newly created object.
5170  */
5171 xmlXPathObjectPtr
5172 xmlXPathNewBoolean(int val) {
5173     xmlXPathObjectPtr ret;
5174
5175     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5176     if (ret == NULL) {
5177         xmlXPathErrMemory(NULL, "creating boolean object\n");
5178         return(NULL);
5179     }
5180     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5181     ret->type = XPATH_BOOLEAN;
5182     ret->boolval = (val != 0);
5183 #ifdef XP_DEBUG_OBJ_USAGE
5184     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5185 #endif
5186     return(ret);
5187 }
5188
5189 /**
5190  * xmlXPathNewString:
5191  * @val:  the xmlChar * value
5192  *
5193  * Create a new xmlXPathObjectPtr of type string and of value @val
5194  *
5195  * Returns the newly created object.
5196  */
5197 xmlXPathObjectPtr
5198 xmlXPathNewString(const xmlChar *val) {
5199     xmlXPathObjectPtr ret;
5200
5201     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5202     if (ret == NULL) {
5203         xmlXPathErrMemory(NULL, "creating string object\n");
5204         return(NULL);
5205     }
5206     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5207     ret->type = XPATH_STRING;
5208     if (val != NULL)
5209         ret->stringval = xmlStrdup(val);
5210     else
5211         ret->stringval = xmlStrdup((const xmlChar *)"");
5212 #ifdef XP_DEBUG_OBJ_USAGE
5213     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5214 #endif
5215     return(ret);
5216 }
5217
5218 /**
5219  * xmlXPathWrapString:
5220  * @val:  the xmlChar * value
5221  *
5222  * Wraps the @val string into an XPath object.
5223  *
5224  * Returns the newly created object.
5225  */
5226 xmlXPathObjectPtr
5227 xmlXPathWrapString (xmlChar *val) {
5228     xmlXPathObjectPtr ret;
5229
5230     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5231     if (ret == NULL) {
5232         xmlXPathErrMemory(NULL, "creating string object\n");
5233         return(NULL);
5234     }
5235     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5236     ret->type = XPATH_STRING;
5237     ret->stringval = val;
5238 #ifdef XP_DEBUG_OBJ_USAGE
5239     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5240 #endif
5241     return(ret);
5242 }
5243
5244 /**
5245  * xmlXPathNewCString:
5246  * @val:  the char * value
5247  *
5248  * Create a new xmlXPathObjectPtr of type string and of value @val
5249  *
5250  * Returns the newly created object.
5251  */
5252 xmlXPathObjectPtr
5253 xmlXPathNewCString(const char *val) {
5254     xmlXPathObjectPtr ret;
5255
5256     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5257     if (ret == NULL) {
5258         xmlXPathErrMemory(NULL, "creating string object\n");
5259         return(NULL);
5260     }
5261     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5262     ret->type = XPATH_STRING;
5263     ret->stringval = xmlStrdup(BAD_CAST val);
5264 #ifdef XP_DEBUG_OBJ_USAGE
5265     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5266 #endif
5267     return(ret);
5268 }
5269
5270 /**
5271  * xmlXPathWrapCString:
5272  * @val:  the char * value
5273  *
5274  * Wraps a string into an XPath object.
5275  *
5276  * Returns the newly created object.
5277  */
5278 xmlXPathObjectPtr
5279 xmlXPathWrapCString (char * val) {
5280     return(xmlXPathWrapString((xmlChar *)(val)));
5281 }
5282
5283 /**
5284  * xmlXPathWrapExternal:
5285  * @val:  the user data
5286  *
5287  * Wraps the @val data into an XPath object.
5288  *
5289  * Returns the newly created object.
5290  */
5291 xmlXPathObjectPtr
5292 xmlXPathWrapExternal (void *val) {
5293     xmlXPathObjectPtr ret;
5294
5295     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5296     if (ret == NULL) {
5297         xmlXPathErrMemory(NULL, "creating user object\n");
5298         return(NULL);
5299     }
5300     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5301     ret->type = XPATH_USERS;
5302     ret->user = val;
5303 #ifdef XP_DEBUG_OBJ_USAGE
5304     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5305 #endif
5306     return(ret);
5307 }
5308
5309 /**
5310  * xmlXPathObjectCopy:
5311  * @val:  the original object
5312  *
5313  * allocate a new copy of a given object
5314  *
5315  * Returns the newly created object.
5316  */
5317 xmlXPathObjectPtr
5318 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5319     xmlXPathObjectPtr ret;
5320
5321     if (val == NULL)
5322         return(NULL);
5323
5324     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5325     if (ret == NULL) {
5326         xmlXPathErrMemory(NULL, "copying object\n");
5327         return(NULL);
5328     }
5329     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5330 #ifdef XP_DEBUG_OBJ_USAGE
5331     xmlXPathDebugObjUsageRequested(NULL, val->type);
5332 #endif
5333     switch (val->type) {
5334         case XPATH_BOOLEAN:
5335         case XPATH_NUMBER:
5336         case XPATH_POINT:
5337         case XPATH_RANGE:
5338             break;
5339         case XPATH_STRING:
5340             ret->stringval = xmlStrdup(val->stringval);
5341             break;
5342         case XPATH_XSLT_TREE:
5343 #if 0
5344 /*
5345   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5346   this previous handling is no longer correct, and can cause some serious
5347   problems (ref. bug 145547)
5348 */
5349             if ((val->nodesetval != NULL) &&
5350                 (val->nodesetval->nodeTab != NULL)) {
5351                 xmlNodePtr cur, tmp;
5352                 xmlDocPtr top;
5353
5354                 ret->boolval = 1;
5355                 top =  xmlNewDoc(NULL);
5356                 top->name = (char *)
5357                     xmlStrdup(val->nodesetval->nodeTab[0]->name);
5358                 ret->user = top;
5359                 if (top != NULL) {
5360                     top->doc = top;
5361                     cur = val->nodesetval->nodeTab[0]->children;
5362                     while (cur != NULL) {
5363                         tmp = xmlDocCopyNode(cur, top, 1);
5364                         xmlAddChild((xmlNodePtr) top, tmp);
5365                         cur = cur->next;
5366                     }
5367                 }
5368
5369                 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5370             } else
5371                 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5372             /* Deallocate the copied tree value */
5373             break;
5374 #endif
5375         case XPATH_NODESET:
5376             ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5377             /* Do not deallocate the copied tree value */
5378             ret->boolval = 0;
5379             break;
5380         case XPATH_LOCATIONSET:
5381 #ifdef LIBXML_XPTR_ENABLED
5382         {
5383             xmlLocationSetPtr loc = val->user;
5384             ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5385             break;
5386         }
5387 #endif
5388         case XPATH_USERS:
5389             ret->user = val->user;
5390             break;
5391         case XPATH_UNDEFINED:
5392             xmlGenericError(xmlGenericErrorContext,
5393                     "xmlXPathObjectCopy: unsupported type %d\n",
5394                     val->type);
5395             break;
5396     }
5397     return(ret);
5398 }
5399
5400 /**
5401  * xmlXPathFreeObject:
5402  * @obj:  the object to free
5403  *
5404  * Free up an xmlXPathObjectPtr object.
5405  */
5406 void
5407 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5408     if (obj == NULL) return;
5409     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5410         if (obj->boolval) {
5411 #if 0
5412             if (obj->user != NULL) {
5413                 xmlXPathFreeNodeSet(obj->nodesetval);
5414                 xmlFreeNodeList((xmlNodePtr) obj->user);
5415             } else
5416 #endif
5417             obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5418             if (obj->nodesetval != NULL)
5419                 xmlXPathFreeValueTree(obj->nodesetval);
5420         } else {
5421             if (obj->nodesetval != NULL)
5422                 xmlXPathFreeNodeSet(obj->nodesetval);
5423         }
5424 #ifdef LIBXML_XPTR_ENABLED
5425     } else if (obj->type == XPATH_LOCATIONSET) {
5426         if (obj->user != NULL)
5427             xmlXPtrFreeLocationSet(obj->user);
5428 #endif
5429     } else if (obj->type == XPATH_STRING) {
5430         if (obj->stringval != NULL)
5431             xmlFree(obj->stringval);
5432     }
5433 #ifdef XP_DEBUG_OBJ_USAGE
5434     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5435 #endif
5436     xmlFree(obj);
5437 }
5438
5439 /**
5440  * xmlXPathReleaseObject:
5441  * @obj:  the xmlXPathObjectPtr to free or to cache
5442  *
5443  * Depending on the state of the cache this frees the given
5444  * XPath object or stores it in the cache.
5445  */
5446 static void
5447 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5448 {
5449 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5450         sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5451     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5452
5453 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5454
5455     if (obj == NULL)
5456         return;
5457     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5458          xmlXPathFreeObject(obj);
5459     } else {
5460         xmlXPathContextCachePtr cache =
5461             (xmlXPathContextCachePtr) ctxt->cache;
5462
5463         switch (obj->type) {
5464             case XPATH_NODESET:
5465             case XPATH_XSLT_TREE:
5466                 if (obj->nodesetval != NULL) {
5467                     if (obj->boolval) {
5468                         /*
5469                         * It looks like the @boolval is used for
5470                         * evaluation if this an XSLT Result Tree Fragment.
5471                         * TODO: Check if this assumption is correct.
5472                         */
5473                         obj->type = XPATH_XSLT_TREE; /* just for debugging */
5474                         xmlXPathFreeValueTree(obj->nodesetval);
5475                         obj->nodesetval = NULL;
5476                     } else if ((obj->nodesetval->nodeMax <= 40) &&
5477                         (XP_CACHE_WANTS(cache->nodesetObjs,
5478                                         cache->maxNodeset)))
5479                     {
5480                         XP_CACHE_ADD(cache->nodesetObjs, obj);
5481                         goto obj_cached;
5482                     } else {
5483                         xmlXPathFreeNodeSet(obj->nodesetval);
5484                         obj->nodesetval = NULL;
5485                     }
5486                 }
5487                 break;
5488             case XPATH_STRING:
5489                 if (obj->stringval != NULL)
5490                     xmlFree(obj->stringval);
5491
5492                 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5493                     XP_CACHE_ADD(cache->stringObjs, obj);
5494                     goto obj_cached;
5495                 }
5496                 break;
5497             case XPATH_BOOLEAN:
5498                 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5499                     XP_CACHE_ADD(cache->booleanObjs, obj);
5500                     goto obj_cached;
5501                 }
5502                 break;
5503             case XPATH_NUMBER:
5504                 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5505                     XP_CACHE_ADD(cache->numberObjs, obj);
5506                     goto obj_cached;
5507                 }
5508                 break;
5509 #ifdef LIBXML_XPTR_ENABLED
5510             case XPATH_LOCATIONSET:
5511                 if (obj->user != NULL) {
5512                     xmlXPtrFreeLocationSet(obj->user);
5513                 }
5514                 goto free_obj;
5515 #endif
5516             default:
5517                 goto free_obj;
5518         }
5519
5520         /*
5521         * Fallback to adding to the misc-objects slot.
5522         */
5523         if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5524             XP_CACHE_ADD(cache->miscObjs, obj);
5525         } else
5526             goto free_obj;
5527
5528 obj_cached:
5529
5530 #ifdef XP_DEBUG_OBJ_USAGE
5531         xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5532 #endif
5533
5534         if (obj->nodesetval != NULL) {
5535             xmlNodeSetPtr tmpset = obj->nodesetval;
5536
5537             /*
5538             * TODO: Due to those nasty ns-nodes, we need to traverse
5539             *  the list and free the ns-nodes.
5540             * URGENT TODO: Check if it's actually slowing things down.
5541             *  Maybe we shouldn't try to preserve the list.
5542             */
5543             if (tmpset->nodeNr > 1) {
5544                 int i;
5545                 xmlNodePtr node;
5546
5547                 for (i = 0; i < tmpset->nodeNr; i++) {
5548                     node = tmpset->nodeTab[i];
5549                     if ((node != NULL) &&
5550                         (node->type == XML_NAMESPACE_DECL))
5551                     {
5552                         xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5553                     }
5554                 }
5555             } else if (tmpset->nodeNr == 1) {
5556                 if ((tmpset->nodeTab[0] != NULL) &&
5557                     (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5558                     xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5559             }
5560             tmpset->nodeNr = 0;
5561             memset(obj, 0, sizeof(xmlXPathObject));
5562             obj->nodesetval = tmpset;
5563         } else
5564             memset(obj, 0, sizeof(xmlXPathObject));
5565
5566         return;
5567
5568 free_obj:
5569         /*
5570         * Cache is full; free the object.
5571         */
5572         if (obj->nodesetval != NULL)
5573             xmlXPathFreeNodeSet(obj->nodesetval);
5574 #ifdef XP_DEBUG_OBJ_USAGE
5575         xmlXPathDebugObjUsageReleased(NULL, obj->type);
5576 #endif
5577         xmlFree(obj);
5578     }
5579     return;
5580 }
5581
5582
5583 /************************************************************************
5584  *                                                                      *
5585  *                      Type Casting Routines                           *
5586  *                                                                      *
5587  ************************************************************************/
5588
5589 /**
5590  * xmlXPathCastBooleanToString:
5591  * @val:  a boolean
5592  *
5593  * Converts a boolean to its string value.
5594  *
5595  * Returns a newly allocated string.
5596  */
5597 xmlChar *
5598 xmlXPathCastBooleanToString (int val) {
5599     xmlChar *ret;
5600     if (val)
5601         ret = xmlStrdup((const xmlChar *) "true");
5602     else
5603         ret = xmlStrdup((const xmlChar *) "false");
5604     return(ret);
5605 }
5606
5607 /**
5608  * xmlXPathCastNumberToString:
5609  * @val:  a number
5610  *
5611  * Converts a number to its string value.
5612  *
5613  * Returns a newly allocated string.
5614  */
5615 xmlChar *
5616 xmlXPathCastNumberToString (double val) {
5617     xmlChar *ret;
5618     switch (xmlXPathIsInf(val)) {
5619     case 1:
5620         ret = xmlStrdup((const xmlChar *) "Infinity");
5621         break;
5622     case -1:
5623         ret = xmlStrdup((const xmlChar *) "-Infinity");
5624         break;
5625     default:
5626         if (xmlXPathIsNaN(val)) {
5627             ret = xmlStrdup((const xmlChar *) "NaN");
5628         } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5629             ret = xmlStrdup((const xmlChar *) "0");
5630         } else {
5631             /* could be improved */
5632             char buf[100];
5633             xmlXPathFormatNumber(val, buf, 99);
5634             buf[99] = 0;
5635             ret = xmlStrdup((const xmlChar *) buf);
5636         }
5637     }
5638     return(ret);
5639 }
5640
5641 /**
5642  * xmlXPathCastNodeToString:
5643  * @node:  a node
5644  *
5645  * Converts a node to its string value.
5646  *
5647  * Returns a newly allocated string.
5648  */
5649 xmlChar *
5650 xmlXPathCastNodeToString (xmlNodePtr node) {
5651 xmlChar *ret;
5652     if ((ret = xmlNodeGetContent(node)) == NULL)
5653         ret = xmlStrdup((const xmlChar *) "");
5654     return(ret);
5655 }
5656
5657 /**
5658  * xmlXPathCastNodeSetToString:
5659  * @ns:  a node-set
5660  *
5661  * Converts a node-set to its string value.
5662  *
5663  * Returns a newly allocated string.
5664  */
5665 xmlChar *
5666 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5667     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5668         return(xmlStrdup((const xmlChar *) ""));
5669
5670     if (ns->nodeNr > 1)
5671         xmlXPathNodeSetSort(ns);
5672     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5673 }
5674
5675 /**
5676  * xmlXPathCastToString:
5677  * @val:  an XPath object
5678  *
5679  * Converts an existing object to its string() equivalent
5680  *
5681  * Returns the allocated string value of the object, NULL in case of error.
5682  *         It's up to the caller to free the string memory with xmlFree().
5683  */
5684 xmlChar *
5685 xmlXPathCastToString(xmlXPathObjectPtr val) {
5686     xmlChar *ret = NULL;
5687
5688     if (val == NULL)
5689         return(xmlStrdup((const xmlChar *) ""));
5690     switch (val->type) {
5691         case XPATH_UNDEFINED:
5692 #ifdef DEBUG_EXPR
5693             xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5694 #endif
5695             ret = xmlStrdup((const xmlChar *) "");
5696             break;
5697         case XPATH_NODESET:
5698         case XPATH_XSLT_TREE:
5699             ret = xmlXPathCastNodeSetToString(val->nodesetval);
5700             break;
5701         case XPATH_STRING:
5702             return(xmlStrdup(val->stringval));
5703         case XPATH_BOOLEAN:
5704             ret = xmlXPathCastBooleanToString(val->boolval);
5705             break;
5706         case XPATH_NUMBER: {
5707             ret = xmlXPathCastNumberToString(val->floatval);
5708             break;
5709         }
5710         case XPATH_USERS:
5711         case XPATH_POINT:
5712         case XPATH_RANGE:
5713         case XPATH_LOCATIONSET:
5714             TODO
5715             ret = xmlStrdup((const xmlChar *) "");
5716             break;
5717     }
5718     return(ret);
5719 }
5720
5721 /**
5722  * xmlXPathConvertString:
5723  * @val:  an XPath object
5724  *
5725  * Converts an existing object to its string() equivalent
5726  *
5727  * Returns the new object, the old one is freed (or the operation
5728  *         is done directly on @val)
5729  */
5730 xmlXPathObjectPtr
5731 xmlXPathConvertString(xmlXPathObjectPtr val) {
5732     xmlChar *res = NULL;
5733
5734     if (val == NULL)
5735         return(xmlXPathNewCString(""));
5736
5737     switch (val->type) {
5738     case XPATH_UNDEFINED:
5739 #ifdef DEBUG_EXPR
5740         xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5741 #endif
5742         break;
5743     case XPATH_NODESET:
5744     case XPATH_XSLT_TREE:
5745         res = xmlXPathCastNodeSetToString(val->nodesetval);
5746         break;
5747     case XPATH_STRING:
5748         return(val);
5749     case XPATH_BOOLEAN:
5750         res = xmlXPathCastBooleanToString(val->boolval);
5751         break;
5752     case XPATH_NUMBER:
5753         res = xmlXPathCastNumberToString(val->floatval);
5754         break;
5755     case XPATH_USERS:
5756     case XPATH_POINT:
5757     case XPATH_RANGE:
5758     case XPATH_LOCATIONSET:
5759         TODO;
5760         break;
5761     }
5762     xmlXPathFreeObject(val);
5763     if (res == NULL)
5764         return(xmlXPathNewCString(""));
5765     return(xmlXPathWrapString(res));
5766 }
5767
5768 /**
5769  * xmlXPathCastBooleanToNumber:
5770  * @val:  a boolean
5771  *
5772  * Converts a boolean to its number value
5773  *
5774  * Returns the number value
5775  */
5776 double
5777 xmlXPathCastBooleanToNumber(int val) {
5778     if (val)
5779         return(1.0);
5780     return(0.0);
5781 }
5782
5783 /**
5784  * xmlXPathCastStringToNumber:
5785  * @val:  a string
5786  *
5787  * Converts a string to its number value
5788  *
5789  * Returns the number value
5790  */
5791 double
5792 xmlXPathCastStringToNumber(const xmlChar * val) {
5793     return(xmlXPathStringEvalNumber(val));
5794 }
5795
5796 /**
5797  * xmlXPathCastNodeToNumber:
5798  * @node:  a node
5799  *
5800  * Converts a node to its number value
5801  *
5802  * Returns the number value
5803  */
5804 double
5805 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5806     xmlChar *strval;
5807     double ret;
5808
5809     if (node == NULL)
5810         return(xmlXPathNAN);
5811     strval = xmlXPathCastNodeToString(node);
5812     if (strval == NULL)
5813         return(xmlXPathNAN);
5814     ret = xmlXPathCastStringToNumber(strval);
5815     xmlFree(strval);
5816
5817     return(ret);
5818 }
5819
5820 /**
5821  * xmlXPathCastNodeSetToNumber:
5822  * @ns:  a node-set
5823  *
5824  * Converts a node-set to its number value
5825  *
5826  * Returns the number value
5827  */
5828 double
5829 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5830     xmlChar *str;
5831     double ret;
5832
5833     if (ns == NULL)
5834         return(xmlXPathNAN);
5835     str = xmlXPathCastNodeSetToString(ns);
5836     ret = xmlXPathCastStringToNumber(str);
5837     xmlFree(str);
5838     return(ret);
5839 }
5840
5841 /**
5842  * xmlXPathCastToNumber:
5843  * @val:  an XPath object
5844  *
5845  * Converts an XPath object to its number value
5846  *
5847  * Returns the number value
5848  */
5849 double
5850 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5851     double ret = 0.0;
5852
5853     if (val == NULL)
5854         return(xmlXPathNAN);
5855     switch (val->type) {
5856     case XPATH_UNDEFINED:
5857 #ifdef DEGUB_EXPR
5858         xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5859 #endif
5860         ret = xmlXPathNAN;
5861         break;
5862     case XPATH_NODESET:
5863     case XPATH_XSLT_TREE:
5864         ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5865         break;
5866     case XPATH_STRING:
5867         ret = xmlXPathCastStringToNumber(val->stringval);
5868         break;
5869     case XPATH_NUMBER:
5870         ret = val->floatval;
5871         break;
5872     case XPATH_BOOLEAN:
5873         ret = xmlXPathCastBooleanToNumber(val->boolval);
5874         break;
5875     case XPATH_USERS:
5876     case XPATH_POINT:
5877     case XPATH_RANGE:
5878     case XPATH_LOCATIONSET:
5879         TODO;
5880         ret = xmlXPathNAN;
5881         break;
5882     }
5883     return(ret);
5884 }
5885
5886 /**
5887  * xmlXPathConvertNumber:
5888  * @val:  an XPath object
5889  *
5890  * Converts an existing object to its number() equivalent
5891  *
5892  * Returns the new object, the old one is freed (or the operation
5893  *         is done directly on @val)
5894  */
5895 xmlXPathObjectPtr
5896 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5897     xmlXPathObjectPtr ret;
5898
5899     if (val == NULL)
5900         return(xmlXPathNewFloat(0.0));
5901     if (val->type == XPATH_NUMBER)
5902         return(val);
5903     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5904     xmlXPathFreeObject(val);
5905     return(ret);
5906 }
5907
5908 /**
5909  * xmlXPathCastNumberToBoolean:
5910  * @val:  a number
5911  *
5912  * Converts a number to its boolean value
5913  *
5914  * Returns the boolean value
5915  */
5916 int
5917 xmlXPathCastNumberToBoolean (double val) {
5918      if (xmlXPathIsNaN(val) || (val == 0.0))
5919          return(0);
5920      return(1);
5921 }
5922
5923 /**
5924  * xmlXPathCastStringToBoolean:
5925  * @val:  a string
5926  *
5927  * Converts a string to its boolean value
5928  *
5929  * Returns the boolean value
5930  */
5931 int
5932 xmlXPathCastStringToBoolean (const xmlChar *val) {
5933     if ((val == NULL) || (xmlStrlen(val) == 0))
5934         return(0);
5935     return(1);
5936 }
5937
5938 /**
5939  * xmlXPathCastNodeSetToBoolean:
5940  * @ns:  a node-set
5941  *
5942  * Converts a node-set to its boolean value
5943  *
5944  * Returns the boolean value
5945  */
5946 int
5947 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5948     if ((ns == NULL) || (ns->nodeNr == 0))
5949         return(0);
5950     return(1);
5951 }
5952
5953 /**
5954  * xmlXPathCastToBoolean:
5955  * @val:  an XPath object
5956  *
5957  * Converts an XPath object to its boolean value
5958  *
5959  * Returns the boolean value
5960  */
5961 int
5962 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5963     int ret = 0;
5964
5965     if (val == NULL)
5966         return(0);
5967     switch (val->type) {
5968     case XPATH_UNDEFINED:
5969 #ifdef DEBUG_EXPR
5970         xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5971 #endif
5972         ret = 0;
5973         break;
5974     case XPATH_NODESET:
5975     case XPATH_XSLT_TREE:
5976         ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5977         break;
5978     case XPATH_STRING:
5979         ret = xmlXPathCastStringToBoolean(val->stringval);
5980         break;
5981     case XPATH_NUMBER:
5982         ret = xmlXPathCastNumberToBoolean(val->floatval);
5983         break;
5984     case XPATH_BOOLEAN:
5985         ret = val->boolval;
5986         break;
5987     case XPATH_USERS:
5988     case XPATH_POINT:
5989     case XPATH_RANGE:
5990     case XPATH_LOCATIONSET:
5991         TODO;
5992         ret = 0;
5993         break;
5994     }
5995     return(ret);
5996 }
5997
5998
5999 /**
6000  * xmlXPathConvertBoolean:
6001  * @val:  an XPath object
6002  *
6003  * Converts an existing object to its boolean() equivalent
6004  *
6005  * Returns the new object, the old one is freed (or the operation
6006  *         is done directly on @val)
6007  */
6008 xmlXPathObjectPtr
6009 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6010     xmlXPathObjectPtr ret;
6011
6012     if (val == NULL)
6013         return(xmlXPathNewBoolean(0));
6014     if (val->type == XPATH_BOOLEAN)
6015         return(val);
6016     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6017     xmlXPathFreeObject(val);
6018     return(ret);
6019 }
6020
6021 /************************************************************************
6022  *                                                                      *
6023  *              Routines to handle XPath contexts                       *
6024  *                                                                      *
6025  ************************************************************************/
6026
6027 /**
6028  * xmlXPathNewContext:
6029  * @doc:  the XML document
6030  *
6031  * Create a new xmlXPathContext
6032  *
6033  * Returns the xmlXPathContext just allocated. The caller will need to free it.
6034  */
6035 xmlXPathContextPtr
6036 xmlXPathNewContext(xmlDocPtr doc) {
6037     xmlXPathContextPtr ret;
6038
6039     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6040     if (ret == NULL) {
6041         xmlXPathErrMemory(NULL, "creating context\n");
6042         return(NULL);
6043     }
6044     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6045     ret->doc = doc;
6046     ret->node = NULL;
6047
6048     ret->varHash = NULL;
6049
6050     ret->nb_types = 0;
6051     ret->max_types = 0;
6052     ret->types = NULL;
6053
6054     ret->funcHash = xmlHashCreate(0);
6055
6056     ret->nb_axis = 0;
6057     ret->max_axis = 0;
6058     ret->axis = NULL;
6059
6060     ret->nsHash = NULL;
6061     ret->user = NULL;
6062
6063     ret->contextSize = -1;
6064     ret->proximityPosition = -1;
6065
6066 #ifdef XP_DEFAULT_CACHE_ON
6067     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6068         xmlXPathFreeContext(ret);
6069         return(NULL);
6070     }
6071 #endif
6072
6073     xmlXPathRegisterAllFunctions(ret);
6074
6075     return(ret);
6076 }
6077
6078 /**
6079  * xmlXPathFreeContext:
6080  * @ctxt:  the context to free
6081  *
6082  * Free up an xmlXPathContext
6083  */
6084 void
6085 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6086     if (ctxt == NULL) return;
6087
6088     if (ctxt->cache != NULL)
6089         xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6090     xmlXPathRegisteredNsCleanup(ctxt);
6091     xmlXPathRegisteredFuncsCleanup(ctxt);
6092     xmlXPathRegisteredVariablesCleanup(ctxt);
6093     xmlResetError(&ctxt->lastError);
6094     xmlFree(ctxt);
6095 }
6096
6097 /************************************************************************
6098  *                                                                      *
6099  *              Routines to handle XPath parser contexts                *
6100  *                                                                      *
6101  ************************************************************************/
6102
6103 #define CHECK_CTXT(ctxt)                                                \
6104     if (ctxt == NULL) {                                         \
6105         __xmlRaiseError(NULL, NULL, NULL,                               \
6106                 NULL, NULL, XML_FROM_XPATH,                             \
6107                 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6108                 __FILE__, __LINE__,                                     \
6109                 NULL, NULL, NULL, 0, 0,                                 \
6110                 "NULL context pointer\n");                              \
6111         return(NULL);                                                   \
6112     }                                                                   \
6113
6114 #define CHECK_CTXT_NEG(ctxt)                                            \
6115     if (ctxt == NULL) {                                         \
6116         __xmlRaiseError(NULL, NULL, NULL,                               \
6117                 NULL, NULL, XML_FROM_XPATH,                             \
6118                 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6119                 __FILE__, __LINE__,                                     \
6120                 NULL, NULL, NULL, 0, 0,                                 \
6121                 "NULL context pointer\n");                              \
6122         return(-1);                                                     \
6123     }                                                                   \
6124
6125
6126 #define CHECK_CONTEXT(ctxt)                                             \
6127     if ((ctxt == NULL) || (ctxt->doc == NULL) ||                        \
6128         (ctxt->doc->children == NULL)) {                                \
6129         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);    \
6130         return(NULL);                                                   \
6131     }
6132
6133
6134 /**
6135  * xmlXPathNewParserContext:
6136  * @str:  the XPath expression
6137  * @ctxt:  the XPath context
6138  *
6139  * Create a new xmlXPathParserContext
6140  *
6141  * Returns the xmlXPathParserContext just allocated.
6142  */
6143 xmlXPathParserContextPtr
6144 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6145     xmlXPathParserContextPtr ret;
6146
6147     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6148     if (ret == NULL) {
6149         xmlXPathErrMemory(ctxt, "creating parser context\n");
6150         return(NULL);
6151     }
6152     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6153     ret->cur = ret->base = str;
6154     ret->context = ctxt;
6155
6156     ret->comp = xmlXPathNewCompExpr();
6157     if (ret->comp == NULL) {
6158         xmlFree(ret->valueTab);
6159         xmlFree(ret);
6160         return(NULL);
6161     }
6162     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6163         ret->comp->dict = ctxt->dict;
6164         xmlDictReference(ret->comp->dict);
6165     }
6166
6167     return(ret);
6168 }
6169
6170 /**
6171  * xmlXPathCompParserContext:
6172  * @comp:  the XPath compiled expression
6173  * @ctxt:  the XPath context
6174  *
6175  * Create a new xmlXPathParserContext when processing a compiled expression
6176  *
6177  * Returns the xmlXPathParserContext just allocated.
6178  */
6179 static xmlXPathParserContextPtr
6180 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6181     xmlXPathParserContextPtr ret;
6182
6183     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6184     if (ret == NULL) {
6185         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6186         return(NULL);
6187     }
6188     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6189
6190     /* Allocate the value stack */
6191     ret->valueTab = (xmlXPathObjectPtr *)
6192                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6193     if (ret->valueTab == NULL) {
6194         xmlFree(ret);
6195         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6196         return(NULL);
6197     }
6198     ret->valueNr = 0;
6199     ret->valueMax = 10;
6200     ret->value = NULL;
6201     ret->valueFrame = 0;
6202
6203     ret->context = ctxt;
6204     ret->comp = comp;
6205
6206     return(ret);
6207 }
6208
6209 /**
6210  * xmlXPathFreeParserContext:
6211  * @ctxt:  the context to free
6212  *
6213  * Free up an xmlXPathParserContext
6214  */
6215 void
6216 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6217     if (ctxt->valueTab != NULL) {
6218         xmlFree(ctxt->valueTab);
6219     }
6220     if (ctxt->comp != NULL) {
6221 #ifdef XPATH_STREAMING
6222         if (ctxt->comp->stream != NULL) {
6223             xmlFreePatternList(ctxt->comp->stream);
6224             ctxt->comp->stream = NULL;
6225         }
6226 #endif
6227         xmlXPathFreeCompExpr(ctxt->comp);
6228     }
6229     xmlFree(ctxt);
6230 }
6231
6232 /************************************************************************
6233  *                                                                      *
6234  *              The implicit core function library                      *
6235  *                                                                      *
6236  ************************************************************************/
6237
6238 /**
6239  * xmlXPathNodeValHash:
6240  * @node:  a node pointer
6241  *
6242  * Function computing the beginning of the string value of the node,
6243  * used to speed up comparisons
6244  *
6245  * Returns an int usable as a hash
6246  */
6247 static unsigned int
6248 xmlXPathNodeValHash(xmlNodePtr node) {
6249     int len = 2;
6250     const xmlChar * string = NULL;
6251     xmlNodePtr tmp = NULL;
6252     unsigned int ret = 0;
6253
6254     if (node == NULL)
6255         return(0);
6256
6257     if (node->type == XML_DOCUMENT_NODE) {
6258         tmp = xmlDocGetRootElement((xmlDocPtr) node);
6259         if (tmp == NULL)
6260             node = node->children;
6261         else
6262             node = tmp;
6263
6264         if (node == NULL)
6265             return(0);
6266     }
6267
6268     switch (node->type) {
6269         case XML_COMMENT_NODE:
6270         case XML_PI_NODE:
6271         case XML_CDATA_SECTION_NODE:
6272         case XML_TEXT_NODE:
6273             string = node->content;
6274             if (string == NULL)
6275                 return(0);
6276             if (string[0] == 0)
6277                 return(0);
6278             return(((unsigned int) string[0]) +
6279                    (((unsigned int) string[1]) << 8));
6280         case XML_NAMESPACE_DECL:
6281             string = ((xmlNsPtr)node)->href;
6282             if (string == NULL)
6283                 return(0);
6284             if (string[0] == 0)
6285                 return(0);
6286             return(((unsigned int) string[0]) +
6287                    (((unsigned int) string[1]) << 8));
6288         case XML_ATTRIBUTE_NODE:
6289             tmp = ((xmlAttrPtr) node)->children;
6290             break;
6291         case XML_ELEMENT_NODE:
6292             tmp = node->children;
6293             break;
6294         default:
6295             return(0);
6296     }
6297     while (tmp != NULL) {
6298         switch (tmp->type) {
6299             case XML_COMMENT_NODE:
6300             case XML_PI_NODE:
6301             case XML_CDATA_SECTION_NODE:
6302             case XML_TEXT_NODE:
6303                 string = tmp->content;
6304                 break;
6305             case XML_NAMESPACE_DECL:
6306                 string = ((xmlNsPtr)tmp)->href;
6307                 break;
6308             default:
6309                 break;
6310         }
6311         if ((string != NULL) && (string[0] != 0)) {
6312             if (len == 1) {
6313                 return(ret + (((unsigned int) string[0]) << 8));
6314             }
6315             if (string[1] == 0) {
6316                 len = 1;
6317                 ret = (unsigned int) string[0];
6318             } else {
6319                 return(((unsigned int) string[0]) +
6320                        (((unsigned int) string[1]) << 8));
6321             }
6322         }
6323         /*
6324          * Skip to next node
6325          */
6326         if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6327             if (tmp->children->type != XML_ENTITY_DECL) {
6328                 tmp = tmp->children;
6329                 continue;
6330             }
6331         }
6332         if (tmp == node)
6333             break;
6334
6335         if (tmp->next != NULL) {
6336             tmp = tmp->next;
6337             continue;
6338         }
6339
6340         do {
6341             tmp = tmp->parent;
6342             if (tmp == NULL)
6343                 break;
6344             if (tmp == node) {
6345                 tmp = NULL;
6346                 break;
6347             }
6348             if (tmp->next != NULL) {
6349                 tmp = tmp->next;
6350                 break;
6351             }
6352         } while (tmp != NULL);
6353     }
6354     return(ret);
6355 }
6356
6357 /**
6358  * xmlXPathStringHash:
6359  * @string:  a string
6360  *
6361  * Function computing the beginning of the string value of the node,
6362  * used to speed up comparisons
6363  *
6364  * Returns an int usable as a hash
6365  */
6366 static unsigned int
6367 xmlXPathStringHash(const xmlChar * string) {
6368     if (string == NULL)
6369         return((unsigned int) 0);
6370     if (string[0] == 0)
6371         return(0);
6372     return(((unsigned int) string[0]) +
6373            (((unsigned int) string[1]) << 8));
6374 }
6375
6376 /**
6377  * xmlXPathCompareNodeSetFloat:
6378  * @ctxt:  the XPath Parser context
6379  * @inf:  less than (1) or greater than (0)
6380  * @strict:  is the comparison strict
6381  * @arg:  the node set
6382  * @f:  the value
6383  *
6384  * Implement the compare operation between a nodeset and a number
6385  *     @ns < @val    (1, 1, ...
6386  *     @ns <= @val   (1, 0, ...
6387  *     @ns > @val    (0, 1, ...
6388  *     @ns >= @val   (0, 0, ...
6389  *
6390  * If one object to be compared is a node-set and the other is a number,
6391  * then the comparison will be true if and only if there is a node in the
6392  * node-set such that the result of performing the comparison on the number
6393  * to be compared and on the result of converting the string-value of that
6394  * node to a number using the number function is true.
6395  *
6396  * Returns 0 or 1 depending on the results of the test.
6397  */
6398 static int
6399 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6400                             xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6401     int i, ret = 0;
6402     xmlNodeSetPtr ns;
6403     xmlChar *str2;
6404
6405     if ((f == NULL) || (arg == NULL) ||
6406         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6407         xmlXPathReleaseObject(ctxt->context, arg);
6408         xmlXPathReleaseObject(ctxt->context, f);
6409         return(0);
6410     }
6411     ns = arg->nodesetval;
6412     if (ns != NULL) {
6413         for (i = 0;i < ns->nodeNr;i++) {
6414              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6415              if (str2 != NULL) {
6416                  valuePush(ctxt,
6417                            xmlXPathCacheNewString(ctxt->context, str2));
6418                  xmlFree(str2);
6419                  xmlXPathNumberFunction(ctxt, 1);
6420                  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6421                  ret = xmlXPathCompareValues(ctxt, inf, strict);
6422                  if (ret)
6423                      break;
6424              }
6425         }
6426     }
6427     xmlXPathReleaseObject(ctxt->context, arg);
6428     xmlXPathReleaseObject(ctxt->context, f);
6429     return(ret);
6430 }
6431
6432 /**
6433  * xmlXPathCompareNodeSetString:
6434  * @ctxt:  the XPath Parser context
6435  * @inf:  less than (1) or greater than (0)
6436  * @strict:  is the comparison strict
6437  * @arg:  the node set
6438  * @s:  the value
6439  *
6440  * Implement the compare operation between a nodeset and a string
6441  *     @ns < @val    (1, 1, ...
6442  *     @ns <= @val   (1, 0, ...
6443  *     @ns > @val    (0, 1, ...
6444  *     @ns >= @val   (0, 0, ...
6445  *
6446  * If one object to be compared is a node-set and the other is a string,
6447  * then the comparison will be true if and only if there is a node in
6448  * the node-set such that the result of performing the comparison on the
6449  * string-value of the node and the other string is true.
6450  *
6451  * Returns 0 or 1 depending on the results of the test.
6452  */
6453 static int
6454 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6455                             xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6456     int i, ret = 0;
6457     xmlNodeSetPtr ns;
6458     xmlChar *str2;
6459
6460     if ((s == NULL) || (arg == NULL) ||
6461         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6462         xmlXPathReleaseObject(ctxt->context, arg);
6463         xmlXPathReleaseObject(ctxt->context, s);
6464         return(0);
6465     }
6466     ns = arg->nodesetval;
6467     if (ns != NULL) {
6468         for (i = 0;i < ns->nodeNr;i++) {
6469              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6470              if (str2 != NULL) {
6471                  valuePush(ctxt,
6472                            xmlXPathCacheNewString(ctxt->context, str2));
6473                  xmlFree(str2);
6474                  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6475                  ret = xmlXPathCompareValues(ctxt, inf, strict);
6476                  if (ret)
6477                      break;
6478              }
6479         }
6480     }
6481     xmlXPathReleaseObject(ctxt->context, arg);
6482     xmlXPathReleaseObject(ctxt->context, s);
6483     return(ret);
6484 }
6485
6486 /**
6487  * xmlXPathCompareNodeSets:
6488  * @inf:  less than (1) or greater than (0)
6489  * @strict:  is the comparison strict
6490  * @arg1:  the first node set object
6491  * @arg2:  the second node set object
6492  *
6493  * Implement the compare operation on nodesets:
6494  *
6495  * If both objects to be compared are node-sets, then the comparison
6496  * will be true if and only if there is a node in the first node-set
6497  * and a node in the second node-set such that the result of performing
6498  * the comparison on the string-values of the two nodes is true.
6499  * ....
6500  * When neither object to be compared is a node-set and the operator
6501  * is <=, <, >= or >, then the objects are compared by converting both
6502  * objects to numbers and comparing the numbers according to IEEE 754.
6503  * ....
6504  * The number function converts its argument to a number as follows:
6505  *  - a string that consists of optional whitespace followed by an
6506  *    optional minus sign followed by a Number followed by whitespace
6507  *    is converted to the IEEE 754 number that is nearest (according
6508  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6509  *    represented by the string; any other string is converted to NaN
6510  *
6511  * Conclusion all nodes need to be converted first to their string value
6512  * and then the comparison must be done when possible
6513  */
6514 static int
6515 xmlXPathCompareNodeSets(int inf, int strict,
6516                         xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6517     int i, j, init = 0;
6518     double val1;
6519     double *values2;
6520     int ret = 0;
6521     xmlNodeSetPtr ns1;
6522     xmlNodeSetPtr ns2;
6523
6524     if ((arg1 == NULL) ||
6525         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6526         xmlXPathFreeObject(arg2);
6527         return(0);
6528     }
6529     if ((arg2 == NULL) ||
6530         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6531         xmlXPathFreeObject(arg1);
6532         xmlXPathFreeObject(arg2);
6533         return(0);
6534     }
6535
6536     ns1 = arg1->nodesetval;
6537     ns2 = arg2->nodesetval;
6538
6539     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6540         xmlXPathFreeObject(arg1);
6541         xmlXPathFreeObject(arg2);
6542         return(0);
6543     }
6544     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6545         xmlXPathFreeObject(arg1);
6546         xmlXPathFreeObject(arg2);
6547         return(0);
6548     }
6549
6550     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6551     if (values2 == NULL) {
6552         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6553         xmlXPathFreeObject(arg1);
6554         xmlXPathFreeObject(arg2);
6555         return(0);
6556     }
6557     for (i = 0;i < ns1->nodeNr;i++) {
6558         val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6559         if (xmlXPathIsNaN(val1))
6560             continue;
6561         for (j = 0;j < ns2->nodeNr;j++) {
6562             if (init == 0) {
6563                 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6564             }
6565             if (xmlXPathIsNaN(values2[j]))
6566                 continue;
6567             if (inf && strict)
6568                 ret = (val1 < values2[j]);
6569             else if (inf && !strict)
6570                 ret = (val1 <= values2[j]);
6571             else if (!inf && strict)
6572                 ret = (val1 > values2[j]);
6573             else if (!inf && !strict)
6574                 ret = (val1 >= values2[j]);
6575             if (ret)
6576                 break;
6577         }
6578         if (ret)
6579             break;
6580         init = 1;
6581     }
6582     xmlFree(values2);
6583     xmlXPathFreeObject(arg1);
6584     xmlXPathFreeObject(arg2);
6585     return(ret);
6586 }
6587
6588 /**
6589  * xmlXPathCompareNodeSetValue:
6590  * @ctxt:  the XPath Parser context
6591  * @inf:  less than (1) or greater than (0)
6592  * @strict:  is the comparison strict
6593  * @arg:  the node set
6594  * @val:  the value
6595  *
6596  * Implement the compare operation between a nodeset and a value
6597  *     @ns < @val    (1, 1, ...
6598  *     @ns <= @val   (1, 0, ...
6599  *     @ns > @val    (0, 1, ...
6600  *     @ns >= @val   (0, 0, ...
6601  *
6602  * If one object to be compared is a node-set and the other is a boolean,
6603  * then the comparison will be true if and only if the result of performing
6604  * the comparison on the boolean and on the result of converting
6605  * the node-set to a boolean using the boolean function is true.
6606  *
6607  * Returns 0 or 1 depending on the results of the test.
6608  */
6609 static int
6610 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6611                             xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6612     if ((val == NULL) || (arg == NULL) ||
6613         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6614         return(0);
6615
6616     switch(val->type) {
6617         case XPATH_NUMBER:
6618             return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6619         case XPATH_NODESET:
6620         case XPATH_XSLT_TREE:
6621             return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6622         case XPATH_STRING:
6623             return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6624         case XPATH_BOOLEAN:
6625             valuePush(ctxt, arg);
6626             xmlXPathBooleanFunction(ctxt, 1);
6627             valuePush(ctxt, val);
6628             return(xmlXPathCompareValues(ctxt, inf, strict));
6629         default:
6630             TODO
6631     }
6632     return(0);
6633 }
6634
6635 /**
6636  * xmlXPathEqualNodeSetString:
6637  * @arg:  the nodeset object argument
6638  * @str:  the string to compare to.
6639  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6640  *
6641  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6642  * If one object to be compared is a node-set and the other is a string,
6643  * then the comparison will be true if and only if there is a node in
6644  * the node-set such that the result of performing the comparison on the
6645  * string-value of the node and the other string is true.
6646  *
6647  * Returns 0 or 1 depending on the results of the test.
6648  */
6649 static int
6650 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6651 {
6652     int i;
6653     xmlNodeSetPtr ns;
6654     xmlChar *str2;
6655     unsigned int hash;
6656
6657     if ((str == NULL) || (arg == NULL) ||
6658         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6659         return (0);
6660     ns = arg->nodesetval;
6661     /*
6662      * A NULL nodeset compared with a string is always false
6663      * (since there is no node equal, and no node not equal)
6664      */
6665     if ((ns == NULL) || (ns->nodeNr <= 0) )
6666         return (0);
6667     hash = xmlXPathStringHash(str);
6668     for (i = 0; i < ns->nodeNr; i++) {
6669         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6670             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6671             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6672                 xmlFree(str2);
6673                 if (neq)
6674                     continue;
6675                 return (1);
6676             } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6677                 if (neq)
6678                     continue;
6679                 return (1);
6680             } else if (neq) {
6681                 if (str2 != NULL)
6682                     xmlFree(str2);
6683                 return (1);
6684             }
6685             if (str2 != NULL)
6686                 xmlFree(str2);
6687         } else if (neq)
6688             return (1);
6689     }
6690     return (0);
6691 }
6692
6693 /**
6694  * xmlXPathEqualNodeSetFloat:
6695  * @arg:  the nodeset object argument
6696  * @f:  the float to compare to
6697  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6698  *
6699  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6700  * If one object to be compared is a node-set and the other is a number,
6701  * then the comparison will be true if and only if there is a node in
6702  * the node-set such that the result of performing the comparison on the
6703  * number to be compared and on the result of converting the string-value
6704  * of that node to a number using the number function is true.
6705  *
6706  * Returns 0 or 1 depending on the results of the test.
6707  */
6708 static int
6709 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6710     xmlXPathObjectPtr arg, double f, int neq) {
6711   int i, ret=0;
6712   xmlNodeSetPtr ns;
6713   xmlChar *str2;
6714   xmlXPathObjectPtr val;
6715   double v;
6716
6717     if ((arg == NULL) ||
6718         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6719         return(0);
6720
6721     ns = arg->nodesetval;
6722     if (ns != NULL) {
6723         for (i=0;i<ns->nodeNr;i++) {
6724             str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6725             if (str2 != NULL) {
6726                 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6727                 xmlFree(str2);
6728                 xmlXPathNumberFunction(ctxt, 1);
6729                 val = valuePop(ctxt);
6730                 v = val->floatval;
6731                 xmlXPathReleaseObject(ctxt->context, val);
6732                 if (!xmlXPathIsNaN(v)) {
6733                     if ((!neq) && (v==f)) {
6734                         ret = 1;
6735                         break;
6736                     } else if ((neq) && (v!=f)) {
6737                         ret = 1;
6738                         break;
6739                     }
6740                 } else {        /* NaN is unequal to any value */
6741                     if (neq)
6742                         ret = 1;
6743                 }
6744             }
6745         }
6746     }
6747
6748     return(ret);
6749 }
6750
6751
6752 /**
6753  * xmlXPathEqualNodeSets:
6754  * @arg1:  first nodeset object argument
6755  * @arg2:  second nodeset object argument
6756  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6757  *
6758  * Implement the equal / not equal operation on XPath nodesets:
6759  * @arg1 == @arg2  or  @arg1 != @arg2
6760  * If both objects to be compared are node-sets, then the comparison
6761  * will be true if and only if there is a node in the first node-set and
6762  * a node in the second node-set such that the result of performing the
6763  * comparison on the string-values of the two nodes is true.
6764  *
6765  * (needless to say, this is a costly operation)
6766  *
6767  * Returns 0 or 1 depending on the results of the test.
6768  */
6769 static int
6770 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6771     int i, j;
6772     unsigned int *hashs1;
6773     unsigned int *hashs2;
6774     xmlChar **values1;
6775     xmlChar **values2;
6776     int ret = 0;
6777     xmlNodeSetPtr ns1;
6778     xmlNodeSetPtr ns2;
6779
6780     if ((arg1 == NULL) ||
6781         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6782         return(0);
6783     if ((arg2 == NULL) ||
6784         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6785         return(0);
6786
6787     ns1 = arg1->nodesetval;
6788     ns2 = arg2->nodesetval;
6789
6790     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6791         return(0);
6792     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6793         return(0);
6794
6795     /*
6796      * for equal, check if there is a node pertaining to both sets
6797      */
6798     if (neq == 0)
6799         for (i = 0;i < ns1->nodeNr;i++)
6800             for (j = 0;j < ns2->nodeNr;j++)
6801                 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6802                     return(1);
6803
6804     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6805     if (values1 == NULL) {
6806         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6807         return(0);
6808     }
6809     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6810     if (hashs1 == NULL) {
6811         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6812         xmlFree(values1);
6813         return(0);
6814     }
6815     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6816     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6817     if (values2 == NULL) {
6818         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6819         xmlFree(hashs1);
6820         xmlFree(values1);
6821         return(0);
6822     }
6823     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6824     if (hashs2 == NULL) {
6825         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6826         xmlFree(hashs1);
6827         xmlFree(values1);
6828         xmlFree(values2);
6829         return(0);
6830     }
6831     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6832     for (i = 0;i < ns1->nodeNr;i++) {
6833         hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6834         for (j = 0;j < ns2->nodeNr;j++) {
6835             if (i == 0)
6836                 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6837             if (hashs1[i] != hashs2[j]) {
6838                 if (neq) {
6839                     ret = 1;
6840                     break;
6841                 }
6842             }
6843             else {
6844                 if (values1[i] == NULL)
6845                     values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6846                 if (values2[j] == NULL)
6847                     values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6848                 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6849                 if (ret)
6850                     break;
6851             }
6852         }
6853         if (ret)
6854             break;
6855     }
6856     for (i = 0;i < ns1->nodeNr;i++)
6857         if (values1[i] != NULL)
6858             xmlFree(values1[i]);
6859     for (j = 0;j < ns2->nodeNr;j++)
6860         if (values2[j] != NULL)
6861             xmlFree(values2[j]);
6862     xmlFree(values1);
6863     xmlFree(values2);
6864     xmlFree(hashs1);
6865     xmlFree(hashs2);
6866     return(ret);
6867 }
6868
6869 static int
6870 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6871   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6872     int ret = 0;
6873     /*
6874      *At this point we are assured neither arg1 nor arg2
6875      *is a nodeset, so we can just pick the appropriate routine.
6876      */
6877     switch (arg1->type) {
6878         case XPATH_UNDEFINED:
6879 #ifdef DEBUG_EXPR
6880             xmlGenericError(xmlGenericErrorContext,
6881                     "Equal: undefined\n");
6882 #endif
6883             break;
6884         case XPATH_BOOLEAN:
6885             switch (arg2->type) {
6886                 case XPATH_UNDEFINED:
6887 #ifdef DEBUG_EXPR
6888                     xmlGenericError(xmlGenericErrorContext,
6889                             "Equal: undefined\n");
6890 #endif
6891                     break;
6892                 case XPATH_BOOLEAN:
6893 #ifdef DEBUG_EXPR
6894                     xmlGenericError(xmlGenericErrorContext,
6895                             "Equal: %d boolean %d \n",
6896                             arg1->boolval, arg2->boolval);
6897 #endif
6898                     ret = (arg1->boolval == arg2->boolval);
6899                     break;
6900                 case XPATH_NUMBER:
6901                     ret = (arg1->boolval ==
6902                            xmlXPathCastNumberToBoolean(arg2->floatval));
6903                     break;
6904                 case XPATH_STRING:
6905                     if ((arg2->stringval == NULL) ||
6906                         (arg2->stringval[0] == 0)) ret = 0;
6907                     else
6908                         ret = 1;
6909                     ret = (arg1->boolval == ret);
6910                     break;
6911                 case XPATH_USERS:
6912                 case XPATH_POINT:
6913                 case XPATH_RANGE:
6914                 case XPATH_LOCATIONSET:
6915                     TODO
6916                     break;
6917                 case XPATH_NODESET:
6918                 case XPATH_XSLT_TREE:
6919                     break;
6920             }
6921             break;
6922         case XPATH_NUMBER:
6923             switch (arg2->type) {
6924                 case XPATH_UNDEFINED:
6925 #ifdef DEBUG_EXPR
6926                     xmlGenericError(xmlGenericErrorContext,
6927                             "Equal: undefined\n");
6928 #endif
6929                     break;
6930                 case XPATH_BOOLEAN:
6931                     ret = (arg2->boolval==
6932                            xmlXPathCastNumberToBoolean(arg1->floatval));
6933                     break;
6934                 case XPATH_STRING:
6935                     valuePush(ctxt, arg2);
6936                     xmlXPathNumberFunction(ctxt, 1);
6937                     arg2 = valuePop(ctxt);
6938                     /* no break on purpose */
6939                 case XPATH_NUMBER:
6940                     /* Hand check NaN and Infinity equalities */
6941                     if (xmlXPathIsNaN(arg1->floatval) ||
6942                             xmlXPathIsNaN(arg2->floatval)) {
6943                         ret = 0;
6944                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6945                         if (xmlXPathIsInf(arg2->floatval) == 1)
6946                             ret = 1;
6947                         else
6948                             ret = 0;
6949                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6950                         if (xmlXPathIsInf(arg2->floatval) == -1)
6951                             ret = 1;
6952                         else
6953                             ret = 0;
6954                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6955                         if (xmlXPathIsInf(arg1->floatval) == 1)
6956                             ret = 1;
6957                         else
6958                             ret = 0;
6959                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6960                         if (xmlXPathIsInf(arg1->floatval) == -1)
6961                             ret = 1;
6962                         else
6963                             ret = 0;
6964                     } else {
6965                         ret = (arg1->floatval == arg2->floatval);
6966                     }
6967                     break;
6968                 case XPATH_USERS:
6969                 case XPATH_POINT:
6970                 case XPATH_RANGE:
6971                 case XPATH_LOCATIONSET:
6972                     TODO
6973                     break;
6974                 case XPATH_NODESET:
6975                 case XPATH_XSLT_TREE:
6976                     break;
6977             }
6978             break;
6979         case XPATH_STRING:
6980             switch (arg2->type) {
6981                 case XPATH_UNDEFINED:
6982 #ifdef DEBUG_EXPR
6983                     xmlGenericError(xmlGenericErrorContext,
6984                             "Equal: undefined\n");
6985 #endif
6986                     break;
6987                 case XPATH_BOOLEAN:
6988                     if ((arg1->stringval == NULL) ||
6989                         (arg1->stringval[0] == 0)) ret = 0;
6990                     else
6991                         ret = 1;
6992                     ret = (arg2->boolval == ret);
6993                     break;
6994                 case XPATH_STRING:
6995                     ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6996                     break;
6997                 case XPATH_NUMBER:
6998                     valuePush(ctxt, arg1);
6999                     xmlXPathNumberFunction(ctxt, 1);
7000                     arg1 = valuePop(ctxt);
7001                     /* Hand check NaN and Infinity equalities */
7002                     if (xmlXPathIsNaN(arg1->floatval) ||
7003                             xmlXPathIsNaN(arg2->floatval)) {
7004                         ret = 0;
7005                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7006                         if (xmlXPathIsInf(arg2->floatval) == 1)
7007                             ret = 1;
7008                         else
7009                             ret = 0;
7010                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7011                         if (xmlXPathIsInf(arg2->floatval) == -1)
7012                             ret = 1;
7013                         else
7014                             ret = 0;
7015                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7016                         if (xmlXPathIsInf(arg1->floatval) == 1)
7017                             ret = 1;
7018                         else
7019                             ret = 0;
7020                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7021                         if (xmlXPathIsInf(arg1->floatval) == -1)
7022                             ret = 1;
7023                         else
7024                             ret = 0;
7025                     } else {
7026                         ret = (arg1->floatval == arg2->floatval);
7027                     }
7028                     break;
7029                 case XPATH_USERS:
7030                 case XPATH_POINT:
7031                 case XPATH_RANGE:
7032                 case XPATH_LOCATIONSET:
7033                     TODO
7034                     break;
7035                 case XPATH_NODESET:
7036                 case XPATH_XSLT_TREE:
7037                     break;
7038             }
7039             break;
7040         case XPATH_USERS:
7041         case XPATH_POINT:
7042         case XPATH_RANGE:
7043         case XPATH_LOCATIONSET:
7044             TODO
7045             break;
7046         case XPATH_NODESET:
7047         case XPATH_XSLT_TREE:
7048             break;
7049     }
7050     xmlXPathReleaseObject(ctxt->context, arg1);
7051     xmlXPathReleaseObject(ctxt->context, arg2);
7052     return(ret);
7053 }
7054
7055 /**
7056  * xmlXPathEqualValues:
7057  * @ctxt:  the XPath Parser context
7058  *
7059  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7060  *
7061  * Returns 0 or 1 depending on the results of the test.
7062  */
7063 int
7064 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7065     xmlXPathObjectPtr arg1, arg2, argtmp;
7066     int ret = 0;
7067
7068     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7069     arg2 = valuePop(ctxt);
7070     arg1 = valuePop(ctxt);
7071     if ((arg1 == NULL) || (arg2 == NULL)) {
7072         if (arg1 != NULL)
7073             xmlXPathReleaseObject(ctxt->context, arg1);
7074         else
7075             xmlXPathReleaseObject(ctxt->context, arg2);
7076         XP_ERROR0(XPATH_INVALID_OPERAND);
7077     }
7078
7079     if (arg1 == arg2) {
7080 #ifdef DEBUG_EXPR
7081         xmlGenericError(xmlGenericErrorContext,
7082                 "Equal: by pointer\n");
7083 #endif
7084         xmlXPathFreeObject(arg1);
7085         return(1);
7086     }
7087
7088     /*
7089      *If either argument is a nodeset, it's a 'special case'
7090      */
7091     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7092       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7093         /*
7094          *Hack it to assure arg1 is the nodeset
7095          */
7096         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7097                 argtmp = arg2;
7098                 arg2 = arg1;
7099                 arg1 = argtmp;
7100         }
7101         switch (arg2->type) {
7102             case XPATH_UNDEFINED:
7103 #ifdef DEBUG_EXPR
7104                 xmlGenericError(xmlGenericErrorContext,
7105                         "Equal: undefined\n");
7106 #endif
7107                 break;
7108             case XPATH_NODESET:
7109             case XPATH_XSLT_TREE:
7110                 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7111                 break;
7112             case XPATH_BOOLEAN:
7113                 if ((arg1->nodesetval == NULL) ||
7114                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
7115                 else
7116                     ret = 1;
7117                 ret = (ret == arg2->boolval);
7118                 break;
7119             case XPATH_NUMBER:
7120                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7121                 break;
7122             case XPATH_STRING:
7123                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7124                 break;
7125             case XPATH_USERS:
7126             case XPATH_POINT:
7127             case XPATH_RANGE:
7128             case XPATH_LOCATIONSET:
7129                 TODO
7130                 break;
7131         }
7132         xmlXPathReleaseObject(ctxt->context, arg1);
7133         xmlXPathReleaseObject(ctxt->context, arg2);
7134         return(ret);
7135     }
7136
7137     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7138 }
7139
7140 /**
7141  * xmlXPathNotEqualValues:
7142  * @ctxt:  the XPath Parser context
7143  *
7144  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7145  *
7146  * Returns 0 or 1 depending on the results of the test.
7147  */
7148 int
7149 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7150     xmlXPathObjectPtr arg1, arg2, argtmp;
7151     int ret = 0;
7152
7153     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7154     arg2 = valuePop(ctxt);
7155     arg1 = valuePop(ctxt);
7156     if ((arg1 == NULL) || (arg2 == NULL)) {
7157         if (arg1 != NULL)
7158             xmlXPathReleaseObject(ctxt->context, arg1);
7159         else
7160             xmlXPathReleaseObject(ctxt->context, arg2);
7161         XP_ERROR0(XPATH_INVALID_OPERAND);
7162     }
7163
7164     if (arg1 == arg2) {
7165 #ifdef DEBUG_EXPR
7166         xmlGenericError(xmlGenericErrorContext,
7167                 "NotEqual: by pointer\n");
7168 #endif
7169         xmlXPathReleaseObject(ctxt->context, arg1);
7170         return(0);
7171     }
7172
7173     /*
7174      *If either argument is a nodeset, it's a 'special case'
7175      */
7176     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7177       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7178         /*
7179          *Hack it to assure arg1 is the nodeset
7180          */
7181         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7182                 argtmp = arg2;
7183                 arg2 = arg1;
7184                 arg1 = argtmp;
7185         }
7186         switch (arg2->type) {
7187             case XPATH_UNDEFINED:
7188 #ifdef DEBUG_EXPR
7189                 xmlGenericError(xmlGenericErrorContext,
7190                         "NotEqual: undefined\n");
7191 #endif
7192                 break;
7193             case XPATH_NODESET:
7194             case XPATH_XSLT_TREE:
7195                 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7196                 break;
7197             case XPATH_BOOLEAN:
7198                 if ((arg1->nodesetval == NULL) ||
7199                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
7200                 else
7201                     ret = 1;
7202                 ret = (ret != arg2->boolval);
7203                 break;
7204             case XPATH_NUMBER:
7205                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7206                 break;
7207             case XPATH_STRING:
7208                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7209                 break;
7210             case XPATH_USERS:
7211             case XPATH_POINT:
7212             case XPATH_RANGE:
7213             case XPATH_LOCATIONSET:
7214                 TODO
7215                 break;
7216         }
7217         xmlXPathReleaseObject(ctxt->context, arg1);
7218         xmlXPathReleaseObject(ctxt->context, arg2);
7219         return(ret);
7220     }
7221
7222     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7223 }
7224
7225 /**
7226  * xmlXPathCompareValues:
7227  * @ctxt:  the XPath Parser context
7228  * @inf:  less than (1) or greater than (0)
7229  * @strict:  is the comparison strict
7230  *
7231  * Implement the compare operation on XPath objects:
7232  *     @arg1 < @arg2    (1, 1, ...
7233  *     @arg1 <= @arg2   (1, 0, ...
7234  *     @arg1 > @arg2    (0, 1, ...
7235  *     @arg1 >= @arg2   (0, 0, ...
7236  *
7237  * When neither object to be compared is a node-set and the operator is
7238  * <=, <, >=, >, then the objects are compared by converted both objects
7239  * to numbers and comparing the numbers according to IEEE 754. The <
7240  * comparison will be true if and only if the first number is less than the
7241  * second number. The <= comparison will be true if and only if the first
7242  * number is less than or equal to the second number. The > comparison
7243  * will be true if and only if the first number is greater than the second
7244  * number. The >= comparison will be true if and only if the first number
7245  * is greater than or equal to the second number.
7246  *
7247  * Returns 1 if the comparison succeeded, 0 if it failed
7248  */
7249 int
7250 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7251     int ret = 0, arg1i = 0, arg2i = 0;
7252     xmlXPathObjectPtr arg1, arg2;
7253
7254     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7255     arg2 = valuePop(ctxt);
7256     arg1 = valuePop(ctxt);
7257     if ((arg1 == NULL) || (arg2 == NULL)) {
7258         if (arg1 != NULL)
7259             xmlXPathReleaseObject(ctxt->context, arg1);
7260         else
7261             xmlXPathReleaseObject(ctxt->context, arg2);
7262         XP_ERROR0(XPATH_INVALID_OPERAND);
7263     }
7264
7265     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7266       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7267         /*
7268          * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7269          * are not freed from within this routine; they will be freed from the
7270          * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7271          */
7272         if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7273           ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7274             ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7275         } else {
7276             if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7277                 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7278                                                   arg1, arg2);
7279             } else {
7280                 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7281                                                   arg2, arg1);
7282             }
7283         }
7284         return(ret);
7285     }
7286
7287     if (arg1->type != XPATH_NUMBER) {
7288         valuePush(ctxt, arg1);
7289         xmlXPathNumberFunction(ctxt, 1);
7290         arg1 = valuePop(ctxt);
7291     }
7292     if (arg1->type != XPATH_NUMBER) {
7293         xmlXPathFreeObject(arg1);
7294         xmlXPathFreeObject(arg2);
7295         XP_ERROR0(XPATH_INVALID_OPERAND);
7296     }
7297     if (arg2->type != XPATH_NUMBER) {
7298         valuePush(ctxt, arg2);
7299         xmlXPathNumberFunction(ctxt, 1);
7300         arg2 = valuePop(ctxt);
7301     }
7302     if (arg2->type != XPATH_NUMBER) {
7303         xmlXPathReleaseObject(ctxt->context, arg1);
7304         xmlXPathReleaseObject(ctxt->context, arg2);
7305         XP_ERROR0(XPATH_INVALID_OPERAND);
7306     }
7307     /*
7308      * Add tests for infinity and nan
7309      * => feedback on 3.4 for Inf and NaN
7310      */
7311     /* Hand check NaN and Infinity comparisons */
7312     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7313         ret=0;
7314     } else {
7315         arg1i=xmlXPathIsInf(arg1->floatval);
7316         arg2i=xmlXPathIsInf(arg2->floatval);
7317         if (inf && strict) {
7318             if ((arg1i == -1 && arg2i != -1) ||
7319                 (arg2i == 1 && arg1i != 1)) {
7320                 ret = 1;
7321             } else if (arg1i == 0 && arg2i == 0) {
7322                 ret = (arg1->floatval < arg2->floatval);
7323             } else {
7324                 ret = 0;
7325             }
7326         }
7327         else if (inf && !strict) {
7328             if (arg1i == -1 || arg2i == 1) {
7329                 ret = 1;
7330             } else if (arg1i == 0 && arg2i == 0) {
7331                 ret = (arg1->floatval <= arg2->floatval);
7332             } else {
7333                 ret = 0;
7334             }
7335         }
7336         else if (!inf && strict) {
7337             if ((arg1i == 1 && arg2i != 1) ||
7338                 (arg2i == -1 && arg1i != -1)) {
7339                 ret = 1;
7340             } else if (arg1i == 0 && arg2i == 0) {
7341                 ret = (arg1->floatval > arg2->floatval);
7342             } else {
7343                 ret = 0;
7344             }
7345         }
7346         else if (!inf && !strict) {
7347             if (arg1i == 1 || arg2i == -1) {
7348                 ret = 1;
7349             } else if (arg1i == 0 && arg2i == 0) {
7350                 ret = (arg1->floatval >= arg2->floatval);
7351             } else {
7352                 ret = 0;
7353             }
7354         }
7355     }
7356     xmlXPathReleaseObject(ctxt->context, arg1);
7357     xmlXPathReleaseObject(ctxt->context, arg2);
7358     return(ret);
7359 }
7360
7361 /**
7362  * xmlXPathValueFlipSign:
7363  * @ctxt:  the XPath Parser context
7364  *
7365  * Implement the unary - operation on an XPath object
7366  * The numeric operators convert their operands to numbers as if
7367  * by calling the number function.
7368  */
7369 void
7370 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7371     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7372     CAST_TO_NUMBER;
7373     CHECK_TYPE(XPATH_NUMBER);
7374     if (xmlXPathIsNaN(ctxt->value->floatval))
7375         ctxt->value->floatval=xmlXPathNAN;
7376     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7377         ctxt->value->floatval=xmlXPathNINF;
7378     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7379         ctxt->value->floatval=xmlXPathPINF;
7380     else if (ctxt->value->floatval == 0) {
7381         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7382             ctxt->value->floatval = xmlXPathNZERO;
7383         else
7384             ctxt->value->floatval = 0;
7385     }
7386     else
7387         ctxt->value->floatval = - ctxt->value->floatval;
7388 }
7389
7390 /**
7391  * xmlXPathAddValues:
7392  * @ctxt:  the XPath Parser context
7393  *
7394  * Implement the add operation on XPath objects:
7395  * The numeric operators convert their operands to numbers as if
7396  * by calling the number function.
7397  */
7398 void
7399 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7400     xmlXPathObjectPtr arg;
7401     double val;
7402
7403     arg = valuePop(ctxt);
7404     if (arg == NULL)
7405         XP_ERROR(XPATH_INVALID_OPERAND);
7406     val = xmlXPathCastToNumber(arg);
7407     xmlXPathReleaseObject(ctxt->context, arg);
7408     CAST_TO_NUMBER;
7409     CHECK_TYPE(XPATH_NUMBER);
7410     ctxt->value->floatval += val;
7411 }
7412
7413 /**
7414  * xmlXPathSubValues:
7415  * @ctxt:  the XPath Parser context
7416  *
7417  * Implement the subtraction operation on XPath objects:
7418  * The numeric operators convert their operands to numbers as if
7419  * by calling the number function.
7420  */
7421 void
7422 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7423     xmlXPathObjectPtr arg;
7424     double val;
7425
7426     arg = valuePop(ctxt);
7427     if (arg == NULL)
7428         XP_ERROR(XPATH_INVALID_OPERAND);
7429     val = xmlXPathCastToNumber(arg);
7430     xmlXPathReleaseObject(ctxt->context, arg);
7431     CAST_TO_NUMBER;
7432     CHECK_TYPE(XPATH_NUMBER);
7433     ctxt->value->floatval -= val;
7434 }
7435
7436 /**
7437  * xmlXPathMultValues:
7438  * @ctxt:  the XPath Parser context
7439  *
7440  * Implement the multiply operation on XPath objects:
7441  * The numeric operators convert their operands to numbers as if
7442  * by calling the number function.
7443  */
7444 void
7445 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7446     xmlXPathObjectPtr arg;
7447     double val;
7448
7449     arg = valuePop(ctxt);
7450     if (arg == NULL)
7451         XP_ERROR(XPATH_INVALID_OPERAND);
7452     val = xmlXPathCastToNumber(arg);
7453     xmlXPathReleaseObject(ctxt->context, arg);
7454     CAST_TO_NUMBER;
7455     CHECK_TYPE(XPATH_NUMBER);
7456     ctxt->value->floatval *= val;
7457 }
7458
7459 /**
7460  * xmlXPathDivValues:
7461  * @ctxt:  the XPath Parser context
7462  *
7463  * Implement the div operation on XPath objects @arg1 / @arg2:
7464  * The numeric operators convert their operands to numbers as if
7465  * by calling the number function.
7466  */
7467 void
7468 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7469     xmlXPathObjectPtr arg;
7470     double val;
7471
7472     arg = valuePop(ctxt);
7473     if (arg == NULL)
7474         XP_ERROR(XPATH_INVALID_OPERAND);
7475     val = xmlXPathCastToNumber(arg);
7476     xmlXPathReleaseObject(ctxt->context, arg);
7477     CAST_TO_NUMBER;
7478     CHECK_TYPE(XPATH_NUMBER);
7479     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7480         ctxt->value->floatval = xmlXPathNAN;
7481     else if (val == 0 && xmlXPathGetSign(val) != 0) {
7482         if (ctxt->value->floatval == 0)
7483             ctxt->value->floatval = xmlXPathNAN;
7484         else if (ctxt->value->floatval > 0)
7485             ctxt->value->floatval = xmlXPathNINF;
7486         else if (ctxt->value->floatval < 0)
7487             ctxt->value->floatval = xmlXPathPINF;
7488     }
7489     else if (val == 0) {
7490         if (ctxt->value->floatval == 0)
7491             ctxt->value->floatval = xmlXPathNAN;
7492         else if (ctxt->value->floatval > 0)
7493             ctxt->value->floatval = xmlXPathPINF;
7494         else if (ctxt->value->floatval < 0)
7495             ctxt->value->floatval = xmlXPathNINF;
7496     } else
7497         ctxt->value->floatval /= val;
7498 }
7499
7500 /**
7501  * xmlXPathModValues:
7502  * @ctxt:  the XPath Parser context
7503  *
7504  * Implement the mod operation on XPath objects: @arg1 / @arg2
7505  * The numeric operators convert their operands to numbers as if
7506  * by calling the number function.
7507  */
7508 void
7509 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7510     xmlXPathObjectPtr arg;
7511     double arg1, arg2;
7512
7513     arg = valuePop(ctxt);
7514     if (arg == NULL)
7515         XP_ERROR(XPATH_INVALID_OPERAND);
7516     arg2 = xmlXPathCastToNumber(arg);
7517     xmlXPathReleaseObject(ctxt->context, arg);
7518     CAST_TO_NUMBER;
7519     CHECK_TYPE(XPATH_NUMBER);
7520     arg1 = ctxt->value->floatval;
7521     if (arg2 == 0)
7522         ctxt->value->floatval = xmlXPathNAN;
7523     else {
7524         ctxt->value->floatval = fmod(arg1, arg2);
7525     }
7526 }
7527
7528 /************************************************************************
7529  *                                                                      *
7530  *              The traversal functions                                 *
7531  *                                                                      *
7532  ************************************************************************/
7533
7534 /*
7535  * A traversal function enumerates nodes along an axis.
7536  * Initially it must be called with NULL, and it indicates
7537  * termination on the axis by returning NULL.
7538  */
7539 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7540                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7541
7542 /*
7543  * xmlXPathTraversalFunctionExt:
7544  * A traversal function enumerates nodes along an axis.
7545  * Initially it must be called with NULL, and it indicates
7546  * termination on the axis by returning NULL.
7547  * The context node of the traversal is specified via @contextNode.
7548  */
7549 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7550                     (xmlNodePtr cur, xmlNodePtr contextNode);
7551
7552 /*
7553  * xmlXPathNodeSetMergeFunction:
7554  * Used for merging node sets in xmlXPathCollectAndTest().
7555  */
7556 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7557                     (xmlNodeSetPtr, xmlNodeSetPtr, int);
7558
7559
7560 /**
7561  * xmlXPathNextSelf:
7562  * @ctxt:  the XPath Parser context
7563  * @cur:  the current node in the traversal
7564  *
7565  * Traversal function for the "self" direction
7566  * The self axis contains just the context node itself
7567  *
7568  * Returns the next element following that axis
7569  */
7570 xmlNodePtr
7571 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7572     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7573     if (cur == NULL)
7574         return(ctxt->context->node);
7575     return(NULL);
7576 }
7577
7578 /**
7579  * xmlXPathNextChild:
7580  * @ctxt:  the XPath Parser context
7581  * @cur:  the current node in the traversal
7582  *
7583  * Traversal function for the "child" direction
7584  * The child axis contains the children of the context node in document order.
7585  *
7586  * Returns the next element following that axis
7587  */
7588 xmlNodePtr
7589 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7590     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7591     if (cur == NULL) {
7592         if (ctxt->context->node == NULL) return(NULL);
7593         switch (ctxt->context->node->type) {
7594             case XML_ELEMENT_NODE:
7595             case XML_TEXT_NODE:
7596             case XML_CDATA_SECTION_NODE:
7597             case XML_ENTITY_REF_NODE:
7598             case XML_ENTITY_NODE:
7599             case XML_PI_NODE:
7600             case XML_COMMENT_NODE:
7601             case XML_NOTATION_NODE:
7602             case XML_DTD_NODE:
7603                 return(ctxt->context->node->children);
7604             case XML_DOCUMENT_NODE:
7605             case XML_DOCUMENT_TYPE_NODE:
7606             case XML_DOCUMENT_FRAG_NODE:
7607             case XML_HTML_DOCUMENT_NODE:
7608 #ifdef LIBXML_DOCB_ENABLED
7609             case XML_DOCB_DOCUMENT_NODE:
7610 #endif
7611                 return(((xmlDocPtr) ctxt->context->node)->children);
7612             case XML_ELEMENT_DECL:
7613             case XML_ATTRIBUTE_DECL:
7614             case XML_ENTITY_DECL:
7615             case XML_ATTRIBUTE_NODE:
7616             case XML_NAMESPACE_DECL:
7617             case XML_XINCLUDE_START:
7618             case XML_XINCLUDE_END:
7619                 return(NULL);
7620         }
7621         return(NULL);
7622     }
7623     if ((cur->type == XML_DOCUMENT_NODE) ||
7624         (cur->type == XML_HTML_DOCUMENT_NODE))
7625         return(NULL);
7626     return(cur->next);
7627 }
7628
7629 /**
7630  * xmlXPathNextChildElement:
7631  * @ctxt:  the XPath Parser context
7632  * @cur:  the current node in the traversal
7633  *
7634  * Traversal function for the "child" direction and nodes of type element.
7635  * The child axis contains the children of the context node in document order.
7636  *
7637  * Returns the next element following that axis
7638  */
7639 static xmlNodePtr
7640 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7641     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7642     if (cur == NULL) {
7643         cur = ctxt->context->node;
7644         if (cur == NULL) return(NULL);
7645         /*
7646         * Get the first element child.
7647         */
7648         switch (cur->type) {
7649             case XML_ELEMENT_NODE:
7650             case XML_DOCUMENT_FRAG_NODE:
7651             case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7652             case XML_ENTITY_NODE:
7653                 cur = cur->children;
7654                 if (cur != NULL) {
7655                     if (cur->type == XML_ELEMENT_NODE)
7656                         return(cur);
7657                     do {
7658                         cur = cur->next;
7659                     } while ((cur != NULL) &&
7660                         (cur->type != XML_ELEMENT_NODE));
7661                     return(cur);
7662                 }
7663                 return(NULL);
7664             case XML_DOCUMENT_NODE:
7665             case XML_HTML_DOCUMENT_NODE:
7666 #ifdef LIBXML_DOCB_ENABLED
7667             case XML_DOCB_DOCUMENT_NODE:
7668 #endif
7669                 return(xmlDocGetRootElement((xmlDocPtr) cur));
7670             default:
7671                 return(NULL);
7672         }
7673         return(NULL);
7674     }
7675     /*
7676     * Get the next sibling element node.
7677     */
7678     switch (cur->type) {
7679         case XML_ELEMENT_NODE:
7680         case XML_TEXT_NODE:
7681         case XML_ENTITY_REF_NODE:
7682         case XML_ENTITY_NODE:
7683         case XML_CDATA_SECTION_NODE:
7684         case XML_PI_NODE:
7685         case XML_COMMENT_NODE:
7686         case XML_XINCLUDE_END:
7687             break;
7688         /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7689         default:
7690             return(NULL);
7691     }
7692     if (cur->next != NULL) {
7693         if (cur->next->type == XML_ELEMENT_NODE)
7694             return(cur->next);
7695         cur = cur->next;
7696         do {
7697             cur = cur->next;
7698         } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7699         return(cur);
7700     }
7701     return(NULL);
7702 }
7703
7704 /**
7705  * xmlXPathNextDescendantOrSelfElemParent:
7706  * @ctxt:  the XPath Parser context
7707  * @cur:  the current node in the traversal
7708  *
7709  * Traversal function for the "descendant-or-self" axis.
7710  * Additionally it returns only nodes which can be parents of
7711  * element nodes.
7712  *
7713  *
7714  * Returns the next element following that axis
7715  */
7716 static xmlNodePtr
7717 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7718                                        xmlNodePtr contextNode)
7719 {
7720     if (cur == NULL) {
7721         if (contextNode == NULL)
7722             return(NULL);
7723         switch (contextNode->type) {
7724             case XML_ELEMENT_NODE:
7725             case XML_XINCLUDE_START:
7726             case XML_DOCUMENT_FRAG_NODE:
7727             case XML_DOCUMENT_NODE:
7728 #ifdef LIBXML_DOCB_ENABLED
7729             case XML_DOCB_DOCUMENT_NODE:
7730 #endif
7731             case XML_HTML_DOCUMENT_NODE:            
7732                 return(contextNode);
7733             default:
7734                 return(NULL);
7735         }
7736         return(NULL);
7737     } else {
7738         xmlNodePtr start = cur;
7739
7740         while (cur != NULL) {
7741             switch (cur->type) {
7742                 case XML_ELEMENT_NODE:
7743                 /* TODO: OK to have XInclude here? */
7744                 case XML_XINCLUDE_START:
7745                 case XML_DOCUMENT_FRAG_NODE:
7746                     if (cur != start)
7747                         return(cur);
7748                     if (cur->children != NULL) {
7749                         cur = cur->children;
7750                         continue;
7751                     }
7752                     break;
7753                 /* Not sure if we need those here. */
7754                 case XML_DOCUMENT_NODE:
7755 #ifdef LIBXML_DOCB_ENABLED
7756                 case XML_DOCB_DOCUMENT_NODE:
7757 #endif
7758                 case XML_HTML_DOCUMENT_NODE:
7759                     if (cur != start)
7760                         return(cur);
7761                     return(xmlDocGetRootElement((xmlDocPtr) cur));
7762                 default:
7763                     break;
7764             }
7765
7766 next_sibling:
7767             if ((cur == NULL) || (cur == contextNode))
7768                 return(NULL);
7769             if (cur->next != NULL) {
7770                 cur = cur->next;
7771             } else {
7772                 cur = cur->parent;
7773                 goto next_sibling;
7774             }
7775         }
7776     }
7777     return(NULL);
7778 }
7779
7780 /**
7781  * xmlXPathNextDescendant:
7782  * @ctxt:  the XPath Parser context
7783  * @cur:  the current node in the traversal
7784  *
7785  * Traversal function for the "descendant" direction
7786  * the descendant axis contains the descendants of the context node in document
7787  * order; a descendant is a child or a child of a child and so on.
7788  *
7789  * Returns the next element following that axis
7790  */
7791 xmlNodePtr
7792 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7793     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7794     if (cur == NULL) {
7795         if (ctxt->context->node == NULL)
7796             return(NULL);
7797         if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7798             (ctxt->context->node->type == XML_NAMESPACE_DECL))
7799             return(NULL);
7800
7801         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7802             return(ctxt->context->doc->children);
7803         return(ctxt->context->node->children);
7804     }
7805
7806     if (cur->children != NULL) {
7807         /*
7808          * Do not descend on entities declarations
7809          */
7810         if (cur->children->type != XML_ENTITY_DECL) {
7811             cur = cur->children;
7812             /*
7813              * Skip DTDs
7814              */
7815             if (cur->type != XML_DTD_NODE)
7816                 return(cur);
7817         }
7818     }
7819
7820     if (cur == ctxt->context->node) return(NULL);
7821
7822     while (cur->next != NULL) {
7823         cur = cur->next;
7824         if ((cur->type != XML_ENTITY_DECL) &&
7825             (cur->type != XML_DTD_NODE))
7826             return(cur);
7827     }
7828
7829     do {
7830         cur = cur->parent;
7831         if (cur == NULL) break;
7832         if (cur == ctxt->context->node) return(NULL);
7833         if (cur->next != NULL) {
7834             cur = cur->next;
7835             return(cur);
7836         }
7837     } while (cur != NULL);
7838     return(cur);
7839 }
7840
7841 /**
7842  * xmlXPathNextDescendantOrSelf:
7843  * @ctxt:  the XPath Parser context
7844  * @cur:  the current node in the traversal
7845  *
7846  * Traversal function for the "descendant-or-self" direction
7847  * the descendant-or-self axis contains the context node and the descendants
7848  * of the context node in document order; thus the context node is the first
7849  * node on the axis, and the first child of the context node is the second node
7850  * on the axis
7851  *
7852  * Returns the next element following that axis
7853  */
7854 xmlNodePtr
7855 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7856     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7857     if (cur == NULL) {
7858         if (ctxt->context->node == NULL)
7859             return(NULL);
7860         if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7861             (ctxt->context->node->type == XML_NAMESPACE_DECL))
7862             return(NULL);
7863         return(ctxt->context->node);
7864     }
7865
7866     return(xmlXPathNextDescendant(ctxt, cur));
7867 }
7868
7869 /**
7870  * xmlXPathNextParent:
7871  * @ctxt:  the XPath Parser context
7872  * @cur:  the current node in the traversal
7873  *
7874  * Traversal function for the "parent" direction
7875  * The parent axis contains the parent of the context node, if there is one.
7876  *
7877  * Returns the next element following that axis
7878  */
7879 xmlNodePtr
7880 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7881     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7882     /*
7883      * the parent of an attribute or namespace node is the element
7884      * to which the attribute or namespace node is attached
7885      * Namespace handling !!!
7886      */
7887     if (cur == NULL) {
7888         if (ctxt->context->node == NULL) return(NULL);
7889         switch (ctxt->context->node->type) {
7890             case XML_ELEMENT_NODE:
7891             case XML_TEXT_NODE:
7892             case XML_CDATA_SECTION_NODE:
7893             case XML_ENTITY_REF_NODE:
7894             case XML_ENTITY_NODE:
7895             case XML_PI_NODE:
7896             case XML_COMMENT_NODE:
7897             case XML_NOTATION_NODE:
7898             case XML_DTD_NODE:
7899             case XML_ELEMENT_DECL:
7900             case XML_ATTRIBUTE_DECL:
7901             case XML_XINCLUDE_START:
7902             case XML_XINCLUDE_END:
7903             case XML_ENTITY_DECL:
7904                 if (ctxt->context->node->parent == NULL)
7905                     return((xmlNodePtr) ctxt->context->doc);
7906                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7907                     ((ctxt->context->node->parent->name[0] == ' ') ||
7908                      (xmlStrEqual(ctxt->context->node->parent->name,
7909                                  BAD_CAST "fake node libxslt"))))
7910                     return(NULL);
7911                 return(ctxt->context->node->parent);
7912             case XML_ATTRIBUTE_NODE: {
7913                 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7914
7915                 return(att->parent);
7916             }
7917             case XML_DOCUMENT_NODE:
7918             case XML_DOCUMENT_TYPE_NODE:
7919             case XML_DOCUMENT_FRAG_NODE:
7920             case XML_HTML_DOCUMENT_NODE:
7921 #ifdef LIBXML_DOCB_ENABLED
7922             case XML_DOCB_DOCUMENT_NODE:
7923 #endif
7924                 return(NULL);
7925             case XML_NAMESPACE_DECL: {
7926                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7927
7928                 if ((ns->next != NULL) &&
7929                     (ns->next->type != XML_NAMESPACE_DECL))
7930                     return((xmlNodePtr) ns->next);
7931                 return(NULL);
7932             }
7933         }
7934     }
7935     return(NULL);
7936 }
7937
7938 /**
7939  * xmlXPathNextAncestor:
7940  * @ctxt:  the XPath Parser context
7941  * @cur:  the current node in the traversal
7942  *
7943  * Traversal function for the "ancestor" direction
7944  * the ancestor axis contains the ancestors of the context node; the ancestors
7945  * of the context node consist of the parent of context node and the parent's
7946  * parent and so on; the nodes are ordered in reverse document order; thus the
7947  * parent is the first node on the axis, and the parent's parent is the second
7948  * node on the axis
7949  *
7950  * Returns the next element following that axis
7951  */
7952 xmlNodePtr
7953 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7954     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7955     /*
7956      * the parent of an attribute or namespace node is the element
7957      * to which the attribute or namespace node is attached
7958      * !!!!!!!!!!!!!
7959      */
7960     if (cur == NULL) {
7961         if (ctxt->context->node == NULL) return(NULL);
7962         switch (ctxt->context->node->type) {
7963             case XML_ELEMENT_NODE:
7964             case XML_TEXT_NODE:
7965             case XML_CDATA_SECTION_NODE:
7966             case XML_ENTITY_REF_NODE:
7967             case XML_ENTITY_NODE:
7968             case XML_PI_NODE:
7969             case XML_COMMENT_NODE:
7970             case XML_DTD_NODE:
7971             case XML_ELEMENT_DECL:
7972             case XML_ATTRIBUTE_DECL:
7973             case XML_ENTITY_DECL:
7974             case XML_NOTATION_NODE:
7975             case XML_XINCLUDE_START:
7976             case XML_XINCLUDE_END:
7977                 if (ctxt->context->node->parent == NULL)
7978                     return((xmlNodePtr) ctxt->context->doc);
7979                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7980                     ((ctxt->context->node->parent->name[0] == ' ') ||
7981                      (xmlStrEqual(ctxt->context->node->parent->name,
7982                                  BAD_CAST "fake node libxslt"))))
7983                     return(NULL);
7984                 return(ctxt->context->node->parent);
7985             case XML_ATTRIBUTE_NODE: {
7986                 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7987
7988                 return(tmp->parent);
7989             }
7990             case XML_DOCUMENT_NODE:
7991             case XML_DOCUMENT_TYPE_NODE:
7992             case XML_DOCUMENT_FRAG_NODE:
7993             case XML_HTML_DOCUMENT_NODE:
7994 #ifdef LIBXML_DOCB_ENABLED
7995             case XML_DOCB_DOCUMENT_NODE:
7996 #endif
7997                 return(NULL);
7998             case XML_NAMESPACE_DECL: {
7999                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8000
8001                 if ((ns->next != NULL) &&
8002                     (ns->next->type != XML_NAMESPACE_DECL))
8003                     return((xmlNodePtr) ns->next);
8004                 /* Bad, how did that namespace end up here ? */
8005                 return(NULL);
8006             }
8007         }
8008         return(NULL);
8009     }
8010     if (cur == ctxt->context->doc->children)
8011         return((xmlNodePtr) ctxt->context->doc);
8012     if (cur == (xmlNodePtr) ctxt->context->doc)
8013         return(NULL);
8014     switch (cur->type) {
8015         case XML_ELEMENT_NODE:
8016         case XML_TEXT_NODE:
8017         case XML_CDATA_SECTION_NODE:
8018         case XML_ENTITY_REF_NODE:
8019         case XML_ENTITY_NODE:
8020         case XML_PI_NODE:
8021         case XML_COMMENT_NODE:
8022         case XML_NOTATION_NODE:
8023         case XML_DTD_NODE:
8024         case XML_ELEMENT_DECL:
8025         case XML_ATTRIBUTE_DECL:
8026         case XML_ENTITY_DECL:
8027         case XML_XINCLUDE_START:
8028         case XML_XINCLUDE_END:
8029             if (cur->parent == NULL)
8030                 return(NULL);
8031             if ((cur->parent->type == XML_ELEMENT_NODE) &&
8032                 ((cur->parent->name[0] == ' ') ||
8033                  (xmlStrEqual(cur->parent->name,
8034                               BAD_CAST "fake node libxslt"))))
8035                 return(NULL);
8036             return(cur->parent);
8037         case XML_ATTRIBUTE_NODE: {
8038             xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8039
8040             return(att->parent);
8041         }
8042         case XML_NAMESPACE_DECL: {
8043             xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8044
8045             if ((ns->next != NULL) &&
8046                 (ns->next->type != XML_NAMESPACE_DECL))
8047                 return((xmlNodePtr) ns->next);
8048             /* Bad, how did that namespace end up here ? */
8049             return(NULL);
8050         }
8051         case XML_DOCUMENT_NODE:
8052         case XML_DOCUMENT_TYPE_NODE:
8053         case XML_DOCUMENT_FRAG_NODE:
8054         case XML_HTML_DOCUMENT_NODE:
8055 #ifdef LIBXML_DOCB_ENABLED
8056         case XML_DOCB_DOCUMENT_NODE:
8057 #endif
8058             return(NULL);
8059     }
8060     return(NULL);
8061 }
8062
8063 /**
8064  * xmlXPathNextAncestorOrSelf:
8065  * @ctxt:  the XPath Parser context
8066  * @cur:  the current node in the traversal
8067  *
8068  * Traversal function for the "ancestor-or-self" direction
8069  * he ancestor-or-self axis contains the context node and ancestors of
8070  * the context node in reverse document order; thus the context node is
8071  * the first node on the axis, and the context node's parent the second;
8072  * parent here is defined the same as with the parent axis.
8073  *
8074  * Returns the next element following that axis
8075  */
8076 xmlNodePtr
8077 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8078     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8079     if (cur == NULL)
8080         return(ctxt->context->node);
8081     return(xmlXPathNextAncestor(ctxt, cur));
8082 }
8083
8084 /**
8085  * xmlXPathNextFollowingSibling:
8086  * @ctxt:  the XPath Parser context
8087  * @cur:  the current node in the traversal
8088  *
8089  * Traversal function for the "following-sibling" direction
8090  * The following-sibling axis contains the following siblings of the context
8091  * node in document order.
8092  *
8093  * Returns the next element following that axis
8094  */
8095 xmlNodePtr
8096 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8097     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8098     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8099         (ctxt->context->node->type == XML_NAMESPACE_DECL))
8100         return(NULL);
8101     if (cur == (xmlNodePtr) ctxt->context->doc)
8102         return(NULL);
8103     if (cur == NULL)
8104         return(ctxt->context->node->next);
8105     return(cur->next);
8106 }
8107
8108 /**
8109  * xmlXPathNextPrecedingSibling:
8110  * @ctxt:  the XPath Parser context
8111  * @cur:  the current node in the traversal
8112  *
8113  * Traversal function for the "preceding-sibling" direction
8114  * The preceding-sibling axis contains the preceding siblings of the context
8115  * node in reverse document order; the first preceding sibling is first on the
8116  * axis; the sibling preceding that node is the second on the axis and so on.
8117  *
8118  * Returns the next element following that axis
8119  */
8120 xmlNodePtr
8121 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8122     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8123     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8124         (ctxt->context->node->type == XML_NAMESPACE_DECL))
8125         return(NULL);
8126     if (cur == (xmlNodePtr) ctxt->context->doc)
8127         return(NULL);
8128     if (cur == NULL)
8129         return(ctxt->context->node->prev);
8130     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8131         cur = cur->prev;
8132         if (cur == NULL)
8133             return(ctxt->context->node->prev);
8134     }
8135     return(cur->prev);
8136 }
8137
8138 /**
8139  * xmlXPathNextFollowing:
8140  * @ctxt:  the XPath Parser context
8141  * @cur:  the current node in the traversal
8142  *
8143  * Traversal function for the "following" direction
8144  * The following axis contains all nodes in the same document as the context
8145  * node that are after the context node in document order, excluding any
8146  * descendants and excluding attribute nodes and namespace nodes; the nodes
8147  * are ordered in document order
8148  *
8149  * Returns the next element following that axis
8150  */
8151 xmlNodePtr
8152 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8153     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8154     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8155         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8156         return(cur->children);
8157
8158     if (cur == NULL) {
8159         cur = ctxt->context->node;
8160         if (cur->type == XML_NAMESPACE_DECL)
8161             return(NULL);
8162         if (cur->type == XML_ATTRIBUTE_NODE)
8163             cur = cur->parent;
8164     }
8165     if (cur == NULL) return(NULL) ; /* ERROR */
8166     if (cur->next != NULL) return(cur->next) ;
8167     do {
8168         cur = cur->parent;
8169         if (cur == NULL) break;
8170         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8171         if (cur->next != NULL) return(cur->next);
8172     } while (cur != NULL);
8173     return(cur);
8174 }
8175
8176 /*
8177  * xmlXPathIsAncestor:
8178  * @ancestor:  the ancestor node
8179  * @node:  the current node
8180  *
8181  * Check that @ancestor is a @node's ancestor
8182  *
8183  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8184  */
8185 static int
8186 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8187     if ((ancestor == NULL) || (node == NULL)) return(0);
8188     /* nodes need to be in the same document */
8189     if (ancestor->doc != node->doc) return(0);
8190     /* avoid searching if ancestor or node is the root node */
8191     if (ancestor == (xmlNodePtr) node->doc) return(1);
8192     if (node == (xmlNodePtr) ancestor->doc) return(0);
8193     while (node->parent != NULL) {
8194         if (node->parent == ancestor)
8195             return(1);
8196         node = node->parent;
8197     }
8198     return(0);
8199 }
8200
8201 /**
8202  * xmlXPathNextPreceding:
8203  * @ctxt:  the XPath Parser context
8204  * @cur:  the current node in the traversal
8205  *
8206  * Traversal function for the "preceding" direction
8207  * the preceding axis contains all nodes in the same document as the context
8208  * node that are before the context node in document order, excluding any
8209  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8210  * ordered in reverse document order
8211  *
8212  * Returns the next element following that axis
8213  */
8214 xmlNodePtr
8215 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8216 {
8217     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8218     if (cur == NULL) {
8219         cur = ctxt->context->node;
8220         if (cur->type == XML_NAMESPACE_DECL)
8221             return(NULL);
8222         if (cur->type == XML_ATTRIBUTE_NODE)
8223             return(cur->parent);
8224     }
8225     if (cur == NULL)
8226         return (NULL);
8227     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8228         cur = cur->prev;
8229     do {
8230         if (cur->prev != NULL) {
8231             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8232             return (cur);
8233         }
8234
8235         cur = cur->parent;
8236         if (cur == NULL)
8237             return (NULL);
8238         if (cur == ctxt->context->doc->children)
8239             return (NULL);
8240     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8241     return (cur);
8242 }
8243
8244 /**
8245  * xmlXPathNextPrecedingInternal:
8246  * @ctxt:  the XPath Parser context
8247  * @cur:  the current node in the traversal
8248  *
8249  * Traversal function for the "preceding" direction
8250  * the preceding axis contains all nodes in the same document as the context
8251  * node that are before the context node in document order, excluding any
8252  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8253  * ordered in reverse document order
8254  * This is a faster implementation but internal only since it requires a
8255  * state kept in the parser context: ctxt->ancestor.
8256  *
8257  * Returns the next element following that axis
8258  */
8259 static xmlNodePtr
8260 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8261                               xmlNodePtr cur)
8262 {
8263     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8264     if (cur == NULL) {
8265         cur = ctxt->context->node;
8266         if (cur == NULL)
8267             return (NULL);
8268         if (cur->type == XML_NAMESPACE_DECL)
8269             return (NULL);
8270         ctxt->ancestor = cur->parent;
8271     }
8272     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8273         cur = cur->prev;
8274     while (cur->prev == NULL) {
8275         cur = cur->parent;
8276         if (cur == NULL)
8277             return (NULL);
8278         if (cur == ctxt->context->doc->children)
8279             return (NULL);
8280         if (cur != ctxt->ancestor)
8281             return (cur);
8282         ctxt->ancestor = cur->parent;
8283     }
8284     cur = cur->prev;
8285     while (cur->last != NULL)
8286         cur = cur->last;
8287     return (cur);
8288 }
8289
8290 /**
8291  * xmlXPathNextNamespace:
8292  * @ctxt:  the XPath Parser context
8293  * @cur:  the current attribute in the traversal
8294  *
8295  * Traversal function for the "namespace" direction
8296  * the namespace axis contains the namespace nodes of the context node;
8297  * the order of nodes on this axis is implementation-defined; the axis will
8298  * be empty unless the context node is an element
8299  *
8300  * We keep the XML namespace node at the end of the list.
8301  *
8302  * Returns the next element following that axis
8303  */
8304 xmlNodePtr
8305 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8306     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8307     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8308     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8309         if (ctxt->context->tmpNsList != NULL)
8310             xmlFree(ctxt->context->tmpNsList);
8311         ctxt->context->tmpNsList =
8312             xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8313         ctxt->context->tmpNsNr = 0;
8314         if (ctxt->context->tmpNsList != NULL) {
8315             while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8316                 ctxt->context->tmpNsNr++;
8317             }
8318         }
8319         return((xmlNodePtr) xmlXPathXMLNamespace);
8320     }
8321     if (ctxt->context->tmpNsNr > 0) {
8322         return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8323     } else {
8324         if (ctxt->context->tmpNsList != NULL)
8325             xmlFree(ctxt->context->tmpNsList);
8326         ctxt->context->tmpNsList = NULL;
8327         return(NULL);
8328     }
8329 }
8330
8331 /**
8332  * xmlXPathNextAttribute:
8333  * @ctxt:  the XPath Parser context
8334  * @cur:  the current attribute in the traversal
8335  *
8336  * Traversal function for the "attribute" direction
8337  * TODO: support DTD inherited default attributes
8338  *
8339  * Returns the next element following that axis
8340  */
8341 xmlNodePtr
8342 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8343     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8344     if (ctxt->context->node == NULL)
8345         return(NULL);
8346     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8347         return(NULL);
8348     if (cur == NULL) {
8349         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8350             return(NULL);
8351         return((xmlNodePtr)ctxt->context->node->properties);
8352     }
8353     return((xmlNodePtr)cur->next);
8354 }
8355
8356 /************************************************************************
8357  *                                                                      *
8358  *              NodeTest Functions                                      *
8359  *                                                                      *
8360  ************************************************************************/
8361
8362 #define IS_FUNCTION                     200
8363
8364
8365 /************************************************************************
8366  *                                                                      *
8367  *              Implicit tree core function library                     *
8368  *                                                                      *
8369  ************************************************************************/
8370
8371 /**
8372  * xmlXPathRoot:
8373  * @ctxt:  the XPath Parser context
8374  *
8375  * Initialize the context to the root of the document
8376  */
8377 void
8378 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8379     if ((ctxt == NULL) || (ctxt->context == NULL))
8380         return;
8381     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8382     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8383         ctxt->context->node));
8384 }
8385
8386 /************************************************************************
8387  *                                                                      *
8388  *              The explicit core function library                      *
8389  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8390  *                                                                      *
8391  ************************************************************************/
8392
8393
8394 /**
8395  * xmlXPathLastFunction:
8396  * @ctxt:  the XPath Parser context
8397  * @nargs:  the number of arguments
8398  *
8399  * Implement the last() XPath function
8400  *    number last()
8401  * The last function returns the number of nodes in the context node list.
8402  */
8403 void
8404 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8405     CHECK_ARITY(0);
8406     if (ctxt->context->contextSize >= 0) {
8407         valuePush(ctxt,
8408             xmlXPathCacheNewFloat(ctxt->context,
8409                 (double) ctxt->context->contextSize));
8410 #ifdef DEBUG_EXPR
8411         xmlGenericError(xmlGenericErrorContext,
8412                 "last() : %d\n", ctxt->context->contextSize);
8413 #endif
8414     } else {
8415         XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8416     }
8417 }
8418
8419 /**
8420  * xmlXPathPositionFunction:
8421  * @ctxt:  the XPath Parser context
8422  * @nargs:  the number of arguments
8423  *
8424  * Implement the position() XPath function
8425  *    number position()
8426  * The position function returns the position of the context node in the
8427  * context node list. The first position is 1, and so the last position
8428  * will be equal to last().
8429  */
8430 void
8431 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8432     CHECK_ARITY(0);
8433     if (ctxt->context->proximityPosition >= 0) {
8434         valuePush(ctxt,
8435               xmlXPathCacheNewFloat(ctxt->context,
8436                 (double) ctxt->context->proximityPosition));
8437 #ifdef DEBUG_EXPR
8438         xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8439                 ctxt->context->proximityPosition);
8440 #endif
8441     } else {
8442         XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8443     }
8444 }
8445
8446 /**
8447  * xmlXPathCountFunction:
8448  * @ctxt:  the XPath Parser context
8449  * @nargs:  the number of arguments
8450  *
8451  * Implement the count() XPath function
8452  *    number count(node-set)
8453  */
8454 void
8455 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8456     xmlXPathObjectPtr cur;
8457
8458     CHECK_ARITY(1);
8459     if ((ctxt->value == NULL) ||
8460         ((ctxt->value->type != XPATH_NODESET) &&
8461          (ctxt->value->type != XPATH_XSLT_TREE)))
8462         XP_ERROR(XPATH_INVALID_TYPE);
8463     cur = valuePop(ctxt);
8464
8465     if ((cur == NULL) || (cur->nodesetval == NULL))
8466         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8467     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8468         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8469             (double) cur->nodesetval->nodeNr));
8470     } else {
8471         if ((cur->nodesetval->nodeNr != 1) ||
8472             (cur->nodesetval->nodeTab == NULL)) {
8473             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8474         } else {
8475             xmlNodePtr tmp;
8476             int i = 0;
8477
8478             tmp = cur->nodesetval->nodeTab[0];
8479             if (tmp != NULL) {
8480                 tmp = tmp->children;
8481                 while (tmp != NULL) {
8482                     tmp = tmp->next;
8483                     i++;
8484                 }
8485             }
8486             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8487         }
8488     }
8489     xmlXPathReleaseObject(ctxt->context, cur);
8490 }
8491
8492 /**
8493  * xmlXPathGetElementsByIds:
8494  * @doc:  the document
8495  * @ids:  a whitespace separated list of IDs
8496  *
8497  * Selects elements by their unique ID.
8498  *
8499  * Returns a node-set of selected elements.
8500  */
8501 static xmlNodeSetPtr
8502 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8503     xmlNodeSetPtr ret;
8504     const xmlChar *cur = ids;
8505     xmlChar *ID;
8506     xmlAttrPtr attr;
8507     xmlNodePtr elem = NULL;
8508
8509     if (ids == NULL) return(NULL);
8510
8511     ret = xmlXPathNodeSetCreate(NULL);
8512     if (ret == NULL)
8513         return(ret);
8514
8515     while (IS_BLANK_CH(*cur)) cur++;
8516     while (*cur != 0) {
8517         while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8518             cur++;
8519
8520         ID = xmlStrndup(ids, cur - ids);
8521         if (ID != NULL) {
8522             /*
8523              * We used to check the fact that the value passed
8524              * was an NCName, but this generated much troubles for
8525              * me and Aleksey Sanin, people blatantly violated that
8526              * constaint, like Visa3D spec.
8527              * if (xmlValidateNCName(ID, 1) == 0)
8528              */
8529             attr = xmlGetID(doc, ID);
8530             if (attr != NULL) {
8531                 if (attr->type == XML_ATTRIBUTE_NODE)
8532                     elem = attr->parent;
8533                 else if (attr->type == XML_ELEMENT_NODE)
8534                     elem = (xmlNodePtr) attr;
8535                 else
8536                     elem = NULL;
8537                 if (elem != NULL)
8538                     xmlXPathNodeSetAdd(ret, elem);
8539             }
8540             xmlFree(ID);
8541         }
8542
8543         while (IS_BLANK_CH(*cur)) cur++;
8544         ids = cur;
8545     }
8546     return(ret);
8547 }
8548
8549 /**
8550  * xmlXPathIdFunction:
8551  * @ctxt:  the XPath Parser context
8552  * @nargs:  the number of arguments
8553  *
8554  * Implement the id() XPath function
8555  *    node-set id(object)
8556  * The id function selects elements by their unique ID
8557  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8558  * then the result is the union of the result of applying id to the
8559  * string value of each of the nodes in the argument node-set. When the
8560  * argument to id is of any other type, the argument is converted to a
8561  * string as if by a call to the string function; the string is split
8562  * into a whitespace-separated list of tokens (whitespace is any sequence
8563  * of characters matching the production S); the result is a node-set
8564  * containing the elements in the same document as the context node that
8565  * have a unique ID equal to any of the tokens in the list.
8566  */
8567 void
8568 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8569     xmlChar *tokens;
8570     xmlNodeSetPtr ret;
8571     xmlXPathObjectPtr obj;
8572
8573     CHECK_ARITY(1);
8574     obj = valuePop(ctxt);
8575     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8576     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8577         xmlNodeSetPtr ns;
8578         int i;
8579
8580         ret = xmlXPathNodeSetCreate(NULL);
8581         /*
8582          * FIXME -- in an out-of-memory condition this will behave badly.
8583          * The solution is not clear -- we already popped an item from
8584          * ctxt, so the object is in a corrupt state.
8585          */
8586
8587         if (obj->nodesetval != NULL) {
8588             for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8589                 tokens =
8590                     xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8591                 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8592                 ret = xmlXPathNodeSetMerge(ret, ns);
8593                 xmlXPathFreeNodeSet(ns);
8594                 if (tokens != NULL)
8595                     xmlFree(tokens);
8596             }
8597         }
8598         xmlXPathReleaseObject(ctxt->context, obj);
8599         valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8600         return;
8601     }
8602     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8603     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8604     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8605     xmlXPathReleaseObject(ctxt->context, obj);
8606     return;
8607 }
8608
8609 /**
8610  * xmlXPathLocalNameFunction:
8611  * @ctxt:  the XPath Parser context
8612  * @nargs:  the number of arguments
8613  *
8614  * Implement the local-name() XPath function
8615  *    string local-name(node-set?)
8616  * The local-name function returns a string containing the local part
8617  * of the name of the node in the argument node-set that is first in
8618  * document order. If the node-set is empty or the first node has no
8619  * name, an empty string is returned. If the argument is omitted it
8620  * defaults to the context node.
8621  */
8622 void
8623 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8624     xmlXPathObjectPtr cur;
8625
8626     if (ctxt == NULL) return;
8627
8628     if (nargs == 0) {
8629         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8630             ctxt->context->node));
8631         nargs = 1;
8632     }
8633
8634     CHECK_ARITY(1);
8635     if ((ctxt->value == NULL) ||
8636         ((ctxt->value->type != XPATH_NODESET) &&
8637          (ctxt->value->type != XPATH_XSLT_TREE)))
8638         XP_ERROR(XPATH_INVALID_TYPE);
8639     cur = valuePop(ctxt);
8640
8641     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8642         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8643     } else {
8644         int i = 0; /* Should be first in document order !!!!! */
8645         switch (cur->nodesetval->nodeTab[i]->type) {
8646         case XML_ELEMENT_NODE:
8647         case XML_ATTRIBUTE_NODE:
8648         case XML_PI_NODE:
8649             if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8650                 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8651             else
8652                 valuePush(ctxt,
8653                       xmlXPathCacheNewString(ctxt->context,
8654                         cur->nodesetval->nodeTab[i]->name));
8655             break;
8656         case XML_NAMESPACE_DECL:
8657             valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8658                         ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8659             break;
8660         default:
8661             valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8662         }
8663     }
8664     xmlXPathReleaseObject(ctxt->context, cur);
8665 }
8666
8667 /**
8668  * xmlXPathNamespaceURIFunction:
8669  * @ctxt:  the XPath Parser context
8670  * @nargs:  the number of arguments
8671  *
8672  * Implement the namespace-uri() XPath function
8673  *    string namespace-uri(node-set?)
8674  * The namespace-uri function returns a string containing the
8675  * namespace URI of the expanded name of the node in the argument
8676  * node-set that is first in document order. If the node-set is empty,
8677  * the first node has no name, or the expanded name has no namespace
8678  * URI, an empty string is returned. If the argument is omitted it
8679  * defaults to the context node.
8680  */
8681 void
8682 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8683     xmlXPathObjectPtr cur;
8684
8685     if (ctxt == NULL) return;
8686
8687     if (nargs == 0) {
8688         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8689             ctxt->context->node));
8690         nargs = 1;
8691     }
8692     CHECK_ARITY(1);
8693     if ((ctxt->value == NULL) ||
8694         ((ctxt->value->type != XPATH_NODESET) &&
8695          (ctxt->value->type != XPATH_XSLT_TREE)))
8696         XP_ERROR(XPATH_INVALID_TYPE);
8697     cur = valuePop(ctxt);
8698
8699     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8700         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8701     } else {
8702         int i = 0; /* Should be first in document order !!!!! */
8703         switch (cur->nodesetval->nodeTab[i]->type) {
8704         case XML_ELEMENT_NODE:
8705         case XML_ATTRIBUTE_NODE:
8706             if (cur->nodesetval->nodeTab[i]->ns == NULL)
8707                 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8708             else
8709                 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8710                           cur->nodesetval->nodeTab[i]->ns->href));
8711             break;
8712         default:
8713             valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8714         }
8715     }
8716     xmlXPathReleaseObject(ctxt->context, cur);
8717 }
8718
8719 /**
8720  * xmlXPathNameFunction:
8721  * @ctxt:  the XPath Parser context
8722  * @nargs:  the number of arguments
8723  *
8724  * Implement the name() XPath function
8725  *    string name(node-set?)
8726  * The name function returns a string containing a QName representing
8727  * the name of the node in the argument node-set that is first in document
8728  * order. The QName must represent the name with respect to the namespace
8729  * declarations in effect on the node whose name is being represented.
8730  * Typically, this will be the form in which the name occurred in the XML
8731  * source. This need not be the case if there are namespace declarations
8732  * in effect on the node that associate multiple prefixes with the same
8733  * namespace. However, an implementation may include information about
8734  * the original prefix in its representation of nodes; in this case, an
8735  * implementation can ensure that the returned string is always the same
8736  * as the QName used in the XML source. If the argument it omitted it
8737  * defaults to the context node.
8738  * Libxml keep the original prefix so the "real qualified name" used is
8739  * returned.
8740  */
8741 static void
8742 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8743 {
8744     xmlXPathObjectPtr cur;
8745
8746     if (nargs == 0) {
8747         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8748             ctxt->context->node));
8749         nargs = 1;
8750     }
8751
8752     CHECK_ARITY(1);
8753     if ((ctxt->value == NULL) ||
8754         ((ctxt->value->type != XPATH_NODESET) &&
8755          (ctxt->value->type != XPATH_XSLT_TREE)))
8756         XP_ERROR(XPATH_INVALID_TYPE);
8757     cur = valuePop(ctxt);
8758
8759     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8760         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8761     } else {
8762         int i = 0;              /* Should be first in document order !!!!! */
8763
8764         switch (cur->nodesetval->nodeTab[i]->type) {
8765             case XML_ELEMENT_NODE:
8766             case XML_ATTRIBUTE_NODE:
8767                 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8768                     valuePush(ctxt,
8769                         xmlXPathCacheNewCString(ctxt->context, ""));
8770                 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8771                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8772                     valuePush(ctxt,
8773                         xmlXPathCacheNewString(ctxt->context,
8774                             cur->nodesetval->nodeTab[i]->name));
8775                 } else {
8776                     xmlChar *fullname;
8777
8778                     fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8779                                      cur->nodesetval->nodeTab[i]->ns->prefix,
8780                                      NULL, 0);
8781                     if (fullname == cur->nodesetval->nodeTab[i]->name)
8782                         fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8783                     if (fullname == NULL) {
8784                         XP_ERROR(XPATH_MEMORY_ERROR);
8785                     }
8786                     valuePush(ctxt, xmlXPathCacheWrapString(
8787                         ctxt->context, fullname));
8788                 }
8789                 break;
8790             default:
8791                 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8792                     cur->nodesetval->nodeTab[i]));
8793                 xmlXPathLocalNameFunction(ctxt, 1);
8794         }
8795     }
8796     xmlXPathReleaseObject(ctxt->context, cur);
8797 }
8798
8799
8800 /**
8801  * xmlXPathStringFunction:
8802  * @ctxt:  the XPath Parser context
8803  * @nargs:  the number of arguments
8804  *
8805  * Implement the string() XPath function
8806  *    string string(object?)
8807  * The string function converts an object to a string as follows:
8808  *    - A node-set is converted to a string by returning the value of
8809  *      the node in the node-set that is first in document order.
8810  *      If the node-set is empty, an empty string is returned.
8811  *    - A number is converted to a string as follows
8812  *      + NaN is converted to the string NaN
8813  *      + positive zero is converted to the string 0
8814  *      + negative zero is converted to the string 0
8815  *      + positive infinity is converted to the string Infinity
8816  *      + negative infinity is converted to the string -Infinity
8817  *      + if the number is an integer, the number is represented in
8818  *        decimal form as a Number with no decimal point and no leading
8819  *        zeros, preceded by a minus sign (-) if the number is negative
8820  *      + otherwise, the number is represented in decimal form as a
8821  *        Number including a decimal point with at least one digit
8822  *        before the decimal point and at least one digit after the
8823  *        decimal point, preceded by a minus sign (-) if the number
8824  *        is negative; there must be no leading zeros before the decimal
8825  *        point apart possibly from the one required digit immediately
8826  *        before the decimal point; beyond the one required digit
8827  *        after the decimal point there must be as many, but only as
8828  *        many, more digits as are needed to uniquely distinguish the
8829  *        number from all other IEEE 754 numeric values.
8830  *    - The boolean false value is converted to the string false.
8831  *      The boolean true value is converted to the string true.
8832  *
8833  * If the argument is omitted, it defaults to a node-set with the
8834  * context node as its only member.
8835  */
8836 void
8837 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8838     xmlXPathObjectPtr cur;
8839
8840     if (ctxt == NULL) return;
8841     if (nargs == 0) {
8842     valuePush(ctxt,
8843         xmlXPathCacheWrapString(ctxt->context,
8844             xmlXPathCastNodeToString(ctxt->context->node)));
8845         return;
8846     }
8847
8848     CHECK_ARITY(1);
8849     cur = valuePop(ctxt);
8850     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8851     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8852 }
8853
8854 /**
8855  * xmlXPathStringLengthFunction:
8856  * @ctxt:  the XPath Parser context
8857  * @nargs:  the number of arguments
8858  *
8859  * Implement the string-length() XPath function
8860  *    number string-length(string?)
8861  * The string-length returns the number of characters in the string
8862  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8863  * the context node converted to a string, in other words the value
8864  * of the context node.
8865  */
8866 void
8867 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8868     xmlXPathObjectPtr cur;
8869
8870     if (nargs == 0) {
8871         if ((ctxt == NULL) || (ctxt->context == NULL))
8872             return;
8873         if (ctxt->context->node == NULL) {
8874             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8875         } else {
8876             xmlChar *content;
8877
8878             content = xmlXPathCastNodeToString(ctxt->context->node);
8879             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8880                 xmlUTF8Strlen(content)));
8881             xmlFree(content);
8882         }
8883         return;
8884     }
8885     CHECK_ARITY(1);
8886     CAST_TO_STRING;
8887     CHECK_TYPE(XPATH_STRING);
8888     cur = valuePop(ctxt);
8889     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8890         xmlUTF8Strlen(cur->stringval)));
8891     xmlXPathReleaseObject(ctxt->context, cur);
8892 }
8893
8894 /**
8895  * xmlXPathConcatFunction:
8896  * @ctxt:  the XPath Parser context
8897  * @nargs:  the number of arguments
8898  *
8899  * Implement the concat() XPath function
8900  *    string concat(string, string, string*)
8901  * The concat function returns the concatenation of its arguments.
8902  */
8903 void
8904 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8905     xmlXPathObjectPtr cur, newobj;
8906     xmlChar *tmp;
8907
8908     if (ctxt == NULL) return;
8909     if (nargs < 2) {
8910         CHECK_ARITY(2);
8911     }
8912
8913     CAST_TO_STRING;
8914     cur = valuePop(ctxt);
8915     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8916         xmlXPathReleaseObject(ctxt->context, cur);
8917         return;
8918     }
8919     nargs--;
8920
8921     while (nargs > 0) {
8922         CAST_TO_STRING;
8923         newobj = valuePop(ctxt);
8924         if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8925             xmlXPathReleaseObject(ctxt->context, newobj);
8926             xmlXPathReleaseObject(ctxt->context, cur);
8927             XP_ERROR(XPATH_INVALID_TYPE);
8928         }
8929         tmp = xmlStrcat(newobj->stringval, cur->stringval);
8930         newobj->stringval = cur->stringval;
8931         cur->stringval = tmp;
8932         xmlXPathReleaseObject(ctxt->context, newobj);
8933         nargs--;
8934     }
8935     valuePush(ctxt, cur);
8936 }
8937
8938 /**
8939  * xmlXPathContainsFunction:
8940  * @ctxt:  the XPath Parser context
8941  * @nargs:  the number of arguments
8942  *
8943  * Implement the contains() XPath function
8944  *    boolean contains(string, string)
8945  * The contains function returns true if the first argument string
8946  * contains the second argument string, and otherwise returns false.
8947  */
8948 void
8949 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8950     xmlXPathObjectPtr hay, needle;
8951
8952     CHECK_ARITY(2);
8953     CAST_TO_STRING;
8954     CHECK_TYPE(XPATH_STRING);
8955     needle = valuePop(ctxt);
8956     CAST_TO_STRING;
8957     hay = valuePop(ctxt);
8958
8959     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8960         xmlXPathReleaseObject(ctxt->context, hay);
8961         xmlXPathReleaseObject(ctxt->context, needle);
8962         XP_ERROR(XPATH_INVALID_TYPE);
8963     }
8964     if (xmlStrstr(hay->stringval, needle->stringval))
8965         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8966     else
8967         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8968     xmlXPathReleaseObject(ctxt->context, hay);
8969     xmlXPathReleaseObject(ctxt->context, needle);
8970 }
8971
8972 /**
8973  * xmlXPathStartsWithFunction:
8974  * @ctxt:  the XPath Parser context
8975  * @nargs:  the number of arguments
8976  *
8977  * Implement the starts-with() XPath function
8978  *    boolean starts-with(string, string)
8979  * The starts-with function returns true if the first argument string
8980  * starts with the second argument string, and otherwise returns false.
8981  */
8982 void
8983 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8984     xmlXPathObjectPtr hay, needle;
8985     int n;
8986
8987     CHECK_ARITY(2);
8988     CAST_TO_STRING;
8989     CHECK_TYPE(XPATH_STRING);
8990     needle = valuePop(ctxt);
8991     CAST_TO_STRING;
8992     hay = valuePop(ctxt);
8993
8994     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8995         xmlXPathReleaseObject(ctxt->context, hay);
8996         xmlXPathReleaseObject(ctxt->context, needle);
8997         XP_ERROR(XPATH_INVALID_TYPE);
8998     }
8999     n = xmlStrlen(needle->stringval);
9000     if (xmlStrncmp(hay->stringval, needle->stringval, n))
9001         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9002     else
9003         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9004     xmlXPathReleaseObject(ctxt->context, hay);
9005     xmlXPathReleaseObject(ctxt->context, needle);
9006 }
9007
9008 /**
9009  * xmlXPathSubstringFunction:
9010  * @ctxt:  the XPath Parser context
9011  * @nargs:  the number of arguments
9012  *
9013  * Implement the substring() XPath function
9014  *    string substring(string, number, number?)
9015  * The substring function returns the substring of the first argument
9016  * starting at the position specified in the second argument with
9017  * length specified in the third argument. For example,
9018  * substring("12345",2,3) returns "234". If the third argument is not
9019  * specified, it returns the substring starting at the position specified
9020  * in the second argument and continuing to the end of the string. For
9021  * example, substring("12345",2) returns "2345".  More precisely, each
9022  * character in the string (see [3.6 Strings]) is considered to have a
9023  * numeric position: the position of the first character is 1, the position
9024  * of the second character is 2 and so on. The returned substring contains
9025  * those characters for which the position of the character is greater than
9026  * or equal to the second argument and, if the third argument is specified,
9027  * less than the sum of the second and third arguments; the comparisons
9028  * and addition used for the above follow the standard IEEE 754 rules. Thus:
9029  *  - substring("12345", 1.5, 2.6) returns "234"
9030  *  - substring("12345", 0, 3) returns "12"
9031  *  - substring("12345", 0 div 0, 3) returns ""
9032  *  - substring("12345", 1, 0 div 0) returns ""
9033  *  - substring("12345", -42, 1 div 0) returns "12345"
9034  *  - substring("12345", -1 div 0, 1 div 0) returns ""
9035  */
9036 void
9037 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9038     xmlXPathObjectPtr str, start, len;
9039     double le=0, in;
9040     int i, l, m;
9041     xmlChar *ret;
9042
9043     if (nargs < 2) {
9044         CHECK_ARITY(2);
9045     }
9046     if (nargs > 3) {
9047         CHECK_ARITY(3);
9048     }
9049     /*
9050      * take care of possible last (position) argument
9051     */
9052     if (nargs == 3) {
9053         CAST_TO_NUMBER;
9054         CHECK_TYPE(XPATH_NUMBER);
9055         len = valuePop(ctxt);
9056         le = len->floatval;
9057         xmlXPathReleaseObject(ctxt->context, len);
9058     }
9059
9060     CAST_TO_NUMBER;
9061     CHECK_TYPE(XPATH_NUMBER);
9062     start = valuePop(ctxt);
9063     in = start->floatval;
9064     xmlXPathReleaseObject(ctxt->context, start);
9065     CAST_TO_STRING;
9066     CHECK_TYPE(XPATH_STRING);
9067     str = valuePop(ctxt);
9068     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9069
9070     /*
9071      * If last pos not present, calculate last position
9072     */
9073     if (nargs != 3) {
9074         le = (double)m;
9075         if (in < 1.0)
9076             in = 1.0;
9077     }
9078
9079     /* Need to check for the special cases where either
9080      * the index is NaN, the length is NaN, or both
9081      * arguments are infinity (relying on Inf + -Inf = NaN)
9082      */
9083     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9084         /*
9085          * To meet the requirements of the spec, the arguments
9086          * must be converted to integer format before
9087          * initial index calculations are done
9088          *
9089          * First we go to integer form, rounding up
9090          * and checking for special cases
9091          */
9092         i = (int) in;
9093         if (((double)i)+0.5 <= in) i++;
9094
9095         if (xmlXPathIsInf(le) == 1) {
9096             l = m;
9097             if (i < 1)
9098                 i = 1;
9099         }
9100         else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9101             l = 0;
9102         else {
9103             l = (int) le;
9104             if (((double)l)+0.5 <= le) l++;
9105         }
9106
9107         /* Now we normalize inidices */
9108         i -= 1;
9109         l += i;
9110         if (i < 0)
9111             i = 0;
9112         if (l > m)
9113             l = m;
9114
9115         /* number of chars to copy */
9116         l -= i;
9117
9118         ret = xmlUTF8Strsub(str->stringval, i, l);
9119     }
9120     else {
9121         ret = NULL;
9122     }
9123     if (ret == NULL)
9124         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9125     else {
9126         valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9127         xmlFree(ret);
9128     }
9129     xmlXPathReleaseObject(ctxt->context, str);
9130 }
9131
9132 /**
9133  * xmlXPathSubstringBeforeFunction:
9134  * @ctxt:  the XPath Parser context
9135  * @nargs:  the number of arguments
9136  *
9137  * Implement the substring-before() XPath function
9138  *    string substring-before(string, string)
9139  * The substring-before function returns the substring of the first
9140  * argument string that precedes the first occurrence of the second
9141  * argument string in the first argument string, or the empty string
9142  * if the first argument string does not contain the second argument
9143  * string. For example, substring-before("1999/04/01","/") returns 1999.
9144  */
9145 void
9146 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9147   xmlXPathObjectPtr str;
9148   xmlXPathObjectPtr find;
9149   xmlBufferPtr target;
9150   const xmlChar *point;
9151   int offset;
9152
9153   CHECK_ARITY(2);
9154   CAST_TO_STRING;
9155   find = valuePop(ctxt);
9156   CAST_TO_STRING;
9157   str = valuePop(ctxt);
9158
9159   target = xmlBufferCreate();
9160   if (target) {
9161     point = xmlStrstr(str->stringval, find->stringval);
9162     if (point) {
9163       offset = (int)(point - str->stringval);
9164       xmlBufferAdd(target, str->stringval, offset);
9165     }
9166     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9167         xmlBufferContent(target)));
9168     xmlBufferFree(target);
9169   }
9170   xmlXPathReleaseObject(ctxt->context, str);
9171   xmlXPathReleaseObject(ctxt->context, find);
9172 }
9173
9174 /**
9175  * xmlXPathSubstringAfterFunction:
9176  * @ctxt:  the XPath Parser context
9177  * @nargs:  the number of arguments
9178  *
9179  * Implement the substring-after() XPath function
9180  *    string substring-after(string, string)
9181  * The substring-after function returns the substring of the first
9182  * argument string that follows the first occurrence of the second
9183  * argument string in the first argument string, or the empty stringi
9184  * if the first argument string does not contain the second argument
9185  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9186  * and substring-after("1999/04/01","19") returns 99/04/01.
9187  */
9188 void
9189 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9190   xmlXPathObjectPtr str;
9191   xmlXPathObjectPtr find;
9192   xmlBufferPtr target;
9193   const xmlChar *point;
9194   int offset;
9195
9196   CHECK_ARITY(2);
9197   CAST_TO_STRING;
9198   find = valuePop(ctxt);
9199   CAST_TO_STRING;
9200   str = valuePop(ctxt);
9201
9202   target = xmlBufferCreate();
9203   if (target) {
9204     point = xmlStrstr(str->stringval, find->stringval);
9205     if (point) {
9206       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9207       xmlBufferAdd(target, &str->stringval[offset],
9208                    xmlStrlen(str->stringval) - offset);
9209     }
9210     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9211         xmlBufferContent(target)));
9212     xmlBufferFree(target);
9213   }
9214   xmlXPathReleaseObject(ctxt->context, str);
9215   xmlXPathReleaseObject(ctxt->context, find);
9216 }
9217
9218 /**
9219  * xmlXPathNormalizeFunction:
9220  * @ctxt:  the XPath Parser context
9221  * @nargs:  the number of arguments
9222  *
9223  * Implement the normalize-space() XPath function
9224  *    string normalize-space(string?)
9225  * The normalize-space function returns the argument string with white
9226  * space normalized by stripping leading and trailing whitespace
9227  * and replacing sequences of whitespace characters by a single
9228  * space. Whitespace characters are the same allowed by the S production
9229  * in XML. If the argument is omitted, it defaults to the context
9230  * node converted to a string, in other words the value of the context node.
9231  */
9232 void
9233 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9234   xmlXPathObjectPtr obj = NULL;
9235   xmlChar *source = NULL;
9236   xmlBufferPtr target;
9237   xmlChar blank;
9238
9239   if (ctxt == NULL) return;
9240   if (nargs == 0) {
9241     /* Use current context node */
9242       valuePush(ctxt,
9243           xmlXPathCacheWrapString(ctxt->context,
9244             xmlXPathCastNodeToString(ctxt->context->node)));
9245     nargs = 1;
9246   }
9247
9248   CHECK_ARITY(1);
9249   CAST_TO_STRING;
9250   CHECK_TYPE(XPATH_STRING);
9251   obj = valuePop(ctxt);
9252   source = obj->stringval;
9253
9254   target = xmlBufferCreate();
9255   if (target && source) {
9256
9257     /* Skip leading whitespaces */
9258     while (IS_BLANK_CH(*source))
9259       source++;
9260
9261     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9262     blank = 0;
9263     while (*source) {
9264       if (IS_BLANK_CH(*source)) {
9265         blank = 0x20;
9266       } else {
9267         if (blank) {
9268           xmlBufferAdd(target, &blank, 1);
9269           blank = 0;
9270         }
9271         xmlBufferAdd(target, source, 1);
9272       }
9273       source++;
9274     }
9275     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9276         xmlBufferContent(target)));
9277     xmlBufferFree(target);
9278   }
9279   xmlXPathReleaseObject(ctxt->context, obj);
9280 }
9281
9282 /**
9283  * xmlXPathTranslateFunction:
9284  * @ctxt:  the XPath Parser context
9285  * @nargs:  the number of arguments
9286  *
9287  * Implement the translate() XPath function
9288  *    string translate(string, string, string)
9289  * The translate function returns the first argument string with
9290  * occurrences of characters in the second argument string replaced
9291  * by the character at the corresponding position in the third argument
9292  * string. For example, translate("bar","abc","ABC") returns the string
9293  * BAr. If there is a character in the second argument string with no
9294  * character at a corresponding position in the third argument string
9295  * (because the second argument string is longer than the third argument
9296  * string), then occurrences of that character in the first argument
9297  * string are removed. For example, translate("--aaa--","abc-","ABC")
9298  * returns "AAA". If a character occurs more than once in second
9299  * argument string, then the first occurrence determines the replacement
9300  * character. If the third argument string is longer than the second
9301  * argument string, then excess characters are ignored.
9302  */
9303 void
9304 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9305     xmlXPathObjectPtr str;
9306     xmlXPathObjectPtr from;
9307     xmlXPathObjectPtr to;
9308     xmlBufferPtr target;
9309     int offset, max;
9310     xmlChar ch;
9311     const xmlChar *point;
9312     xmlChar *cptr;
9313
9314     CHECK_ARITY(3);
9315
9316     CAST_TO_STRING;
9317     to = valuePop(ctxt);
9318     CAST_TO_STRING;
9319     from = valuePop(ctxt);
9320     CAST_TO_STRING;
9321     str = valuePop(ctxt);
9322
9323     target = xmlBufferCreate();
9324     if (target) {
9325         max = xmlUTF8Strlen(to->stringval);
9326         for (cptr = str->stringval; (ch=*cptr); ) {
9327             offset = xmlUTF8Strloc(from->stringval, cptr);
9328             if (offset >= 0) {
9329                 if (offset < max) {
9330                     point = xmlUTF8Strpos(to->stringval, offset);
9331                     if (point)
9332                         xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9333                 }
9334             } else
9335                 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9336
9337             /* Step to next character in input */
9338             cptr++;
9339             if ( ch & 0x80 ) {
9340                 /* if not simple ascii, verify proper format */
9341                 if ( (ch & 0xc0) != 0xc0 ) {
9342                     xmlGenericError(xmlGenericErrorContext,
9343                         "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9344                     /* not asserting an XPath error is probably better */
9345                     break;
9346                 }
9347                 /* then skip over remaining bytes for this char */
9348                 while ( (ch <<= 1) & 0x80 )
9349                     if ( (*cptr++ & 0xc0) != 0x80 ) {
9350                         xmlGenericError(xmlGenericErrorContext,
9351                             "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9352                         /* not asserting an XPath error is probably better */
9353                         break;
9354                     }
9355                 if (ch & 0x80) /* must have had error encountered */
9356                     break;
9357             }
9358         }
9359     }
9360     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9361         xmlBufferContent(target)));
9362     xmlBufferFree(target);
9363     xmlXPathReleaseObject(ctxt->context, str);
9364     xmlXPathReleaseObject(ctxt->context, from);
9365     xmlXPathReleaseObject(ctxt->context, to);
9366 }
9367
9368 /**
9369  * xmlXPathBooleanFunction:
9370  * @ctxt:  the XPath Parser context
9371  * @nargs:  the number of arguments
9372  *
9373  * Implement the boolean() XPath function
9374  *    boolean boolean(object)
9375  * The boolean function converts its argument to a boolean as follows:
9376  *    - a number is true if and only if it is neither positive or
9377  *      negative zero nor NaN
9378  *    - a node-set is true if and only if it is non-empty
9379  *    - a string is true if and only if its length is non-zero
9380  */
9381 void
9382 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9383     xmlXPathObjectPtr cur;
9384
9385     CHECK_ARITY(1);
9386     cur = valuePop(ctxt);
9387     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9388     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9389     valuePush(ctxt, cur);
9390 }
9391
9392 /**
9393  * xmlXPathNotFunction:
9394  * @ctxt:  the XPath Parser context
9395  * @nargs:  the number of arguments
9396  *
9397  * Implement the not() XPath function
9398  *    boolean not(boolean)
9399  * The not function returns true if its argument is false,
9400  * and false otherwise.
9401  */
9402 void
9403 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9404     CHECK_ARITY(1);
9405     CAST_TO_BOOLEAN;
9406     CHECK_TYPE(XPATH_BOOLEAN);
9407     ctxt->value->boolval = ! ctxt->value->boolval;
9408 }
9409
9410 /**
9411  * xmlXPathTrueFunction:
9412  * @ctxt:  the XPath Parser context
9413  * @nargs:  the number of arguments
9414  *
9415  * Implement the true() XPath function
9416  *    boolean true()
9417  */
9418 void
9419 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9420     CHECK_ARITY(0);
9421     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9422 }
9423
9424 /**
9425  * xmlXPathFalseFunction:
9426  * @ctxt:  the XPath Parser context
9427  * @nargs:  the number of arguments
9428  *
9429  * Implement the false() XPath function
9430  *    boolean false()
9431  */
9432 void
9433 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9434     CHECK_ARITY(0);
9435     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9436 }
9437
9438 /**
9439  * xmlXPathLangFunction:
9440  * @ctxt:  the XPath Parser context
9441  * @nargs:  the number of arguments
9442  *
9443  * Implement the lang() XPath function
9444  *    boolean lang(string)
9445  * The lang function returns true or false depending on whether the
9446  * language of the context node as specified by xml:lang attributes
9447  * is the same as or is a sublanguage of the language specified by
9448  * the argument string. The language of the context node is determined
9449  * by the value of the xml:lang attribute on the context node, or, if
9450  * the context node has no xml:lang attribute, by the value of the
9451  * xml:lang attribute on the nearest ancestor of the context node that
9452  * has an xml:lang attribute. If there is no such attribute, then lang
9453  * returns false. If there is such an attribute, then lang returns
9454  * true if the attribute value is equal to the argument ignoring case,
9455  * or if there is some suffix starting with - such that the attribute
9456  * value is equal to the argument ignoring that suffix of the attribute
9457  * value and ignoring case.
9458  */
9459 void
9460 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9461     xmlXPathObjectPtr val = NULL;
9462     const xmlChar *theLang = NULL;
9463     const xmlChar *lang;
9464     int ret = 0;
9465     int i;
9466
9467     CHECK_ARITY(1);
9468     CAST_TO_STRING;
9469     CHECK_TYPE(XPATH_STRING);
9470     val = valuePop(ctxt);
9471     lang = val->stringval;
9472     theLang = xmlNodeGetLang(ctxt->context->node);
9473     if ((theLang != NULL) && (lang != NULL)) {
9474         for (i = 0;lang[i] != 0;i++)
9475             if (toupper(lang[i]) != toupper(theLang[i]))
9476                 goto not_equal;
9477         if ((theLang[i] == 0) || (theLang[i] == '-'))
9478             ret = 1;
9479     }
9480 not_equal:
9481     if (theLang != NULL)
9482         xmlFree((void *)theLang);
9483
9484     xmlXPathReleaseObject(ctxt->context, val);
9485     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9486 }
9487
9488 /**
9489  * xmlXPathNumberFunction:
9490  * @ctxt:  the XPath Parser context
9491  * @nargs:  the number of arguments
9492  *
9493  * Implement the number() XPath function
9494  *    number number(object?)
9495  */
9496 void
9497 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9498     xmlXPathObjectPtr cur;
9499     double res;
9500
9501     if (ctxt == NULL) return;
9502     if (nargs == 0) {
9503         if (ctxt->context->node == NULL) {
9504             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9505         } else {
9506             xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9507
9508             res = xmlXPathStringEvalNumber(content);
9509             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9510             xmlFree(content);
9511         }
9512         return;
9513     }
9514
9515     CHECK_ARITY(1);
9516     cur = valuePop(ctxt);
9517     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9518 }
9519
9520 /**
9521  * xmlXPathSumFunction:
9522  * @ctxt:  the XPath Parser context
9523  * @nargs:  the number of arguments
9524  *
9525  * Implement the sum() XPath function
9526  *    number sum(node-set)
9527  * The sum function returns the sum of the values of the nodes in
9528  * the argument node-set.
9529  */
9530 void
9531 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9532     xmlXPathObjectPtr cur;
9533     int i;
9534     double res = 0.0;
9535
9536     CHECK_ARITY(1);
9537     if ((ctxt->value == NULL) ||
9538         ((ctxt->value->type != XPATH_NODESET) &&
9539          (ctxt->value->type != XPATH_XSLT_TREE)))
9540         XP_ERROR(XPATH_INVALID_TYPE);
9541     cur = valuePop(ctxt);
9542
9543     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9544         for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9545             res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9546         }
9547     }
9548     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9549     xmlXPathReleaseObject(ctxt->context, cur);
9550 }
9551
9552 /*
9553  * To assure working code on multiple platforms, we want to only depend
9554  * upon the characteristic truncation of converting a floating point value
9555  * to an integer.  Unfortunately, because of the different storage sizes
9556  * of our internal floating point value (double) and integer (int), we
9557  * can't directly convert (see bug 301162).  This macro is a messy
9558  * 'workaround'
9559  */
9560 #define XTRUNC(f, v)            \
9561     f = fmod((v), INT_MAX);     \
9562     f = (v) - (f) + (double)((int)(f));
9563
9564 /**
9565  * xmlXPathFloorFunction:
9566  * @ctxt:  the XPath Parser context
9567  * @nargs:  the number of arguments
9568  *
9569  * Implement the floor() XPath function
9570  *    number floor(number)
9571  * The floor function returns the largest (closest to positive infinity)
9572  * number that is not greater than the argument and that is an integer.
9573  */
9574 void
9575 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9576     double f;
9577
9578     CHECK_ARITY(1);
9579     CAST_TO_NUMBER;
9580     CHECK_TYPE(XPATH_NUMBER);
9581
9582     XTRUNC(f, ctxt->value->floatval);
9583     if (f != ctxt->value->floatval) {
9584         if (ctxt->value->floatval > 0)
9585             ctxt->value->floatval = f;
9586         else
9587             ctxt->value->floatval = f - 1;
9588     }
9589 }
9590
9591 /**
9592  * xmlXPathCeilingFunction:
9593  * @ctxt:  the XPath Parser context
9594  * @nargs:  the number of arguments
9595  *
9596  * Implement the ceiling() XPath function
9597  *    number ceiling(number)
9598  * The ceiling function returns the smallest (closest to negative infinity)
9599  * number that is not less than the argument and that is an integer.
9600  */
9601 void
9602 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9603     double f;
9604
9605     CHECK_ARITY(1);
9606     CAST_TO_NUMBER;
9607     CHECK_TYPE(XPATH_NUMBER);
9608
9609 #if 0
9610     ctxt->value->floatval = ceil(ctxt->value->floatval);
9611 #else
9612     XTRUNC(f, ctxt->value->floatval);
9613     if (f != ctxt->value->floatval) {
9614         if (ctxt->value->floatval > 0)
9615             ctxt->value->floatval = f + 1;
9616         else {
9617             if (ctxt->value->floatval < 0 && f == 0)
9618                 ctxt->value->floatval = xmlXPathNZERO;
9619             else
9620                 ctxt->value->floatval = f;
9621         }
9622
9623     }
9624 #endif
9625 }
9626
9627 /**
9628  * xmlXPathRoundFunction:
9629  * @ctxt:  the XPath Parser context
9630  * @nargs:  the number of arguments
9631  *
9632  * Implement the round() XPath function
9633  *    number round(number)
9634  * The round function returns the number that is closest to the
9635  * argument and that is an integer. If there are two such numbers,
9636  * then the one that is even is returned.
9637  */
9638 void
9639 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9640     double f;
9641
9642     CHECK_ARITY(1);
9643     CAST_TO_NUMBER;
9644     CHECK_TYPE(XPATH_NUMBER);
9645
9646     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9647         (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9648         (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9649         (ctxt->value->floatval == 0.0))
9650         return;
9651
9652     XTRUNC(f, ctxt->value->floatval);
9653     if (ctxt->value->floatval < 0) {
9654         if (ctxt->value->floatval < f - 0.5)
9655             ctxt->value->floatval = f - 1;
9656         else
9657             ctxt->value->floatval = f;
9658         if (ctxt->value->floatval == 0)
9659             ctxt->value->floatval = xmlXPathNZERO;
9660     } else {
9661         if (ctxt->value->floatval < f + 0.5)
9662             ctxt->value->floatval = f;
9663         else
9664             ctxt->value->floatval = f + 1;
9665     }
9666 }
9667
9668 /************************************************************************
9669  *                                                                      *
9670  *                      The Parser                                      *
9671  *                                                                      *
9672  ************************************************************************/
9673
9674 /*
9675  * a few forward declarations since we use a recursive call based
9676  * implementation.
9677  */
9678 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9679 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9680 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9681 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9682 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9683                                           int qualified);
9684
9685 /**
9686  * xmlXPathCurrentChar:
9687  * @ctxt:  the XPath parser context
9688  * @cur:  pointer to the beginning of the char
9689  * @len:  pointer to the length of the char read
9690  *
9691  * The current char value, if using UTF-8 this may actually span multiple
9692  * bytes in the input buffer.
9693  *
9694  * Returns the current char value and its length
9695  */
9696
9697 static int
9698 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9699     unsigned char c;
9700     unsigned int val;
9701     const xmlChar *cur;
9702
9703     if (ctxt == NULL)
9704         return(0);
9705     cur = ctxt->cur;
9706
9707     /*
9708      * We are supposed to handle UTF8, check it's valid
9709      * From rfc2044: encoding of the Unicode values on UTF-8:
9710      *
9711      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9712      * 0000 0000-0000 007F   0xxxxxxx
9713      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9714      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9715      *
9716      * Check for the 0x110000 limit too
9717      */
9718     c = *cur;
9719     if (c & 0x80) {
9720         if ((cur[1] & 0xc0) != 0x80)
9721             goto encoding_error;
9722         if ((c & 0xe0) == 0xe0) {
9723
9724             if ((cur[2] & 0xc0) != 0x80)
9725                 goto encoding_error;
9726             if ((c & 0xf0) == 0xf0) {
9727                 if (((c & 0xf8) != 0xf0) ||
9728                     ((cur[3] & 0xc0) != 0x80))
9729                     goto encoding_error;
9730                 /* 4-byte code */
9731                 *len = 4;
9732                 val = (cur[0] & 0x7) << 18;
9733                 val |= (cur[1] & 0x3f) << 12;
9734                 val |= (cur[2] & 0x3f) << 6;
9735                 val |= cur[3] & 0x3f;
9736             } else {
9737               /* 3-byte code */
9738                 *len = 3;
9739                 val = (cur[0] & 0xf) << 12;
9740                 val |= (cur[1] & 0x3f) << 6;
9741                 val |= cur[2] & 0x3f;
9742             }
9743         } else {
9744           /* 2-byte code */
9745             *len = 2;
9746             val = (cur[0] & 0x1f) << 6;
9747             val |= cur[1] & 0x3f;
9748         }
9749         if (!IS_CHAR(val)) {
9750             XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9751         }
9752         return(val);
9753     } else {
9754         /* 1-byte code */
9755         *len = 1;
9756         return((int) *cur);
9757     }
9758 encoding_error:
9759     /*
9760      * If we detect an UTF8 error that probably means that the
9761      * input encoding didn't get properly advertised in the
9762      * declaration header. Report the error and switch the encoding
9763      * to ISO-Latin-1 (if you don't like this policy, just declare the
9764      * encoding !)
9765      */
9766     *len = 0;
9767     XP_ERROR0(XPATH_ENCODING_ERROR);
9768 }
9769
9770 /**
9771  * xmlXPathParseNCName:
9772  * @ctxt:  the XPath Parser context
9773  *
9774  * parse an XML namespace non qualified name.
9775  *
9776  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9777  *
9778  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9779  *                       CombiningChar | Extender
9780  *
9781  * Returns the namespace name or NULL
9782  */
9783
9784 xmlChar *
9785 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9786     const xmlChar *in;
9787     xmlChar *ret;
9788     int count = 0;
9789
9790     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9791     /*
9792      * Accelerator for simple ASCII names
9793      */
9794     in = ctxt->cur;
9795     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9796         ((*in >= 0x41) && (*in <= 0x5A)) ||
9797         (*in == '_')) {
9798         in++;
9799         while (((*in >= 0x61) && (*in <= 0x7A)) ||
9800                ((*in >= 0x41) && (*in <= 0x5A)) ||
9801                ((*in >= 0x30) && (*in <= 0x39)) ||
9802                (*in == '_') || (*in == '.') ||
9803                (*in == '-'))
9804             in++;
9805         if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9806             (*in == '[') || (*in == ']') || (*in == ':') ||
9807             (*in == '@') || (*in == '*')) {
9808             count = in - ctxt->cur;
9809             if (count == 0)
9810                 return(NULL);
9811             ret = xmlStrndup(ctxt->cur, count);
9812             ctxt->cur = in;
9813             return(ret);
9814         }
9815     }
9816     return(xmlXPathParseNameComplex(ctxt, 0));
9817 }
9818
9819
9820 /**
9821  * xmlXPathParseQName:
9822  * @ctxt:  the XPath Parser context
9823  * @prefix:  a xmlChar **
9824  *
9825  * parse an XML qualified name
9826  *
9827  * [NS 5] QName ::= (Prefix ':')? LocalPart
9828  *
9829  * [NS 6] Prefix ::= NCName
9830  *
9831  * [NS 7] LocalPart ::= NCName
9832  *
9833  * Returns the function returns the local part, and prefix is updated
9834  *   to get the Prefix if any.
9835  */
9836
9837 static xmlChar *
9838 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9839     xmlChar *ret = NULL;
9840
9841     *prefix = NULL;
9842     ret = xmlXPathParseNCName(ctxt);
9843     if (ret && CUR == ':') {
9844         *prefix = ret;
9845         NEXT;
9846         ret = xmlXPathParseNCName(ctxt);
9847     }
9848     return(ret);
9849 }
9850
9851 /**
9852  * xmlXPathParseName:
9853  * @ctxt:  the XPath Parser context
9854  *
9855  * parse an XML name
9856  *
9857  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9858  *                  CombiningChar | Extender
9859  *
9860  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9861  *
9862  * Returns the namespace name or NULL
9863  */
9864
9865 xmlChar *
9866 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9867     const xmlChar *in;
9868     xmlChar *ret;
9869     int count = 0;
9870
9871     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9872     /*
9873      * Accelerator for simple ASCII names
9874      */
9875     in = ctxt->cur;
9876     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9877         ((*in >= 0x41) && (*in <= 0x5A)) ||
9878         (*in == '_') || (*in == ':')) {
9879         in++;
9880         while (((*in >= 0x61) && (*in <= 0x7A)) ||
9881                ((*in >= 0x41) && (*in <= 0x5A)) ||
9882                ((*in >= 0x30) && (*in <= 0x39)) ||
9883                (*in == '_') || (*in == '-') ||
9884                (*in == ':') || (*in == '.'))
9885             in++;
9886         if ((*in > 0) && (*in < 0x80)) {
9887             count = in - ctxt->cur;
9888             ret = xmlStrndup(ctxt->cur, count);
9889             ctxt->cur = in;
9890             return(ret);
9891         }
9892     }
9893     return(xmlXPathParseNameComplex(ctxt, 1));
9894 }
9895
9896 static xmlChar *
9897 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9898     xmlChar buf[XML_MAX_NAMELEN + 5];
9899     int len = 0, l;
9900     int c;
9901
9902     /*
9903      * Handler for more complex cases
9904      */
9905     c = CUR_CHAR(l);
9906     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9907         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9908         (c == '*') || /* accelerators */
9909         (!IS_LETTER(c) && (c != '_') &&
9910          ((qualified) && (c != ':')))) {
9911         return(NULL);
9912     }
9913
9914     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9915            ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9916             (c == '.') || (c == '-') ||
9917             (c == '_') || ((qualified) && (c == ':')) ||
9918             (IS_COMBINING(c)) ||
9919             (IS_EXTENDER(c)))) {
9920         COPY_BUF(l,buf,len,c);
9921         NEXTL(l);
9922         c = CUR_CHAR(l);
9923         if (len >= XML_MAX_NAMELEN) {
9924             /*
9925              * Okay someone managed to make a huge name, so he's ready to pay
9926              * for the processing speed.
9927              */
9928             xmlChar *buffer;
9929             int max = len * 2;
9930
9931             buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9932             if (buffer == NULL) {
9933                 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9934             }
9935             memcpy(buffer, buf, len);
9936             while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9937                    (c == '.') || (c == '-') ||
9938                    (c == '_') || ((qualified) && (c == ':')) ||
9939                    (IS_COMBINING(c)) ||
9940                    (IS_EXTENDER(c))) {
9941                 if (len + 10 > max) {
9942                     max *= 2;
9943                     buffer = (xmlChar *) xmlRealloc(buffer,
9944                                                     max * sizeof(xmlChar));
9945                     if (buffer == NULL) {
9946                         XP_ERRORNULL(XPATH_MEMORY_ERROR);
9947                     }
9948                 }
9949                 COPY_BUF(l,buffer,len,c);
9950                 NEXTL(l);
9951                 c = CUR_CHAR(l);
9952             }
9953             buffer[len] = 0;
9954             return(buffer);
9955         }
9956     }
9957     if (len == 0)
9958         return(NULL);
9959     return(xmlStrndup(buf, len));
9960 }
9961
9962 #define MAX_FRAC 20
9963
9964 /*
9965  * These are used as divisors for the fractional part of a number.
9966  * Since the table includes 1.0 (representing '0' fractional digits),
9967  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9968  */
9969 static double my_pow10[MAX_FRAC+1] = {
9970     1.0, 10.0, 100.0, 1000.0, 10000.0,
9971     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9972     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9973     100000000000000.0,
9974     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9975     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9976 };
9977
9978 /**
9979  * xmlXPathStringEvalNumber:
9980  * @str:  A string to scan
9981  *
9982  *  [30a]  Float  ::= Number ('e' Digits?)?
9983  *
9984  *  [30]   Number ::=   Digits ('.' Digits?)?
9985  *                    | '.' Digits
9986  *  [31]   Digits ::=   [0-9]+
9987  *
9988  * Compile a Number in the string
9989  * In complement of the Number expression, this function also handles
9990  * negative values : '-' Number.
9991  *
9992  * Returns the double value.
9993  */
9994 double
9995 xmlXPathStringEvalNumber(const xmlChar *str) {
9996     const xmlChar *cur = str;
9997     double ret;
9998     int ok = 0;
9999     int isneg = 0;
10000     int exponent = 0;
10001     int is_exponent_negative = 0;
10002 #ifdef __GNUC__
10003     unsigned long tmp = 0;
10004     double temp;
10005 #endif
10006     if (cur == NULL) return(0);
10007     while (IS_BLANK_CH(*cur)) cur++;
10008     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10009         return(xmlXPathNAN);
10010     }
10011     if (*cur == '-') {
10012         isneg = 1;
10013         cur++;
10014     }
10015
10016 #ifdef __GNUC__
10017     /*
10018      * tmp/temp is a workaround against a gcc compiler bug
10019      * http://veillard.com/gcc.bug
10020      */
10021     ret = 0;
10022     while ((*cur >= '0') && (*cur <= '9')) {
10023         ret = ret * 10;
10024         tmp = (*cur - '0');
10025         ok = 1;
10026         cur++;
10027         temp = (double) tmp;
10028         ret = ret + temp;
10029     }
10030 #else
10031     ret = 0;
10032     while ((*cur >= '0') && (*cur <= '9')) {
10033         ret = ret * 10 + (*cur - '0');
10034         ok = 1;
10035         cur++;
10036     }
10037 #endif
10038
10039     if (*cur == '.') {
10040         int v, frac = 0;
10041         double fraction = 0;
10042
10043         cur++;
10044         if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10045             return(xmlXPathNAN);
10046         }
10047         while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10048             v = (*cur - '0');
10049             fraction = fraction * 10 + v;
10050             frac = frac + 1;
10051             cur++;
10052         }
10053         fraction /= my_pow10[frac];
10054         ret = ret + fraction;
10055         while ((*cur >= '0') && (*cur <= '9'))
10056             cur++;
10057     }
10058     if ((*cur == 'e') || (*cur == 'E')) {
10059       cur++;
10060       if (*cur == '-') {
10061         is_exponent_negative = 1;
10062         cur++;
10063       } else if (*cur == '+') {
10064         cur++;
10065       }
10066       while ((*cur >= '0') && (*cur <= '9')) {
10067         exponent = exponent * 10 + (*cur - '0');
10068         cur++;
10069       }
10070     }
10071     while (IS_BLANK_CH(*cur)) cur++;
10072     if (*cur != 0) return(xmlXPathNAN);
10073     if (isneg) ret = -ret;
10074     if (is_exponent_negative) exponent = -exponent;
10075     ret *= pow(10.0, (double)exponent);
10076     return(ret);
10077 }
10078
10079 /**
10080  * xmlXPathCompNumber:
10081  * @ctxt:  the XPath Parser context
10082  *
10083  *  [30]   Number ::=   Digits ('.' Digits?)?
10084  *                    | '.' Digits
10085  *  [31]   Digits ::=   [0-9]+
10086  *
10087  * Compile a Number, then push it on the stack
10088  *
10089  */
10090 static void
10091 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10092 {
10093     double ret = 0.0;
10094     int ok = 0;
10095     int exponent = 0;
10096     int is_exponent_negative = 0;
10097 #ifdef __GNUC__
10098     unsigned long tmp = 0;
10099     double temp;
10100 #endif
10101
10102     CHECK_ERROR;
10103     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10104         XP_ERROR(XPATH_NUMBER_ERROR);
10105     }
10106 #ifdef __GNUC__
10107     /*
10108      * tmp/temp is a workaround against a gcc compiler bug
10109      * http://veillard.com/gcc.bug
10110      */
10111     ret = 0;
10112     while ((CUR >= '0') && (CUR <= '9')) {
10113         ret = ret * 10;
10114         tmp = (CUR - '0');
10115         ok = 1;
10116         NEXT;
10117         temp = (double) tmp;
10118         ret = ret + temp;
10119     }
10120 #else
10121     ret = 0;
10122     while ((CUR >= '0') && (CUR <= '9')) {
10123         ret = ret * 10 + (CUR - '0');
10124         ok = 1;
10125         NEXT;
10126     }
10127 #endif
10128     if (CUR == '.') {
10129         int v, frac = 0;
10130         double fraction = 0;
10131
10132         NEXT;
10133         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10134             XP_ERROR(XPATH_NUMBER_ERROR);
10135         }
10136         while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10137             v = (CUR - '0');
10138             fraction = fraction * 10 + v;
10139             frac = frac + 1;
10140             NEXT;
10141         }
10142         fraction /= my_pow10[frac];
10143         ret = ret + fraction;
10144         while ((CUR >= '0') && (CUR <= '9'))
10145             NEXT;
10146     }
10147     if ((CUR == 'e') || (CUR == 'E')) {
10148         NEXT;
10149         if (CUR == '-') {
10150             is_exponent_negative = 1;
10151             NEXT;
10152         } else if (CUR == '+') {
10153             NEXT;
10154         }
10155         while ((CUR >= '0') && (CUR <= '9')) {
10156             exponent = exponent * 10 + (CUR - '0');
10157             NEXT;
10158         }
10159         if (is_exponent_negative)
10160             exponent = -exponent;
10161         ret *= pow(10.0, (double) exponent);
10162     }
10163     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10164                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10165 }
10166
10167 /**
10168  * xmlXPathParseLiteral:
10169  * @ctxt:  the XPath Parser context
10170  *
10171  * Parse a Literal
10172  *
10173  *  [29]   Literal ::=   '"' [^"]* '"'
10174  *                    | "'" [^']* "'"
10175  *
10176  * Returns the value found or NULL in case of error
10177  */
10178 static xmlChar *
10179 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10180     const xmlChar *q;
10181     xmlChar *ret = NULL;
10182
10183     if (CUR == '"') {
10184         NEXT;
10185         q = CUR_PTR;
10186         while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10187             NEXT;
10188         if (!IS_CHAR_CH(CUR)) {
10189             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10190         } else {
10191             ret = xmlStrndup(q, CUR_PTR - q);
10192             NEXT;
10193         }
10194     } else if (CUR == '\'') {
10195         NEXT;
10196         q = CUR_PTR;
10197         while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10198             NEXT;
10199         if (!IS_CHAR_CH(CUR)) {
10200             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10201         } else {
10202             ret = xmlStrndup(q, CUR_PTR - q);
10203             NEXT;
10204         }
10205     } else {
10206         XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10207     }
10208     return(ret);
10209 }
10210
10211 /**
10212  * xmlXPathCompLiteral:
10213  * @ctxt:  the XPath Parser context
10214  *
10215  * Parse a Literal and push it on the stack.
10216  *
10217  *  [29]   Literal ::=   '"' [^"]* '"'
10218  *                    | "'" [^']* "'"
10219  *
10220  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10221  */
10222 static void
10223 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10224     const xmlChar *q;
10225     xmlChar *ret = NULL;
10226
10227     if (CUR == '"') {
10228         NEXT;
10229         q = CUR_PTR;
10230         while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10231             NEXT;
10232         if (!IS_CHAR_CH(CUR)) {
10233             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10234         } else {
10235             ret = xmlStrndup(q, CUR_PTR - q);
10236             NEXT;
10237         }
10238     } else if (CUR == '\'') {
10239         NEXT;
10240         q = CUR_PTR;
10241         while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10242             NEXT;
10243         if (!IS_CHAR_CH(CUR)) {
10244             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10245         } else {
10246             ret = xmlStrndup(q, CUR_PTR - q);
10247             NEXT;
10248         }
10249     } else {
10250         XP_ERROR(XPATH_START_LITERAL_ERROR);
10251     }
10252     if (ret == NULL) return;
10253     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10254                    xmlXPathCacheNewString(ctxt->context, ret), NULL);
10255     xmlFree(ret);
10256 }
10257
10258 /**
10259  * xmlXPathCompVariableReference:
10260  * @ctxt:  the XPath Parser context
10261  *
10262  * Parse a VariableReference, evaluate it and push it on the stack.
10263  *
10264  * The variable bindings consist of a mapping from variable names
10265  * to variable values. The value of a variable is an object, which can be
10266  * of any of the types that are possible for the value of an expression,
10267  * and may also be of additional types not specified here.
10268  *
10269  * Early evaluation is possible since:
10270  * The variable bindings [...] used to evaluate a subexpression are
10271  * always the same as those used to evaluate the containing expression.
10272  *
10273  *  [36]   VariableReference ::=   '$' QName
10274  */
10275 static void
10276 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10277     xmlChar *name;
10278     xmlChar *prefix;
10279
10280     SKIP_BLANKS;
10281     if (CUR != '$') {
10282         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10283     }
10284     NEXT;
10285     name = xmlXPathParseQName(ctxt, &prefix);
10286     if (name == NULL) {
10287         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10288     }
10289     ctxt->comp->last = -1;
10290     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10291                    name, prefix);
10292     SKIP_BLANKS;
10293     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10294         XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10295     }
10296 }
10297
10298 /**
10299  * xmlXPathIsNodeType:
10300  * @name:  a name string
10301  *
10302  * Is the name given a NodeType one.
10303  *
10304  *  [38]   NodeType ::=   'comment'
10305  *                    | 'text'
10306  *                    | 'processing-instruction'
10307  *                    | 'node'
10308  *
10309  * Returns 1 if true 0 otherwise
10310  */
10311 int
10312 xmlXPathIsNodeType(const xmlChar *name) {
10313     if (name == NULL)
10314         return(0);
10315
10316     if (xmlStrEqual(name, BAD_CAST "node"))
10317         return(1);
10318     if (xmlStrEqual(name, BAD_CAST "text"))
10319         return(1);
10320     if (xmlStrEqual(name, BAD_CAST "comment"))
10321         return(1);
10322     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10323         return(1);
10324     return(0);
10325 }
10326
10327 /**
10328  * xmlXPathCompFunctionCall:
10329  * @ctxt:  the XPath Parser context
10330  *
10331  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10332  *  [17]   Argument ::=   Expr
10333  *
10334  * Compile a function call, the evaluation of all arguments are
10335  * pushed on the stack
10336  */
10337 static void
10338 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10339     xmlChar *name;
10340     xmlChar *prefix;
10341     int nbargs = 0;
10342     int sort = 1;
10343
10344     name = xmlXPathParseQName(ctxt, &prefix);
10345     if (name == NULL) {
10346         xmlFree(prefix);
10347         XP_ERROR(XPATH_EXPR_ERROR);
10348     }
10349     SKIP_BLANKS;
10350 #ifdef DEBUG_EXPR
10351     if (prefix == NULL)
10352         xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10353                         name);
10354     else
10355         xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10356                         prefix, name);
10357 #endif
10358
10359     if (CUR != '(') {
10360         XP_ERROR(XPATH_EXPR_ERROR);
10361     }
10362     NEXT;
10363     SKIP_BLANKS;
10364
10365     /*
10366     * Optimization for count(): we don't need the node-set to be sorted.
10367     */
10368     if ((prefix == NULL) && (name[0] == 'c') &&
10369         xmlStrEqual(name, BAD_CAST "count"))
10370     {
10371         sort = 0;
10372     }
10373     ctxt->comp->last = -1;
10374     if (CUR != ')') {
10375         while (CUR != 0) {
10376             int op1 = ctxt->comp->last;
10377             ctxt->comp->last = -1;
10378             xmlXPathCompileExpr(ctxt, sort);
10379             if (ctxt->error != XPATH_EXPRESSION_OK) {
10380                 xmlFree(name);
10381                 xmlFree(prefix);
10382                 return;
10383             }
10384             PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10385             nbargs++;
10386             if (CUR == ')') break;
10387             if (CUR != ',') {
10388                 XP_ERROR(XPATH_EXPR_ERROR);
10389             }
10390             NEXT;
10391             SKIP_BLANKS;
10392         }
10393     }
10394     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10395                    name, prefix);
10396     NEXT;
10397     SKIP_BLANKS;
10398 }
10399
10400 /**
10401  * xmlXPathCompPrimaryExpr:
10402  * @ctxt:  the XPath Parser context
10403  *
10404  *  [15]   PrimaryExpr ::=   VariableReference
10405  *                | '(' Expr ')'
10406  *                | Literal
10407  *                | Number
10408  *                | FunctionCall
10409  *
10410  * Compile a primary expression.
10411  */
10412 static void
10413 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10414     SKIP_BLANKS;
10415     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10416     else if (CUR == '(') {
10417         NEXT;
10418         SKIP_BLANKS;
10419         xmlXPathCompileExpr(ctxt, 1);
10420         CHECK_ERROR;
10421         if (CUR != ')') {
10422             XP_ERROR(XPATH_EXPR_ERROR);
10423         }
10424         NEXT;
10425         SKIP_BLANKS;
10426     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10427         xmlXPathCompNumber(ctxt);
10428     } else if ((CUR == '\'') || (CUR == '"')) {
10429         xmlXPathCompLiteral(ctxt);
10430     } else {
10431         xmlXPathCompFunctionCall(ctxt);
10432     }
10433     SKIP_BLANKS;
10434 }
10435
10436 /**
10437  * xmlXPathCompFilterExpr:
10438  * @ctxt:  the XPath Parser context
10439  *
10440  *  [20]   FilterExpr ::=   PrimaryExpr
10441  *               | FilterExpr Predicate
10442  *
10443  * Compile a filter expression.
10444  * Square brackets are used to filter expressions in the same way that
10445  * they are used in location paths. It is an error if the expression to
10446  * be filtered does not evaluate to a node-set. The context node list
10447  * used for evaluating the expression in square brackets is the node-set
10448  * to be filtered listed in document order.
10449  */
10450
10451 static void
10452 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10453     xmlXPathCompPrimaryExpr(ctxt);
10454     CHECK_ERROR;
10455     SKIP_BLANKS;
10456
10457     while (CUR == '[') {
10458         xmlXPathCompPredicate(ctxt, 1);
10459         SKIP_BLANKS;
10460     }
10461
10462
10463 }
10464
10465 /**
10466  * xmlXPathScanName:
10467  * @ctxt:  the XPath Parser context
10468  *
10469  * Trickery: parse an XML name but without consuming the input flow
10470  * Needed to avoid insanity in the parser state.
10471  *
10472  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10473  *                  CombiningChar | Extender
10474  *
10475  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10476  *
10477  * [6] Names ::= Name (S Name)*
10478  *
10479  * Returns the Name parsed or NULL
10480  */
10481
10482 static xmlChar *
10483 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10484     int len = 0, l;
10485     int c;
10486     const xmlChar *cur;
10487     xmlChar *ret;
10488
10489     cur = ctxt->cur;
10490
10491     c = CUR_CHAR(l);
10492     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10493         (!IS_LETTER(c) && (c != '_') &&
10494          (c != ':'))) {
10495         return(NULL);
10496     }
10497
10498     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10499            ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10500             (c == '.') || (c == '-') ||
10501             (c == '_') || (c == ':') ||
10502             (IS_COMBINING(c)) ||
10503             (IS_EXTENDER(c)))) {
10504         len += l;
10505         NEXTL(l);
10506         c = CUR_CHAR(l);
10507     }
10508     ret = xmlStrndup(cur, ctxt->cur - cur);
10509     ctxt->cur = cur;
10510     return(ret);
10511 }
10512
10513 /**
10514  * xmlXPathCompPathExpr:
10515  * @ctxt:  the XPath Parser context
10516  *
10517  *  [19]   PathExpr ::=   LocationPath
10518  *               | FilterExpr
10519  *               | FilterExpr '/' RelativeLocationPath
10520  *               | FilterExpr '//' RelativeLocationPath
10521  *
10522  * Compile a path expression.
10523  * The / operator and // operators combine an arbitrary expression
10524  * and a relative location path. It is an error if the expression
10525  * does not evaluate to a node-set.
10526  * The / operator does composition in the same way as when / is
10527  * used in a location path. As in location paths, // is short for
10528  * /descendant-or-self::node()/.
10529  */
10530
10531 static void
10532 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10533     int lc = 1;           /* Should we branch to LocationPath ?         */
10534     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10535
10536     SKIP_BLANKS;
10537     if ((CUR == '$') || (CUR == '(') ||
10538         (IS_ASCII_DIGIT(CUR)) ||
10539         (CUR == '\'') || (CUR == '"') ||
10540         (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10541         lc = 0;
10542     } else if (CUR == '*') {
10543         /* relative or absolute location path */
10544         lc = 1;
10545     } else if (CUR == '/') {
10546         /* relative or absolute location path */
10547         lc = 1;
10548     } else if (CUR == '@') {
10549         /* relative abbreviated attribute location path */
10550         lc = 1;
10551     } else if (CUR == '.') {
10552         /* relative abbreviated attribute location path */
10553         lc = 1;
10554     } else {
10555         /*
10556          * Problem is finding if we have a name here whether it's:
10557          *   - a nodetype
10558          *   - a function call in which case it's followed by '('
10559          *   - an axis in which case it's followed by ':'
10560          *   - a element name
10561          * We do an a priori analysis here rather than having to
10562          * maintain parsed token content through the recursive function
10563          * calls. This looks uglier but makes the code easier to
10564          * read/write/debug.
10565          */
10566         SKIP_BLANKS;
10567         name = xmlXPathScanName(ctxt);
10568         if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10569 #ifdef DEBUG_STEP
10570             xmlGenericError(xmlGenericErrorContext,
10571                     "PathExpr: Axis\n");
10572 #endif
10573             lc = 1;
10574             xmlFree(name);
10575         } else if (name != NULL) {
10576             int len =xmlStrlen(name);
10577
10578
10579             while (NXT(len) != 0) {
10580                 if (NXT(len) == '/') {
10581                     /* element name */
10582 #ifdef DEBUG_STEP
10583                     xmlGenericError(xmlGenericErrorContext,
10584                             "PathExpr: AbbrRelLocation\n");
10585 #endif
10586                     lc = 1;
10587                     break;
10588                 } else if (IS_BLANK_CH(NXT(len))) {
10589                     /* ignore blanks */
10590                     ;
10591                 } else if (NXT(len) == ':') {
10592 #ifdef DEBUG_STEP
10593                     xmlGenericError(xmlGenericErrorContext,
10594                             "PathExpr: AbbrRelLocation\n");
10595 #endif
10596                     lc = 1;
10597                     break;
10598                 } else if ((NXT(len) == '(')) {
10599                     /* Note Type or Function */
10600                     if (xmlXPathIsNodeType(name)) {
10601 #ifdef DEBUG_STEP
10602                         xmlGenericError(xmlGenericErrorContext,
10603                                 "PathExpr: Type search\n");
10604 #endif
10605                         lc = 1;
10606                     } else {
10607 #ifdef DEBUG_STEP
10608                         xmlGenericError(xmlGenericErrorContext,
10609                                 "PathExpr: function call\n");
10610 #endif
10611                         lc = 0;
10612                     }
10613                     break;
10614                 } else if ((NXT(len) == '[')) {
10615                     /* element name */
10616 #ifdef DEBUG_STEP
10617                     xmlGenericError(xmlGenericErrorContext,
10618                             "PathExpr: AbbrRelLocation\n");
10619 #endif
10620                     lc = 1;
10621                     break;
10622                 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10623                            (NXT(len) == '=')) {
10624                     lc = 1;
10625                     break;
10626                 } else {
10627                     lc = 1;
10628                     break;
10629                 }
10630                 len++;
10631             }
10632             if (NXT(len) == 0) {
10633 #ifdef DEBUG_STEP
10634                 xmlGenericError(xmlGenericErrorContext,
10635                         "PathExpr: AbbrRelLocation\n");
10636 #endif
10637                 /* element name */
10638                 lc = 1;
10639             }
10640             xmlFree(name);
10641         } else {
10642             /* make sure all cases are covered explicitly */
10643             XP_ERROR(XPATH_EXPR_ERROR);
10644         }
10645     }
10646
10647     if (lc) {
10648         if (CUR == '/') {
10649             PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10650         } else {
10651             PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10652         }
10653         xmlXPathCompLocationPath(ctxt);
10654     } else {
10655         xmlXPathCompFilterExpr(ctxt);
10656         CHECK_ERROR;
10657         if ((CUR == '/') && (NXT(1) == '/')) {
10658             SKIP(2);
10659             SKIP_BLANKS;
10660
10661             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10662                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10663             PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10664
10665             xmlXPathCompRelativeLocationPath(ctxt);
10666         } else if (CUR == '/') {
10667             xmlXPathCompRelativeLocationPath(ctxt);
10668         }
10669     }
10670     SKIP_BLANKS;
10671 }
10672
10673 /**
10674  * xmlXPathCompUnionExpr:
10675  * @ctxt:  the XPath Parser context
10676  *
10677  *  [18]   UnionExpr ::=   PathExpr
10678  *               | UnionExpr '|' PathExpr
10679  *
10680  * Compile an union expression.
10681  */
10682
10683 static void
10684 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10685     xmlXPathCompPathExpr(ctxt);
10686     CHECK_ERROR;
10687     SKIP_BLANKS;
10688     while (CUR == '|') {
10689         int op1 = ctxt->comp->last;
10690         PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10691
10692         NEXT;
10693         SKIP_BLANKS;
10694         xmlXPathCompPathExpr(ctxt);
10695
10696         PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10697
10698         SKIP_BLANKS;
10699     }
10700 }
10701
10702 /**
10703  * xmlXPathCompUnaryExpr:
10704  * @ctxt:  the XPath Parser context
10705  *
10706  *  [27]   UnaryExpr ::=   UnionExpr
10707  *                   | '-' UnaryExpr
10708  *
10709  * Compile an unary expression.
10710  */
10711
10712 static void
10713 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10714     int minus = 0;
10715     int found = 0;
10716
10717     SKIP_BLANKS;
10718     while (CUR == '-') {
10719         minus = 1 - minus;
10720         found = 1;
10721         NEXT;
10722         SKIP_BLANKS;
10723     }
10724
10725     xmlXPathCompUnionExpr(ctxt);
10726     CHECK_ERROR;
10727     if (found) {
10728         if (minus)
10729             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10730         else
10731             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10732     }
10733 }
10734
10735 /**
10736  * xmlXPathCompMultiplicativeExpr:
10737  * @ctxt:  the XPath Parser context
10738  *
10739  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10740  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10741  *                   | MultiplicativeExpr 'div' UnaryExpr
10742  *                   | MultiplicativeExpr 'mod' UnaryExpr
10743  *  [34]   MultiplyOperator ::=   '*'
10744  *
10745  * Compile an Additive expression.
10746  */
10747
10748 static void
10749 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10750     xmlXPathCompUnaryExpr(ctxt);
10751     CHECK_ERROR;
10752     SKIP_BLANKS;
10753     while ((CUR == '*') ||
10754            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10755            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10756         int op = -1;
10757         int op1 = ctxt->comp->last;
10758
10759         if (CUR == '*') {
10760             op = 0;
10761             NEXT;
10762         } else if (CUR == 'd') {
10763             op = 1;
10764             SKIP(3);
10765         } else if (CUR == 'm') {
10766             op = 2;
10767             SKIP(3);
10768         }
10769         SKIP_BLANKS;
10770         xmlXPathCompUnaryExpr(ctxt);
10771         CHECK_ERROR;
10772         PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10773         SKIP_BLANKS;
10774     }
10775 }
10776
10777 /**
10778  * xmlXPathCompAdditiveExpr:
10779  * @ctxt:  the XPath Parser context
10780  *
10781  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10782  *                   | AdditiveExpr '+' MultiplicativeExpr
10783  *                   | AdditiveExpr '-' MultiplicativeExpr
10784  *
10785  * Compile an Additive expression.
10786  */
10787
10788 static void
10789 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10790
10791     xmlXPathCompMultiplicativeExpr(ctxt);
10792     CHECK_ERROR;
10793     SKIP_BLANKS;
10794     while ((CUR == '+') || (CUR == '-')) {
10795         int plus;
10796         int op1 = ctxt->comp->last;
10797
10798         if (CUR == '+') plus = 1;
10799         else plus = 0;
10800         NEXT;
10801         SKIP_BLANKS;
10802         xmlXPathCompMultiplicativeExpr(ctxt);
10803         CHECK_ERROR;
10804         PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10805         SKIP_BLANKS;
10806     }
10807 }
10808
10809 /**
10810  * xmlXPathCompRelationalExpr:
10811  * @ctxt:  the XPath Parser context
10812  *
10813  *  [24]   RelationalExpr ::=   AdditiveExpr
10814  *                 | RelationalExpr '<' AdditiveExpr
10815  *                 | RelationalExpr '>' AdditiveExpr
10816  *                 | RelationalExpr '<=' AdditiveExpr
10817  *                 | RelationalExpr '>=' AdditiveExpr
10818  *
10819  *  A <= B > C is allowed ? Answer from James, yes with
10820  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10821  *  which is basically what got implemented.
10822  *
10823  * Compile a Relational expression, then push the result
10824  * on the stack
10825  */
10826
10827 static void
10828 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10829     xmlXPathCompAdditiveExpr(ctxt);
10830     CHECK_ERROR;
10831     SKIP_BLANKS;
10832     while ((CUR == '<') ||
10833            (CUR == '>') ||
10834            ((CUR == '<') && (NXT(1) == '=')) ||
10835            ((CUR == '>') && (NXT(1) == '='))) {
10836         int inf, strict;
10837         int op1 = ctxt->comp->last;
10838
10839         if (CUR == '<') inf = 1;
10840         else inf = 0;
10841         if (NXT(1) == '=') strict = 0;
10842         else strict = 1;
10843         NEXT;
10844         if (!strict) NEXT;
10845         SKIP_BLANKS;
10846         xmlXPathCompAdditiveExpr(ctxt);
10847         CHECK_ERROR;
10848         PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10849         SKIP_BLANKS;
10850     }
10851 }
10852
10853 /**
10854  * xmlXPathCompEqualityExpr:
10855  * @ctxt:  the XPath Parser context
10856  *
10857  *  [23]   EqualityExpr ::=   RelationalExpr
10858  *                 | EqualityExpr '=' RelationalExpr
10859  *                 | EqualityExpr '!=' RelationalExpr
10860  *
10861  *  A != B != C is allowed ? Answer from James, yes with
10862  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10863  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10864  *  which is basically what got implemented.
10865  *
10866  * Compile an Equality expression.
10867  *
10868  */
10869 static void
10870 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10871     xmlXPathCompRelationalExpr(ctxt);
10872     CHECK_ERROR;
10873     SKIP_BLANKS;
10874     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10875         int eq;
10876         int op1 = ctxt->comp->last;
10877
10878         if (CUR == '=') eq = 1;
10879         else eq = 0;
10880         NEXT;
10881         if (!eq) NEXT;
10882         SKIP_BLANKS;
10883         xmlXPathCompRelationalExpr(ctxt);
10884         CHECK_ERROR;
10885         PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10886         SKIP_BLANKS;
10887     }
10888 }
10889
10890 /**
10891  * xmlXPathCompAndExpr:
10892  * @ctxt:  the XPath Parser context
10893  *
10894  *  [22]   AndExpr ::=   EqualityExpr
10895  *                 | AndExpr 'and' EqualityExpr
10896  *
10897  * Compile an AND expression.
10898  *
10899  */
10900 static void
10901 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10902     xmlXPathCompEqualityExpr(ctxt);
10903     CHECK_ERROR;
10904     SKIP_BLANKS;
10905     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10906         int op1 = ctxt->comp->last;
10907         SKIP(3);
10908         SKIP_BLANKS;
10909         xmlXPathCompEqualityExpr(ctxt);
10910         CHECK_ERROR;
10911         PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10912         SKIP_BLANKS;
10913     }
10914 }
10915
10916 /**
10917  * xmlXPathCompileExpr:
10918  * @ctxt:  the XPath Parser context
10919  *
10920  *  [14]   Expr ::=   OrExpr
10921  *  [21]   OrExpr ::=   AndExpr
10922  *                 | OrExpr 'or' AndExpr
10923  *
10924  * Parse and compile an expression
10925  */
10926 static void
10927 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10928     xmlXPathCompAndExpr(ctxt);
10929     CHECK_ERROR;
10930     SKIP_BLANKS;
10931     while ((CUR == 'o') && (NXT(1) == 'r')) {
10932         int op1 = ctxt->comp->last;
10933         SKIP(2);
10934         SKIP_BLANKS;
10935         xmlXPathCompAndExpr(ctxt);
10936         CHECK_ERROR;
10937         PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10938         SKIP_BLANKS;
10939     }
10940     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10941         /* more ops could be optimized too */
10942         /*
10943         * This is the main place to eliminate sorting for
10944         * operations which don't require a sorted node-set.
10945         * E.g. count().
10946         */
10947         PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10948     }
10949 }
10950
10951 /**
10952  * xmlXPathCompPredicate:
10953  * @ctxt:  the XPath Parser context
10954  * @filter:  act as a filter
10955  *
10956  *  [8]   Predicate ::=   '[' PredicateExpr ']'
10957  *  [9]   PredicateExpr ::=   Expr
10958  *
10959  * Compile a predicate expression
10960  */
10961 static void
10962 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10963     int op1 = ctxt->comp->last;
10964
10965     SKIP_BLANKS;
10966     if (CUR != '[') {
10967         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10968     }
10969     NEXT;
10970     SKIP_BLANKS;
10971
10972     ctxt->comp->last = -1;
10973     /*
10974     * This call to xmlXPathCompileExpr() will deactivate sorting
10975     * of the predicate result.
10976     * TODO: Sorting is still activated for filters, since I'm not
10977     *  sure if needed. Normally sorting should not be needed, since
10978     *  a filter can only diminish the number of items in a sequence,
10979     *  but won't change its order; so if the initial sequence is sorted,
10980     *  subsequent sorting is not needed.
10981     */
10982     if (! filter)
10983         xmlXPathCompileExpr(ctxt, 0);
10984     else
10985         xmlXPathCompileExpr(ctxt, 1);
10986     CHECK_ERROR;
10987
10988     if (CUR != ']') {
10989         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10990     }
10991
10992     if (filter)
10993         PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10994     else
10995         PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10996
10997     NEXT;
10998     SKIP_BLANKS;
10999 }
11000
11001 /**
11002  * xmlXPathCompNodeTest:
11003  * @ctxt:  the XPath Parser context
11004  * @test:  pointer to a xmlXPathTestVal
11005  * @type:  pointer to a xmlXPathTypeVal
11006  * @prefix:  placeholder for a possible name prefix
11007  *
11008  * [7] NodeTest ::=   NameTest
11009  *                  | NodeType '(' ')'
11010  *                  | 'processing-instruction' '(' Literal ')'
11011  *
11012  * [37] NameTest ::=  '*'
11013  *                  | NCName ':' '*'
11014  *                  | QName
11015  * [38] NodeType ::= 'comment'
11016  *                 | 'text'
11017  *                 | 'processing-instruction'
11018  *                 | 'node'
11019  *
11020  * Returns the name found and updates @test, @type and @prefix appropriately
11021  */
11022 static xmlChar *
11023 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11024                      xmlXPathTypeVal *type, const xmlChar **prefix,
11025                      xmlChar *name) {
11026     int blanks;
11027
11028     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11029         STRANGE;
11030         return(NULL);
11031     }
11032     *type = (xmlXPathTypeVal) 0;
11033     *test = (xmlXPathTestVal) 0;
11034     *prefix = NULL;
11035     SKIP_BLANKS;
11036
11037     if ((name == NULL) && (CUR == '*')) {
11038         /*
11039          * All elements
11040          */
11041         NEXT;
11042         *test = NODE_TEST_ALL;
11043         return(NULL);
11044     }
11045
11046     if (name == NULL)
11047         name = xmlXPathParseNCName(ctxt);
11048     if (name == NULL) {
11049         XP_ERRORNULL(XPATH_EXPR_ERROR);
11050     }
11051
11052     blanks = IS_BLANK_CH(CUR);
11053     SKIP_BLANKS;
11054     if (CUR == '(') {
11055         NEXT;
11056         /*
11057          * NodeType or PI search
11058          */
11059         if (xmlStrEqual(name, BAD_CAST "comment"))
11060             *type = NODE_TYPE_COMMENT;
11061         else if (xmlStrEqual(name, BAD_CAST "node"))
11062             *type = NODE_TYPE_NODE;
11063         else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11064             *type = NODE_TYPE_PI;
11065         else if (xmlStrEqual(name, BAD_CAST "text"))
11066             *type = NODE_TYPE_TEXT;
11067         else {
11068             if (name != NULL)
11069                 xmlFree(name);
11070             XP_ERRORNULL(XPATH_EXPR_ERROR);
11071         }
11072
11073         *test = NODE_TEST_TYPE;
11074
11075         SKIP_BLANKS;
11076         if (*type == NODE_TYPE_PI) {
11077             /*
11078              * Specific case: search a PI by name.
11079              */
11080             if (name != NULL)
11081                 xmlFree(name);
11082             name = NULL;
11083             if (CUR != ')') {
11084                 name = xmlXPathParseLiteral(ctxt);
11085                 CHECK_ERROR NULL;
11086                 *test = NODE_TEST_PI;
11087                 SKIP_BLANKS;
11088             }
11089         }
11090         if (CUR != ')') {
11091             if (name != NULL)
11092                 xmlFree(name);
11093             XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11094         }
11095         NEXT;
11096         return(name);
11097     }
11098     *test = NODE_TEST_NAME;
11099     if ((!blanks) && (CUR == ':')) {
11100         NEXT;
11101
11102         /*
11103          * Since currently the parser context don't have a
11104          * namespace list associated:
11105          * The namespace name for this prefix can be computed
11106          * only at evaluation time. The compilation is done
11107          * outside of any context.
11108          */
11109 #if 0
11110         *prefix = xmlXPathNsLookup(ctxt->context, name);
11111         if (name != NULL)
11112             xmlFree(name);
11113         if (*prefix == NULL) {
11114             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11115         }
11116 #else
11117         *prefix = name;
11118 #endif
11119
11120         if (CUR == '*') {
11121             /*
11122              * All elements
11123              */
11124             NEXT;
11125             *test = NODE_TEST_ALL;
11126             return(NULL);
11127         }
11128
11129         name = xmlXPathParseNCName(ctxt);
11130         if (name == NULL) {
11131             XP_ERRORNULL(XPATH_EXPR_ERROR);
11132         }
11133     }
11134     return(name);
11135 }
11136
11137 /**
11138  * xmlXPathIsAxisName:
11139  * @name:  a preparsed name token
11140  *
11141  * [6] AxisName ::=   'ancestor'
11142  *                  | 'ancestor-or-self'
11143  *                  | 'attribute'
11144  *                  | 'child'
11145  *                  | 'descendant'
11146  *                  | 'descendant-or-self'
11147  *                  | 'following'
11148  *                  | 'following-sibling'
11149  *                  | 'namespace'
11150  *                  | 'parent'
11151  *                  | 'preceding'
11152  *                  | 'preceding-sibling'
11153  *                  | 'self'
11154  *
11155  * Returns the axis or 0
11156  */
11157 static xmlXPathAxisVal
11158 xmlXPathIsAxisName(const xmlChar *name) {
11159     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11160     switch (name[0]) {
11161         case 'a':
11162             if (xmlStrEqual(name, BAD_CAST "ancestor"))
11163                 ret = AXIS_ANCESTOR;
11164             if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11165                 ret = AXIS_ANCESTOR_OR_SELF;
11166             if (xmlStrEqual(name, BAD_CAST "attribute"))
11167                 ret = AXIS_ATTRIBUTE;
11168             break;
11169         case 'c':
11170             if (xmlStrEqual(name, BAD_CAST "child"))
11171                 ret = AXIS_CHILD;
11172             break;
11173         case 'd':
11174             if (xmlStrEqual(name, BAD_CAST "descendant"))
11175                 ret = AXIS_DESCENDANT;
11176             if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11177                 ret = AXIS_DESCENDANT_OR_SELF;
11178             break;
11179         case 'f':
11180             if (xmlStrEqual(name, BAD_CAST "following"))
11181                 ret = AXIS_FOLLOWING;
11182             if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11183                 ret = AXIS_FOLLOWING_SIBLING;
11184             break;
11185         case 'n':
11186             if (xmlStrEqual(name, BAD_CAST "namespace"))
11187                 ret = AXIS_NAMESPACE;
11188             break;
11189         case 'p':
11190             if (xmlStrEqual(name, BAD_CAST "parent"))
11191                 ret = AXIS_PARENT;
11192             if (xmlStrEqual(name, BAD_CAST "preceding"))
11193                 ret = AXIS_PRECEDING;
11194             if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11195                 ret = AXIS_PRECEDING_SIBLING;
11196             break;
11197         case 's':
11198             if (xmlStrEqual(name, BAD_CAST "self"))
11199                 ret = AXIS_SELF;
11200             break;
11201     }
11202     return(ret);
11203 }
11204
11205 /**
11206  * xmlXPathCompStep:
11207  * @ctxt:  the XPath Parser context
11208  *
11209  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11210  *                  | AbbreviatedStep
11211  *
11212  * [12] AbbreviatedStep ::=   '.' | '..'
11213  *
11214  * [5] AxisSpecifier ::= AxisName '::'
11215  *                  | AbbreviatedAxisSpecifier
11216  *
11217  * [13] AbbreviatedAxisSpecifier ::= '@'?
11218  *
11219  * Modified for XPtr range support as:
11220  *
11221  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11222  *                     | AbbreviatedStep
11223  *                     | 'range-to' '(' Expr ')' Predicate*
11224  *
11225  * Compile one step in a Location Path
11226  * A location step of . is short for self::node(). This is
11227  * particularly useful in conjunction with //. For example, the
11228  * location path .//para is short for
11229  * self::node()/descendant-or-self::node()/child::para
11230  * and so will select all para descendant elements of the context
11231  * node.
11232  * Similarly, a location step of .. is short for parent::node().
11233  * For example, ../title is short for parent::node()/child::title
11234  * and so will select the title children of the parent of the context
11235  * node.
11236  */
11237 static void
11238 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11239 #ifdef LIBXML_XPTR_ENABLED
11240     int rangeto = 0;
11241     int op2 = -1;
11242 #endif
11243
11244     SKIP_BLANKS;
11245     if ((CUR == '.') && (NXT(1) == '.')) {
11246         SKIP(2);
11247         SKIP_BLANKS;
11248         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11249                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11250     } else if (CUR == '.') {
11251         NEXT;
11252         SKIP_BLANKS;
11253     } else {
11254         xmlChar *name = NULL;
11255         const xmlChar *prefix = NULL;
11256         xmlXPathTestVal test = (xmlXPathTestVal) 0;
11257         xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11258         xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11259         int op1;
11260
11261         /*
11262          * The modification needed for XPointer change to the production
11263          */
11264 #ifdef LIBXML_XPTR_ENABLED
11265         if (ctxt->xptr) {
11266             name = xmlXPathParseNCName(ctxt);
11267             if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11268                 op2 = ctxt->comp->last;
11269                 xmlFree(name);
11270                 SKIP_BLANKS;
11271                 if (CUR != '(') {
11272                     XP_ERROR(XPATH_EXPR_ERROR);
11273                 }
11274                 NEXT;
11275                 SKIP_BLANKS;
11276
11277                 xmlXPathCompileExpr(ctxt, 1);
11278                 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11279                 CHECK_ERROR;
11280
11281                 SKIP_BLANKS;
11282                 if (CUR != ')') {
11283                     XP_ERROR(XPATH_EXPR_ERROR);
11284                 }
11285                 NEXT;
11286                 rangeto = 1;
11287                 goto eval_predicates;
11288             }
11289         }
11290 #endif
11291         if (CUR == '*') {
11292             axis = AXIS_CHILD;
11293         } else {
11294             if (name == NULL)
11295                 name = xmlXPathParseNCName(ctxt);
11296             if (name != NULL) {
11297                 axis = xmlXPathIsAxisName(name);
11298                 if (axis != 0) {
11299                     SKIP_BLANKS;
11300                     if ((CUR == ':') && (NXT(1) == ':')) {
11301                         SKIP(2);
11302                         xmlFree(name);
11303                         name = NULL;
11304                     } else {
11305                         /* an element name can conflict with an axis one :-\ */
11306                         axis = AXIS_CHILD;
11307                     }
11308                 } else {
11309                     axis = AXIS_CHILD;
11310                 }
11311             } else if (CUR == '@') {
11312                 NEXT;
11313                 axis = AXIS_ATTRIBUTE;
11314             } else {
11315                 axis = AXIS_CHILD;
11316             }
11317         }
11318
11319         if (ctxt->error != XPATH_EXPRESSION_OK) {
11320             xmlFree(name);
11321             return;
11322         }
11323
11324         name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11325         if (test == 0)
11326             return;
11327
11328         if ((prefix != NULL) && (ctxt->context != NULL) &&
11329             (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11330             if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11331                 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11332             }
11333         }
11334 #ifdef DEBUG_STEP
11335         xmlGenericError(xmlGenericErrorContext,
11336                 "Basis : computing new set\n");
11337 #endif
11338
11339 #ifdef DEBUG_STEP
11340         xmlGenericError(xmlGenericErrorContext, "Basis : ");
11341         if (ctxt->value == NULL)
11342             xmlGenericError(xmlGenericErrorContext, "no value\n");
11343         else if (ctxt->value->nodesetval == NULL)
11344             xmlGenericError(xmlGenericErrorContext, "Empty\n");
11345         else
11346             xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11347 #endif
11348
11349 #ifdef LIBXML_XPTR_ENABLED
11350 eval_predicates:
11351 #endif
11352         op1 = ctxt->comp->last;
11353         ctxt->comp->last = -1;
11354
11355         SKIP_BLANKS;
11356         while (CUR == '[') {
11357             xmlXPathCompPredicate(ctxt, 0);
11358         }
11359
11360 #ifdef LIBXML_XPTR_ENABLED
11361         if (rangeto) {
11362             PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11363         } else
11364 #endif
11365             PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11366                            test, type, (void *)prefix, (void *)name);
11367
11368     }
11369 #ifdef DEBUG_STEP
11370     xmlGenericError(xmlGenericErrorContext, "Step : ");
11371     if (ctxt->value == NULL)
11372         xmlGenericError(xmlGenericErrorContext, "no value\n");
11373     else if (ctxt->value->nodesetval == NULL)
11374         xmlGenericError(xmlGenericErrorContext, "Empty\n");
11375     else
11376         xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11377                 ctxt->value->nodesetval);
11378 #endif
11379 }
11380
11381 /**
11382  * xmlXPathCompRelativeLocationPath:
11383  * @ctxt:  the XPath Parser context
11384  *
11385  *  [3]   RelativeLocationPath ::=   Step
11386  *                     | RelativeLocationPath '/' Step
11387  *                     | AbbreviatedRelativeLocationPath
11388  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11389  *
11390  * Compile a relative location path.
11391  */
11392 static void
11393 xmlXPathCompRelativeLocationPath
11394 (xmlXPathParserContextPtr ctxt) {
11395     SKIP_BLANKS;
11396     if ((CUR == '/') && (NXT(1) == '/')) {
11397         SKIP(2);
11398         SKIP_BLANKS;
11399         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11400                          NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11401     } else if (CUR == '/') {
11402             NEXT;
11403         SKIP_BLANKS;
11404     }
11405     xmlXPathCompStep(ctxt);
11406     CHECK_ERROR;
11407     SKIP_BLANKS;
11408     while (CUR == '/') {
11409         if ((CUR == '/') && (NXT(1) == '/')) {
11410             SKIP(2);
11411             SKIP_BLANKS;
11412             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11413                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11414             xmlXPathCompStep(ctxt);
11415         } else if (CUR == '/') {
11416             NEXT;
11417             SKIP_BLANKS;
11418             xmlXPathCompStep(ctxt);
11419         }
11420         SKIP_BLANKS;
11421     }
11422 }
11423
11424 /**
11425  * xmlXPathCompLocationPath:
11426  * @ctxt:  the XPath Parser context
11427  *
11428  *  [1]   LocationPath ::=   RelativeLocationPath
11429  *                     | AbsoluteLocationPath
11430  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11431  *                     | AbbreviatedAbsoluteLocationPath
11432  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11433  *                           '//' RelativeLocationPath
11434  *
11435  * Compile a location path
11436  *
11437  * // is short for /descendant-or-self::node()/. For example,
11438  * //para is short for /descendant-or-self::node()/child::para and
11439  * so will select any para element in the document (even a para element
11440  * that is a document element will be selected by //para since the
11441  * document element node is a child of the root node); div//para is
11442  * short for div/descendant-or-self::node()/child::para and so will
11443  * select all para descendants of div children.
11444  */
11445 static void
11446 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11447     SKIP_BLANKS;
11448     if (CUR != '/') {
11449         xmlXPathCompRelativeLocationPath(ctxt);
11450     } else {
11451         while (CUR == '/') {
11452             if ((CUR == '/') && (NXT(1) == '/')) {
11453                 SKIP(2);
11454                 SKIP_BLANKS;
11455                 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11456                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11457                 xmlXPathCompRelativeLocationPath(ctxt);
11458             } else if (CUR == '/') {
11459                 NEXT;
11460                 SKIP_BLANKS;
11461                 if ((CUR != 0 ) &&
11462                     ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11463                      (CUR == '@') || (CUR == '*')))
11464                     xmlXPathCompRelativeLocationPath(ctxt);
11465             }
11466             CHECK_ERROR;
11467         }
11468     }
11469 }
11470
11471 /************************************************************************
11472  *                                                                      *
11473  *              XPath precompiled expression evaluation                 *
11474  *                                                                      *
11475  ************************************************************************/
11476
11477 static int
11478 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11479
11480 #ifdef DEBUG_STEP
11481 static void
11482 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11483                           int nbNodes)
11484 {
11485     xmlGenericError(xmlGenericErrorContext, "new step : ");
11486     switch (op->value) {
11487         case AXIS_ANCESTOR:
11488             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11489             break;
11490         case AXIS_ANCESTOR_OR_SELF:
11491             xmlGenericError(xmlGenericErrorContext,
11492                             "axis 'ancestors-or-self' ");
11493             break;
11494         case AXIS_ATTRIBUTE:
11495             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11496             break;
11497         case AXIS_CHILD:
11498             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11499             break;
11500         case AXIS_DESCENDANT:
11501             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11502             break;
11503         case AXIS_DESCENDANT_OR_SELF:
11504             xmlGenericError(xmlGenericErrorContext,
11505                             "axis 'descendant-or-self' ");
11506             break;
11507         case AXIS_FOLLOWING:
11508             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11509             break;
11510         case AXIS_FOLLOWING_SIBLING:
11511             xmlGenericError(xmlGenericErrorContext,
11512                             "axis 'following-siblings' ");
11513             break;
11514         case AXIS_NAMESPACE:
11515             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11516             break;
11517         case AXIS_PARENT:
11518             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11519             break;
11520         case AXIS_PRECEDING:
11521             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11522             break;
11523         case AXIS_PRECEDING_SIBLING:
11524             xmlGenericError(xmlGenericErrorContext,
11525                             "axis 'preceding-sibling' ");
11526             break;
11527         case AXIS_SELF:
11528             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11529             break;
11530     }
11531     xmlGenericError(xmlGenericErrorContext,
11532         " context contains %d nodes\n", nbNodes);
11533     switch (op->value2) {
11534         case NODE_TEST_NONE:
11535             xmlGenericError(xmlGenericErrorContext,
11536                             "           searching for none !!!\n");
11537             break;
11538         case NODE_TEST_TYPE:
11539             xmlGenericError(xmlGenericErrorContext,
11540                             "           searching for type %d\n", op->value3);
11541             break;
11542         case NODE_TEST_PI:
11543             xmlGenericError(xmlGenericErrorContext,
11544                             "           searching for PI !!!\n");
11545             break;
11546         case NODE_TEST_ALL:
11547             xmlGenericError(xmlGenericErrorContext,
11548                             "           searching for *\n");
11549             break;
11550         case NODE_TEST_NS:
11551             xmlGenericError(xmlGenericErrorContext,
11552                             "           searching for namespace %s\n",
11553                             op->value5);
11554             break;
11555         case NODE_TEST_NAME:
11556             xmlGenericError(xmlGenericErrorContext,
11557                             "           searching for name %s\n", op->value5);
11558             if (op->value4)
11559                 xmlGenericError(xmlGenericErrorContext,
11560                                 "           with namespace %s\n", op->value4);
11561             break;
11562     }
11563     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11564 }
11565 #endif /* DEBUG_STEP */
11566
11567 static int
11568 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11569                             xmlXPathStepOpPtr op,
11570                             xmlNodeSetPtr set,
11571                             int contextSize,
11572                             int hasNsNodes)
11573 {
11574     if (op->ch1 != -1) {
11575         xmlXPathCompExprPtr comp = ctxt->comp;
11576         /*
11577         * Process inner predicates first.
11578         */
11579         if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11580             /*
11581             * TODO: raise an internal error.
11582             */
11583         }
11584         contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11585             &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11586         CHECK_ERROR0;
11587         if (contextSize <= 0)
11588             return(0);
11589     }
11590     if (op->ch2 != -1) {
11591         xmlXPathContextPtr xpctxt = ctxt->context;
11592         xmlNodePtr contextNode, oldContextNode;
11593         xmlDocPtr oldContextDoc;
11594         int i, res, contextPos = 0, newContextSize;
11595         xmlXPathStepOpPtr exprOp;
11596         xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11597
11598 #ifdef LIBXML_XPTR_ENABLED
11599         /*
11600         * URGENT TODO: Check the following:
11601         *  We don't expect location sets if evaluating prediates, right?
11602         *  Only filters should expect location sets, right?
11603         */
11604 #endif
11605         /*
11606         * SPEC XPath 1.0:
11607         *  "For each node in the node-set to be filtered, the
11608         *  PredicateExpr is evaluated with that node as the
11609         *  context node, with the number of nodes in the
11610         *  node-set as the context size, and with the proximity
11611         *  position of the node in the node-set with respect to
11612         *  the axis as the context position;"
11613         * @oldset is the node-set" to be filtered.
11614         *
11615         * SPEC XPath 1.0:
11616         *  "only predicates change the context position and
11617         *  context size (see [2.4 Predicates])."
11618         * Example:
11619         *   node-set  context pos
11620         *    nA         1
11621         *    nB         2
11622         *    nC         3
11623         *   After applying predicate [position() > 1] :
11624         *   node-set  context pos
11625         *    nB         1
11626         *    nC         2
11627         */
11628         oldContextNode = xpctxt->node;
11629         oldContextDoc = xpctxt->doc;
11630         /*
11631         * Get the expression of this predicate.
11632         */
11633         exprOp = &ctxt->comp->steps[op->ch2];
11634         newContextSize = 0;
11635         for (i = 0; i < set->nodeNr; i++) {
11636             if (set->nodeTab[i] == NULL)
11637                 continue;
11638
11639             contextNode = set->nodeTab[i];
11640             xpctxt->node = contextNode;
11641             xpctxt->contextSize = contextSize;
11642             xpctxt->proximityPosition = ++contextPos;
11643
11644             /*
11645             * Also set the xpath document in case things like
11646             * key() are evaluated in the predicate.
11647             */
11648             if ((contextNode->type != XML_NAMESPACE_DECL) &&
11649                 (contextNode->doc != NULL))
11650                 xpctxt->doc = contextNode->doc;
11651             /*
11652             * Evaluate the predicate expression with 1 context node
11653             * at a time; this node is packaged into a node set; this
11654             * node set is handed over to the evaluation mechanism.
11655             */
11656             if (contextObj == NULL)
11657                 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11658             else
11659                 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11660                     contextNode);
11661
11662             valuePush(ctxt, contextObj);
11663
11664             res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11665
11666             if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11667                 xmlXPathNodeSetClear(set, hasNsNodes);
11668                 newContextSize = 0;
11669                 goto evaluation_exit;
11670             }
11671
11672             if (res != 0) {
11673                 newContextSize++;
11674             } else {
11675                 /*
11676                 * Remove the entry from the initial node set.
11677                 */
11678                 set->nodeTab[i] = NULL;
11679                 if (contextNode->type == XML_NAMESPACE_DECL)
11680                     xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11681             }
11682             if (ctxt->value == contextObj) {
11683                 /*
11684                 * Don't free the temporary XPath object holding the
11685                 * context node, in order to avoid massive recreation
11686                 * inside this loop.
11687                 */
11688                 valuePop(ctxt);
11689                 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11690             } else {
11691                 /*
11692                 * TODO: The object was lost in the evaluation machinery.
11693                 *  Can this happen? Maybe in internal-error cases.
11694                 */
11695                 contextObj = NULL;
11696             }
11697         }
11698
11699         if (contextObj != NULL) {
11700             if (ctxt->value == contextObj)
11701                 valuePop(ctxt);
11702             xmlXPathReleaseObject(xpctxt, contextObj);
11703         }
11704 evaluation_exit:
11705         if (exprRes != NULL)
11706             xmlXPathReleaseObject(ctxt->context, exprRes);
11707         /*
11708         * Reset/invalidate the context.
11709         */
11710         xpctxt->node = oldContextNode;
11711         xpctxt->doc = oldContextDoc;
11712         xpctxt->contextSize = -1;
11713         xpctxt->proximityPosition = -1;
11714         return(newContextSize);
11715     }
11716     return(contextSize);
11717 }
11718
11719 static int
11720 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11721                                       xmlXPathStepOpPtr op,
11722                                       xmlNodeSetPtr set,
11723                                       int contextSize,
11724                                       int minPos,
11725                                       int maxPos,
11726                                       int hasNsNodes)
11727 {
11728     if (op->ch1 != -1) {
11729         xmlXPathCompExprPtr comp = ctxt->comp;
11730         if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11731             /*
11732             * TODO: raise an internal error.
11733             */
11734         }
11735         contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11736             &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11737         CHECK_ERROR0;
11738         if (contextSize <= 0)
11739             return(0);
11740     }
11741     /*
11742     * Check if the node set contains a sufficient number of nodes for
11743     * the requested range.
11744     */
11745     if (contextSize < minPos) {
11746         xmlXPathNodeSetClear(set, hasNsNodes);
11747         return(0);
11748     }
11749     if (op->ch2 == -1) {
11750         /*
11751         * TODO: Can this ever happen?
11752         */
11753         return (contextSize);
11754     } else {
11755         xmlDocPtr oldContextDoc;
11756         int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11757         xmlXPathStepOpPtr exprOp;
11758         xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11759         xmlNodePtr oldContextNode, contextNode = NULL;
11760         xmlXPathContextPtr xpctxt = ctxt->context;
11761         int frame;
11762
11763 #ifdef LIBXML_XPTR_ENABLED
11764             /*
11765             * URGENT TODO: Check the following:
11766             *  We don't expect location sets if evaluating prediates, right?
11767             *  Only filters should expect location sets, right?
11768         */
11769 #endif /* LIBXML_XPTR_ENABLED */
11770
11771         /*
11772         * Save old context.
11773         */
11774         oldContextNode = xpctxt->node;
11775         oldContextDoc = xpctxt->doc;
11776         /*
11777         * Get the expression of this predicate.
11778         */
11779         exprOp = &ctxt->comp->steps[op->ch2];
11780         for (i = 0; i < set->nodeNr; i++) {
11781             xmlXPathObjectPtr tmp;
11782
11783             if (set->nodeTab[i] == NULL)
11784                 continue;
11785
11786             contextNode = set->nodeTab[i];
11787             xpctxt->node = contextNode;
11788             xpctxt->contextSize = contextSize;
11789             xpctxt->proximityPosition = ++contextPos;
11790
11791             /*
11792             * Initialize the new set.
11793             * Also set the xpath document in case things like
11794             * key() evaluation are attempted on the predicate
11795             */
11796             if ((contextNode->type != XML_NAMESPACE_DECL) &&
11797                 (contextNode->doc != NULL))
11798                 xpctxt->doc = contextNode->doc;
11799             /*
11800             * Evaluate the predicate expression with 1 context node
11801             * at a time; this node is packaged into a node set; this
11802             * node set is handed over to the evaluation mechanism.
11803             */
11804             if (contextObj == NULL)
11805                 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11806             else
11807                 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11808                     contextNode);
11809
11810             frame = xmlXPathSetFrame(ctxt);
11811             valuePush(ctxt, contextObj);
11812             res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11813             tmp = valuePop(ctxt);
11814             xmlXPathPopFrame(ctxt, frame);
11815
11816             if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11817                 while (tmp != contextObj) {
11818                     /*
11819                      * Free up the result
11820                      * then pop off contextObj, which will be freed later
11821                      */
11822                     xmlXPathReleaseObject(xpctxt, tmp);
11823                     tmp = valuePop(ctxt);
11824                 }
11825                 goto evaluation_error;
11826             }
11827             /* push the result back onto the stack */
11828             valuePush(ctxt, tmp);
11829
11830             if (res)
11831                 pos++;
11832
11833             if (res && (pos >= minPos) && (pos <= maxPos)) {
11834                 /*
11835                 * Fits in the requested range.
11836                 */
11837                 newContextSize++;
11838                 if (minPos == maxPos) {
11839                     /*
11840                     * Only 1 node was requested.
11841                     */
11842                     if (contextNode->type == XML_NAMESPACE_DECL) {
11843                         /*
11844                         * As always: take care of those nasty
11845                         * namespace nodes.
11846                         */
11847                         set->nodeTab[i] = NULL;
11848                     }
11849                     xmlXPathNodeSetClear(set, hasNsNodes);
11850                     set->nodeNr = 1;
11851                     set->nodeTab[0] = contextNode;
11852                     goto evaluation_exit;
11853                 }
11854                 if (pos == maxPos) {
11855                     /*
11856                     * We are done.
11857                     */
11858                     xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11859                     goto evaluation_exit;
11860                 }
11861             } else {
11862                 /*
11863                 * Remove the entry from the initial node set.
11864                 */
11865                 set->nodeTab[i] = NULL;
11866                 if (contextNode->type == XML_NAMESPACE_DECL)
11867                     xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11868             }
11869             if (exprRes != NULL) {
11870                 xmlXPathReleaseObject(ctxt->context, exprRes);
11871                 exprRes = NULL;
11872             }
11873             if (ctxt->value == contextObj) {
11874                 /*
11875                 * Don't free the temporary XPath object holding the
11876                 * context node, in order to avoid massive recreation
11877                 * inside this loop.
11878                 */
11879                 valuePop(ctxt);
11880                 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11881             } else {
11882                 /*
11883                 * The object was lost in the evaluation machinery.
11884                 * Can this happen? Maybe in case of internal-errors.
11885                 */
11886                 contextObj = NULL;
11887             }
11888         }
11889         goto evaluation_exit;
11890
11891 evaluation_error:
11892         xmlXPathNodeSetClear(set, hasNsNodes);
11893         newContextSize = 0;
11894
11895 evaluation_exit:
11896         if (contextObj != NULL) {
11897             if (ctxt->value == contextObj)
11898                 valuePop(ctxt);
11899             xmlXPathReleaseObject(xpctxt, contextObj);
11900         }
11901         if (exprRes != NULL)
11902             xmlXPathReleaseObject(ctxt->context, exprRes);
11903         /*
11904         * Reset/invalidate the context.
11905         */
11906         xpctxt->node = oldContextNode;
11907         xpctxt->doc = oldContextDoc;
11908         xpctxt->contextSize = -1;
11909         xpctxt->proximityPosition = -1;
11910         return(newContextSize);
11911     }
11912     return(contextSize);
11913 }
11914
11915 static int
11916 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11917                             xmlXPathStepOpPtr op,
11918                             int *maxPos)
11919 {
11920
11921     xmlXPathStepOpPtr exprOp;
11922
11923     /*
11924     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11925     */
11926
11927     /*
11928     * If not -1, then ch1 will point to:
11929     * 1) For predicates (XPATH_OP_PREDICATE):
11930     *    - an inner predicate operator
11931     * 2) For filters (XPATH_OP_FILTER):
11932     *    - an inner filter operater OR
11933     *    - an expression selecting the node set.
11934     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11935     */
11936     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11937         return(0);
11938
11939     if (op->ch2 != -1) {
11940         exprOp = &ctxt->comp->steps[op->ch2];
11941     } else
11942         return(0);
11943
11944     if ((exprOp != NULL) &&
11945         (exprOp->op == XPATH_OP_VALUE) &&
11946         (exprOp->value4 != NULL) &&
11947         (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11948     {
11949         /*
11950         * We have a "[n]" predicate here.
11951         * TODO: Unfortunately this simplistic test here is not
11952         * able to detect a position() predicate in compound
11953         * expressions like "[@attr = 'a" and position() = 1],
11954         * and even not the usage of position() in
11955         * "[position() = 1]"; thus - obviously - a position-range,
11956         * like it "[position() < 5]", is also not detected.
11957         * Maybe we could rewrite the AST to ease the optimization.
11958         */
11959         *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11960
11961         if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11962             (float) *maxPos)
11963         {
11964             return(1);
11965         }
11966     }
11967     return(0);
11968 }
11969
11970 static int
11971 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11972                            xmlXPathStepOpPtr op,
11973                            xmlNodePtr * first, xmlNodePtr * last,
11974                            int toBool)
11975 {
11976
11977 #define XP_TEST_HIT \
11978     if (hasAxisRange != 0) { \
11979         if (++pos == maxPos) { \
11980             addNode(seq, cur); \
11981         goto axis_range_end; } \
11982     } else { \
11983         addNode(seq, cur); \
11984         if (breakOnFirstHit) goto first_hit; }
11985
11986 #define XP_TEST_HIT_NS \
11987     if (hasAxisRange != 0) { \
11988         if (++pos == maxPos) { \
11989             hasNsNodes = 1; \
11990             xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11991         goto axis_range_end; } \
11992     } else { \
11993         hasNsNodes = 1; \
11994         xmlXPathNodeSetAddNs(seq, \
11995         xpctxt->node, (xmlNsPtr) cur); \
11996         if (breakOnFirstHit) goto first_hit; }
11997
11998     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11999     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12000     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12001     const xmlChar *prefix = op->value4;
12002     const xmlChar *name = op->value5;
12003     const xmlChar *URI = NULL;
12004
12005 #ifdef DEBUG_STEP
12006     int nbMatches = 0, prevMatches = 0;
12007 #endif
12008     int total = 0, hasNsNodes = 0;
12009     /* The popped object holding the context nodes */
12010     xmlXPathObjectPtr obj;
12011     /* The set of context nodes for the node tests */
12012     xmlNodeSetPtr contextSeq;
12013     int contextIdx;
12014     xmlNodePtr contextNode;
12015     /* The context node for a compound traversal */
12016     xmlNodePtr outerContextNode;
12017     /* The final resulting node set wrt to all context nodes */
12018     xmlNodeSetPtr outSeq;
12019     /*
12020     * The temporary resulting node set wrt 1 context node.
12021     * Used to feed predicate evaluation.
12022     */
12023     xmlNodeSetPtr seq;
12024     xmlNodePtr cur;
12025     /* First predicate operator */
12026     xmlXPathStepOpPtr predOp;
12027     int maxPos; /* The requested position() (when a "[n]" predicate) */
12028     int hasPredicateRange, hasAxisRange, pos, size, newSize;
12029     int breakOnFirstHit;
12030
12031     xmlXPathTraversalFunction next = NULL;
12032     /* compound axis traversal */
12033     xmlXPathTraversalFunctionExt outerNext = NULL;
12034     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12035     xmlXPathNodeSetMergeFunction mergeAndClear;
12036     xmlNodePtr oldContextNode;
12037     xmlXPathContextPtr xpctxt = ctxt->context;
12038
12039
12040     CHECK_TYPE0(XPATH_NODESET);
12041     obj = valuePop(ctxt);
12042     /*
12043     * Setup namespaces.
12044     */
12045     if (prefix != NULL) {
12046         URI = xmlXPathNsLookup(xpctxt, prefix);
12047         if (URI == NULL) {
12048             xmlXPathReleaseObject(xpctxt, obj);
12049             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12050         }
12051     }
12052     /*
12053     * Setup axis.
12054     *
12055     * MAYBE FUTURE TODO: merging optimizations:
12056     * - If the nodes to be traversed wrt to the initial nodes and
12057     *   the current axis cannot overlap, then we could avoid searching
12058     *   for duplicates during the merge.
12059     *   But the question is how/when to evaluate if they cannot overlap.
12060     *   Example: if we know that for two initial nodes, the one is
12061     *   not in the ancestor-or-self axis of the other, then we could safely
12062     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12063     *   the descendant-or-self axis.
12064     */
12065     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12066     switch (axis) {
12067         case AXIS_ANCESTOR:
12068             first = NULL;
12069             next = xmlXPathNextAncestor;
12070             break;
12071         case AXIS_ANCESTOR_OR_SELF:
12072             first = NULL;
12073             next = xmlXPathNextAncestorOrSelf;
12074             break;
12075         case AXIS_ATTRIBUTE:
12076             first = NULL;
12077             last = NULL;
12078             next = xmlXPathNextAttribute;
12079             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12080             break;
12081         case AXIS_CHILD:
12082             last = NULL;
12083             if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12084                 /*
12085                 * This iterator will give us only nodes which can
12086                 * hold element nodes.
12087                 */
12088                 outerNext = xmlXPathNextDescendantOrSelfElemParent;
12089             }
12090             if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12091                 (type == NODE_TYPE_NODE))
12092             {
12093                 /*
12094                 * Optimization if an element node type is 'element'.
12095                 */
12096                 next = xmlXPathNextChildElement;
12097             } else
12098                 next = xmlXPathNextChild;
12099             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12100             break;
12101         case AXIS_DESCENDANT:
12102             last = NULL;
12103             next = xmlXPathNextDescendant;
12104             break;
12105         case AXIS_DESCENDANT_OR_SELF:
12106             last = NULL;
12107             next = xmlXPathNextDescendantOrSelf;
12108             break;
12109         case AXIS_FOLLOWING:
12110             last = NULL;
12111             next = xmlXPathNextFollowing;
12112             break;
12113         case AXIS_FOLLOWING_SIBLING:
12114             last = NULL;
12115             next = xmlXPathNextFollowingSibling;
12116             break;
12117         case AXIS_NAMESPACE:
12118             first = NULL;
12119             last = NULL;
12120             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12121             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12122             break;
12123         case AXIS_PARENT:
12124             first = NULL;
12125             next = xmlXPathNextParent;
12126             break;
12127         case AXIS_PRECEDING:
12128             first = NULL;
12129             next = xmlXPathNextPrecedingInternal;
12130             break;
12131         case AXIS_PRECEDING_SIBLING:
12132             first = NULL;
12133             next = xmlXPathNextPrecedingSibling;
12134             break;
12135         case AXIS_SELF:
12136             first = NULL;
12137             last = NULL;
12138             next = xmlXPathNextSelf;
12139             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12140             break;
12141     }
12142
12143 #ifdef DEBUG_STEP
12144     xmlXPathDebugDumpStepAxis(op,
12145         (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12146 #endif
12147
12148     if (next == NULL) {
12149         xmlXPathReleaseObject(xpctxt, obj);
12150         return(0);
12151     }
12152     contextSeq = obj->nodesetval;
12153     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12154         xmlXPathReleaseObject(xpctxt, obj);
12155         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12156         return(0);
12157     }
12158     /*
12159     * Predicate optimization ---------------------------------------------
12160     * If this step has a last predicate, which contains a position(),
12161     * then we'll optimize (although not exactly "position()", but only
12162     * the  short-hand form, i.e., "[n]".
12163     *
12164     * Example - expression "/foo[parent::bar][1]":
12165     *
12166     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12167     *   ROOT                               -- op->ch1
12168     *   PREDICATE                          -- op->ch2 (predOp)
12169     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12170     *       SORT
12171     *         COLLECT  'parent' 'name' 'node' bar
12172     *           NODE
12173     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12174     *
12175     */
12176     maxPos = 0;
12177     predOp = NULL;
12178     hasPredicateRange = 0;
12179     hasAxisRange = 0;
12180     if (op->ch2 != -1) {
12181         /*
12182         * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12183         */
12184         predOp = &ctxt->comp->steps[op->ch2];
12185         if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12186             if (predOp->ch1 != -1) {
12187                 /*
12188                 * Use the next inner predicate operator.
12189                 */
12190                 predOp = &ctxt->comp->steps[predOp->ch1];
12191                 hasPredicateRange = 1;
12192             } else {
12193                 /*
12194                 * There's no other predicate than the [n] predicate.
12195                 */
12196                 predOp = NULL;
12197                 hasAxisRange = 1;
12198             }
12199         }
12200     }
12201     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12202     /*
12203     * Axis traversal -----------------------------------------------------
12204     */
12205     /*
12206      * 2.3 Node Tests
12207      *  - For the attribute axis, the principal node type is attribute.
12208      *  - For the namespace axis, the principal node type is namespace.
12209      *  - For other axes, the principal node type is element.
12210      *
12211      * A node test * is true for any node of the
12212      * principal node type. For example, child::* will
12213      * select all element children of the context node
12214      */
12215     oldContextNode = xpctxt->node;
12216     addNode = xmlXPathNodeSetAddUnique;
12217     outSeq = NULL;
12218     seq = NULL;
12219     outerContextNode = NULL;
12220     contextNode = NULL;
12221     contextIdx = 0;
12222
12223
12224     while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12225         if (outerNext != NULL) {
12226             /*
12227             * This is a compound traversal.
12228             */
12229             if (contextNode == NULL) {
12230                 /*
12231                 * Set the context for the outer traversal.
12232                 */
12233                 outerContextNode = contextSeq->nodeTab[contextIdx++];
12234                 contextNode = outerNext(NULL, outerContextNode);
12235             } else
12236                 contextNode = outerNext(contextNode, outerContextNode);
12237             if (contextNode == NULL)
12238                 continue;
12239             /*
12240             * Set the context for the main traversal.
12241             */
12242             xpctxt->node = contextNode;
12243         } else
12244             xpctxt->node = contextSeq->nodeTab[contextIdx++];
12245
12246         if (seq == NULL) {
12247             seq = xmlXPathNodeSetCreate(NULL);
12248             if (seq == NULL) {
12249                 total = 0;
12250                 goto error;
12251             }
12252         }
12253         /*
12254         * Traverse the axis and test the nodes.
12255         */
12256         pos = 0;
12257         cur = NULL;
12258         hasNsNodes = 0;
12259         do {
12260             cur = next(ctxt, cur);
12261             if (cur == NULL)
12262                 break;
12263
12264             /*
12265             * QUESTION TODO: What does the "first" and "last" stuff do?
12266             */
12267             if ((first != NULL) && (*first != NULL)) {
12268                 if (*first == cur)
12269                     break;
12270                 if (((total % 256) == 0) &&
12271 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12272                     (xmlXPathCmpNodesExt(*first, cur) >= 0))
12273 #else
12274                     (xmlXPathCmpNodes(*first, cur) >= 0))
12275 #endif
12276                 {
12277                     break;
12278                 }
12279             }
12280             if ((last != NULL) && (*last != NULL)) {
12281                 if (*last == cur)
12282                     break;
12283                 if (((total % 256) == 0) &&
12284 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12285                     (xmlXPathCmpNodesExt(cur, *last) >= 0))
12286 #else
12287                     (xmlXPathCmpNodes(cur, *last) >= 0))
12288 #endif
12289                 {
12290                     break;
12291                 }
12292             }
12293
12294             total++;
12295
12296 #ifdef DEBUG_STEP
12297             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12298 #endif
12299
12300             switch (test) {
12301                 case NODE_TEST_NONE:
12302                     total = 0;
12303                     STRANGE
12304                     goto error;
12305                 case NODE_TEST_TYPE:
12306                     /*
12307                     * TODO: Don't we need to use
12308                     *  xmlXPathNodeSetAddNs() for namespace nodes here?
12309                     *  Surprisingly, some c14n tests fail, if we do this.
12310                     */
12311                     if (type == NODE_TYPE_NODE) {
12312                         switch (cur->type) {
12313                             case XML_DOCUMENT_NODE:
12314                             case XML_HTML_DOCUMENT_NODE:
12315 #ifdef LIBXML_DOCB_ENABLED
12316                             case XML_DOCB_DOCUMENT_NODE:
12317 #endif
12318                             case XML_ELEMENT_NODE:
12319                             case XML_ATTRIBUTE_NODE:
12320                             case XML_PI_NODE:
12321                             case XML_COMMENT_NODE:
12322                             case XML_CDATA_SECTION_NODE:
12323                             case XML_TEXT_NODE:
12324                             case XML_NAMESPACE_DECL:
12325                                 XP_TEST_HIT
12326                                 break;
12327                             default:
12328                                 break;
12329                         }
12330                     } else if (cur->type == type) {
12331                         if (type == XML_NAMESPACE_DECL)
12332                             XP_TEST_HIT_NS
12333                         else
12334                             XP_TEST_HIT
12335                     } else if ((type == NODE_TYPE_TEXT) &&
12336                          (cur->type == XML_CDATA_SECTION_NODE))
12337                     {
12338                         XP_TEST_HIT
12339                     }
12340                     break;
12341                 case NODE_TEST_PI:
12342                     if ((cur->type == XML_PI_NODE) &&
12343                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12344                     {
12345                         XP_TEST_HIT
12346                     }
12347                     break;
12348                 case NODE_TEST_ALL:
12349                     if (axis == AXIS_ATTRIBUTE) {
12350                         if (cur->type == XML_ATTRIBUTE_NODE)
12351                         {
12352                             XP_TEST_HIT
12353                         }
12354                     } else if (axis == AXIS_NAMESPACE) {
12355                         if (cur->type == XML_NAMESPACE_DECL)
12356                         {
12357                             XP_TEST_HIT_NS
12358                         }
12359                     } else {
12360                         if (cur->type == XML_ELEMENT_NODE) {
12361                             if (prefix == NULL)
12362                             {
12363                                 XP_TEST_HIT
12364
12365                             } else if ((cur->ns != NULL) &&
12366                                 (xmlStrEqual(URI, cur->ns->href)))
12367                             {
12368                                 XP_TEST_HIT
12369                             }
12370                         }
12371                     }
12372                     break;
12373                 case NODE_TEST_NS:{
12374                         TODO;
12375                         break;
12376                     }
12377                 case NODE_TEST_NAME:
12378                     if (axis == AXIS_ATTRIBUTE) {
12379                         if (cur->type != XML_ATTRIBUTE_NODE)
12380                             break;
12381                     } else if (axis == AXIS_NAMESPACE) {
12382                         if (cur->type != XML_NAMESPACE_DECL)
12383                             break;
12384                     } else {
12385                         if (cur->type != XML_ELEMENT_NODE)
12386                             break;
12387                     }
12388                     switch (cur->type) {
12389                         case XML_ELEMENT_NODE:
12390                             if (xmlStrEqual(name, cur->name)) {
12391                                 if (prefix == NULL) {
12392                                     if (cur->ns == NULL)
12393                                     {
12394                                         XP_TEST_HIT
12395                                     }
12396                                 } else {
12397                                     if ((cur->ns != NULL) &&
12398                                         (xmlStrEqual(URI, cur->ns->href)))
12399                                     {
12400                                         XP_TEST_HIT
12401                                     }
12402                                 }
12403                             }
12404                             break;
12405                         case XML_ATTRIBUTE_NODE:{
12406                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12407
12408                                 if (xmlStrEqual(name, attr->name)) {
12409                                     if (prefix == NULL) {
12410                                         if ((attr->ns == NULL) ||
12411                                             (attr->ns->prefix == NULL))
12412                                         {
12413                                             XP_TEST_HIT
12414                                         }
12415                                     } else {
12416                                         if ((attr->ns != NULL) &&
12417                                             (xmlStrEqual(URI,
12418                                               attr->ns->href)))
12419                                         {
12420                                             XP_TEST_HIT
12421                                         }
12422                                     }
12423                                 }
12424                                 break;
12425                             }
12426                         case XML_NAMESPACE_DECL:
12427                             if (cur->type == XML_NAMESPACE_DECL) {
12428                                 xmlNsPtr ns = (xmlNsPtr) cur;
12429
12430                                 if ((ns->prefix != NULL) && (name != NULL)
12431                                     && (xmlStrEqual(ns->prefix, name)))
12432                                 {
12433                                     XP_TEST_HIT_NS
12434                                 }
12435                             }
12436                             break;
12437                         default:
12438                             break;
12439                     }
12440                     break;
12441             } /* switch(test) */
12442         } while (cur != NULL);
12443
12444         goto apply_predicates;
12445
12446 axis_range_end: /* ----------------------------------------------------- */
12447         /*
12448         * We have a "/foo[n]", and position() = n was reached.
12449         * Note that we can have as well "/foo/::parent::foo[1]", so
12450         * a duplicate-aware merge is still needed.
12451         * Merge with the result.
12452         */
12453         if (outSeq == NULL) {
12454             outSeq = seq;
12455             seq = NULL;
12456         } else
12457             outSeq = mergeAndClear(outSeq, seq, 0);
12458         /*
12459         * Break if only a true/false result was requested.
12460         */
12461         if (toBool)
12462             break;
12463         continue;
12464
12465 first_hit: /* ---------------------------------------------------------- */
12466         /*
12467         * Break if only a true/false result was requested and
12468         * no predicates existed and a node test succeeded.
12469         */
12470         if (outSeq == NULL) {
12471             outSeq = seq;
12472             seq = NULL;
12473         } else
12474             outSeq = mergeAndClear(outSeq, seq, 0);
12475         break;
12476
12477 #ifdef DEBUG_STEP
12478         if (seq != NULL)
12479             nbMatches += seq->nodeNr;
12480 #endif
12481
12482 apply_predicates: /* --------------------------------------------------- */
12483         /*
12484         * Apply predicates.
12485         */
12486         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12487             /*
12488             * E.g. when we have a "/foo[some expression][n]".
12489             */      
12490             /*
12491             * QUESTION TODO: The old predicate evaluation took into
12492             *  account location-sets.
12493             *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12494             *  Do we expect such a set here?
12495             *  All what I learned now from the evaluation semantics
12496             *  does not indicate that a location-set will be processed
12497             *  here, so this looks OK.
12498             */      
12499             /*
12500             * Iterate over all predicates, starting with the outermost
12501             * predicate.
12502             * TODO: Problem: we cannot execute the inner predicates first
12503             *  since we cannot go back *up* the operator tree!
12504             *  Options we have:
12505             *  1) Use of recursive functions (like is it currently done
12506             *     via xmlXPathCompOpEval())
12507             *  2) Add a predicate evaluation information stack to the
12508             *     context struct
12509             *  3) Change the way the operators are linked; we need a
12510             *     "parent" field on xmlXPathStepOp
12511             *
12512             * For the moment, I'll try to solve this with a recursive
12513             * function: xmlXPathCompOpEvalPredicate().
12514             */
12515             size = seq->nodeNr;
12516             if (hasPredicateRange != 0)
12517                 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12518                     predOp, seq, size, maxPos, maxPos, hasNsNodes);
12519             else
12520                 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12521                     predOp, seq, size, hasNsNodes);
12522
12523             if (ctxt->error != XPATH_EXPRESSION_OK) {
12524                 total = 0;
12525                 goto error;
12526             }
12527             /*
12528             * Add the filtered set of nodes to the result node set.
12529             */
12530             if (newSize == 0) {
12531                 /*
12532                 * The predicates filtered all nodes out.
12533                 */
12534                 xmlXPathNodeSetClear(seq, hasNsNodes);
12535             } else if (seq->nodeNr > 0) {
12536                 /*
12537                 * Add to result set.
12538                 */
12539                 if (outSeq == NULL) {
12540                     if (size != newSize) {
12541                         /*
12542                         * We need to merge and clear here, since
12543                         * the sequence will contained NULLed entries.
12544                         */
12545                         outSeq = mergeAndClear(NULL, seq, 1);
12546                     } else {
12547                         outSeq = seq;
12548                         seq = NULL;
12549                     }
12550                 } else
12551                     outSeq = mergeAndClear(outSeq, seq,
12552                         (size != newSize) ? 1: 0);
12553                 /*
12554                 * Break if only a true/false result was requested.
12555                 */
12556                 if (toBool)
12557                     break;
12558             }
12559         } else if (seq->nodeNr > 0) {
12560             /*
12561             * Add to result set.
12562             */
12563             if (outSeq == NULL) {
12564                 outSeq = seq;
12565                 seq = NULL;
12566             } else {
12567                 outSeq = mergeAndClear(outSeq, seq, 0);
12568             }
12569         }
12570     }
12571
12572 error:
12573     if ((obj->boolval) && (obj->user != NULL)) {
12574         /*
12575         * QUESTION TODO: What does this do and why?
12576         * TODO: Do we have to do this also for the "error"
12577         * cleanup further down?
12578         */
12579         ctxt->value->boolval = 1;
12580         ctxt->value->user = obj->user;
12581         obj->user = NULL;
12582         obj->boolval = 0;
12583     }
12584     xmlXPathReleaseObject(xpctxt, obj);
12585
12586     /*
12587     * Ensure we return at least an emtpy set.
12588     */
12589     if (outSeq == NULL) {
12590         if ((seq != NULL) && (seq->nodeNr == 0))
12591             outSeq = seq;
12592         else
12593             outSeq = xmlXPathNodeSetCreate(NULL);
12594         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12595     }
12596     if ((seq != NULL) && (seq != outSeq)) {
12597          xmlXPathFreeNodeSet(seq);
12598     }
12599     /*
12600     * Hand over the result. Better to push the set also in
12601     * case of errors.
12602     */
12603     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12604     /*
12605     * Reset the context node.
12606     */
12607     xpctxt->node = oldContextNode;
12608
12609 #ifdef DEBUG_STEP
12610     xmlGenericError(xmlGenericErrorContext,
12611         "\nExamined %d nodes, found %d nodes at that step\n",
12612         total, nbMatches);
12613 #endif
12614
12615     return(total);
12616 }
12617
12618 static int
12619 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12620                               xmlXPathStepOpPtr op, xmlNodePtr * first);
12621
12622 /**
12623  * xmlXPathCompOpEvalFirst:
12624  * @ctxt:  the XPath parser context with the compiled expression
12625  * @op:  an XPath compiled operation
12626  * @first:  the first elem found so far
12627  *
12628  * Evaluate the Precompiled XPath operation searching only the first
12629  * element in document order
12630  *
12631  * Returns the number of examined objects.
12632  */
12633 static int
12634 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12635                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12636 {
12637     int total = 0, cur;
12638     xmlXPathCompExprPtr comp;
12639     xmlXPathObjectPtr arg1, arg2;
12640
12641     CHECK_ERROR0;
12642     comp = ctxt->comp;
12643     switch (op->op) {
12644         case XPATH_OP_END:
12645             return (0);
12646         case XPATH_OP_UNION:
12647             total =
12648                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12649                                         first);
12650             CHECK_ERROR0;
12651             if ((ctxt->value != NULL)
12652                 && (ctxt->value->type == XPATH_NODESET)
12653                 && (ctxt->value->nodesetval != NULL)
12654                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12655                 /*
12656                  * limit tree traversing to first node in the result
12657                  */
12658                 /*
12659                 * OPTIMIZE TODO: This implicitely sorts
12660                 *  the result, even if not needed. E.g. if the argument
12661                 *  of the count() function, no sorting is needed.
12662                 * OPTIMIZE TODO: How do we know if the node-list wasn't
12663                 *  aready sorted?
12664                 */
12665                 if (ctxt->value->nodesetval->nodeNr > 1)
12666                     xmlXPathNodeSetSort(ctxt->value->nodesetval);
12667                 *first = ctxt->value->nodesetval->nodeTab[0];
12668             }
12669             cur =
12670                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12671                                         first);
12672             CHECK_ERROR0;
12673             CHECK_TYPE0(XPATH_NODESET);
12674             arg2 = valuePop(ctxt);
12675
12676             CHECK_TYPE0(XPATH_NODESET);
12677             arg1 = valuePop(ctxt);
12678
12679             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12680                                                     arg2->nodesetval);
12681             valuePush(ctxt, arg1);
12682             xmlXPathReleaseObject(ctxt->context, arg2);
12683             /* optimizer */
12684             if (total > cur)
12685                 xmlXPathCompSwap(op);
12686             return (total + cur);
12687         case XPATH_OP_ROOT:
12688             xmlXPathRoot(ctxt);
12689             return (0);
12690         case XPATH_OP_NODE:
12691             if (op->ch1 != -1)
12692                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12693             CHECK_ERROR0;
12694             if (op->ch2 != -1)
12695                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12696             CHECK_ERROR0;
12697             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12698                 ctxt->context->node));
12699             return (total);
12700         case XPATH_OP_RESET:
12701             if (op->ch1 != -1)
12702                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12703             CHECK_ERROR0;
12704             if (op->ch2 != -1)
12705                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12706             CHECK_ERROR0;
12707             ctxt->context->node = NULL;
12708             return (total);
12709         case XPATH_OP_COLLECT:{
12710                 if (op->ch1 == -1)
12711                     return (total);
12712
12713                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12714                 CHECK_ERROR0;
12715
12716                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12717                 return (total);
12718             }
12719         case XPATH_OP_VALUE:
12720             valuePush(ctxt,
12721                       xmlXPathCacheObjectCopy(ctxt->context,
12722                         (xmlXPathObjectPtr) op->value4));
12723             return (0);
12724         case XPATH_OP_SORT:
12725             if (op->ch1 != -1)
12726                 total +=
12727                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12728                                             first);
12729             CHECK_ERROR0;
12730             if ((ctxt->value != NULL)
12731                 && (ctxt->value->type == XPATH_NODESET)
12732                 && (ctxt->value->nodesetval != NULL)
12733                 && (ctxt->value->nodesetval->nodeNr > 1))
12734                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12735             return (total);
12736 #ifdef XP_OPTIMIZED_FILTER_FIRST
12737         case XPATH_OP_FILTER:
12738                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12739             return (total);
12740 #endif
12741         default:
12742             return (xmlXPathCompOpEval(ctxt, op));
12743     }
12744 }
12745
12746 /**
12747  * xmlXPathCompOpEvalLast:
12748  * @ctxt:  the XPath parser context with the compiled expression
12749  * @op:  an XPath compiled operation
12750  * @last:  the last elem found so far
12751  *
12752  * Evaluate the Precompiled XPath operation searching only the last
12753  * element in document order
12754  *
12755  * Returns the number of nodes traversed
12756  */
12757 static int
12758 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12759                        xmlNodePtr * last)
12760 {
12761     int total = 0, cur;
12762     xmlXPathCompExprPtr comp;
12763     xmlXPathObjectPtr arg1, arg2;
12764     xmlNodePtr bak;
12765     xmlDocPtr bakd;
12766     int pp;
12767     int cs;
12768
12769     CHECK_ERROR0;
12770     comp = ctxt->comp;
12771     switch (op->op) {
12772         case XPATH_OP_END:
12773             return (0);
12774         case XPATH_OP_UNION:
12775             bakd = ctxt->context->doc;
12776             bak = ctxt->context->node;
12777             pp = ctxt->context->proximityPosition;
12778             cs = ctxt->context->contextSize;
12779             total =
12780                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12781             CHECK_ERROR0;
12782             if ((ctxt->value != NULL)
12783                 && (ctxt->value->type == XPATH_NODESET)
12784                 && (ctxt->value->nodesetval != NULL)
12785                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12786                 /*
12787                  * limit tree traversing to first node in the result
12788                  */
12789                 if (ctxt->value->nodesetval->nodeNr > 1)
12790                     xmlXPathNodeSetSort(ctxt->value->nodesetval);
12791                 *last =
12792                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12793                                                      nodesetval->nodeNr -
12794                                                      1];
12795             }
12796             ctxt->context->doc = bakd;
12797             ctxt->context->node = bak;
12798             ctxt->context->proximityPosition = pp;
12799             ctxt->context->contextSize = cs;
12800             cur =
12801                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12802             CHECK_ERROR0;
12803             if ((ctxt->value != NULL)
12804                 && (ctxt->value->type == XPATH_NODESET)
12805                 && (ctxt->value->nodesetval != NULL)
12806                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12807             }
12808             CHECK_TYPE0(XPATH_NODESET);
12809             arg2 = valuePop(ctxt);
12810
12811             CHECK_TYPE0(XPATH_NODESET);
12812             arg1 = valuePop(ctxt);
12813
12814             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12815                                                     arg2->nodesetval);
12816             valuePush(ctxt, arg1);
12817             xmlXPathReleaseObject(ctxt->context, arg2);
12818             /* optimizer */
12819             if (total > cur)
12820                 xmlXPathCompSwap(op);
12821             return (total + cur);
12822         case XPATH_OP_ROOT:
12823             xmlXPathRoot(ctxt);
12824             return (0);
12825         case XPATH_OP_NODE:
12826             if (op->ch1 != -1)
12827                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12828             CHECK_ERROR0;
12829             if (op->ch2 != -1)
12830                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12831             CHECK_ERROR0;
12832             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12833                 ctxt->context->node));
12834             return (total);
12835         case XPATH_OP_RESET:
12836             if (op->ch1 != -1)
12837                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12838             CHECK_ERROR0;
12839             if (op->ch2 != -1)
12840                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12841             CHECK_ERROR0;
12842             ctxt->context->node = NULL;
12843             return (total);
12844         case XPATH_OP_COLLECT:{
12845                 if (op->ch1 == -1)
12846                     return (0);
12847
12848                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12849                 CHECK_ERROR0;
12850
12851                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12852                 return (total);
12853             }
12854         case XPATH_OP_VALUE:
12855             valuePush(ctxt,
12856                       xmlXPathCacheObjectCopy(ctxt->context,
12857                         (xmlXPathObjectPtr) op->value4));
12858             return (0);
12859         case XPATH_OP_SORT:
12860             if (op->ch1 != -1)
12861                 total +=
12862                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12863                                            last);
12864             CHECK_ERROR0;
12865             if ((ctxt->value != NULL)
12866                 && (ctxt->value->type == XPATH_NODESET)
12867                 && (ctxt->value->nodesetval != NULL)
12868                 && (ctxt->value->nodesetval->nodeNr > 1))
12869                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12870             return (total);
12871         default:
12872             return (xmlXPathCompOpEval(ctxt, op));
12873     }
12874 }
12875
12876 #ifdef XP_OPTIMIZED_FILTER_FIRST
12877 static int
12878 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12879                               xmlXPathStepOpPtr op, xmlNodePtr * first)
12880 {
12881     int total = 0;
12882     xmlXPathCompExprPtr comp;
12883     xmlXPathObjectPtr res;
12884     xmlXPathObjectPtr obj;
12885     xmlNodeSetPtr oldset;
12886     xmlNodePtr oldnode;
12887     xmlDocPtr oldDoc;
12888     int i;
12889
12890     CHECK_ERROR0;
12891     comp = ctxt->comp;
12892     /*
12893     * Optimization for ()[last()] selection i.e. the last elem
12894     */
12895     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12896         (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12897         (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12898         int f = comp->steps[op->ch2].ch1;
12899
12900         if ((f != -1) &&
12901             (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12902             (comp->steps[f].value5 == NULL) &&
12903             (comp->steps[f].value == 0) &&
12904             (comp->steps[f].value4 != NULL) &&
12905             (xmlStrEqual
12906             (comp->steps[f].value4, BAD_CAST "last"))) {
12907             xmlNodePtr last = NULL;
12908
12909             total +=
12910                 xmlXPathCompOpEvalLast(ctxt,
12911                     &comp->steps[op->ch1],
12912                     &last);
12913             CHECK_ERROR0;
12914             /*
12915             * The nodeset should be in document order,
12916             * Keep only the last value
12917             */
12918             if ((ctxt->value != NULL) &&
12919                 (ctxt->value->type == XPATH_NODESET) &&
12920                 (ctxt->value->nodesetval != NULL) &&
12921                 (ctxt->value->nodesetval->nodeTab != NULL) &&
12922                 (ctxt->value->nodesetval->nodeNr > 1)) {
12923                 ctxt->value->nodesetval->nodeTab[0] =
12924                     ctxt->value->nodesetval->nodeTab[ctxt->
12925                     value->
12926                     nodesetval->
12927                     nodeNr -
12928                     1];
12929                 ctxt->value->nodesetval->nodeNr = 1;
12930                 *first = *(ctxt->value->nodesetval->nodeTab);
12931             }
12932             return (total);
12933         }
12934     }
12935
12936     if (op->ch1 != -1)
12937         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12938     CHECK_ERROR0;
12939     if (op->ch2 == -1)
12940         return (total);
12941     if (ctxt->value == NULL)
12942         return (total);
12943
12944 #ifdef LIBXML_XPTR_ENABLED
12945     oldnode = ctxt->context->node;
12946     /*
12947     * Hum are we filtering the result of an XPointer expression
12948     */
12949     if (ctxt->value->type == XPATH_LOCATIONSET) {
12950         xmlXPathObjectPtr tmp = NULL;
12951         xmlLocationSetPtr newlocset = NULL;
12952         xmlLocationSetPtr oldlocset;
12953
12954         /*
12955         * Extract the old locset, and then evaluate the result of the
12956         * expression for all the element in the locset. use it to grow
12957         * up a new locset.
12958         */
12959         CHECK_TYPE0(XPATH_LOCATIONSET);
12960         obj = valuePop(ctxt);
12961         oldlocset = obj->user;
12962         ctxt->context->node = NULL;
12963
12964         if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12965             ctxt->context->contextSize = 0;
12966             ctxt->context->proximityPosition = 0;
12967             if (op->ch2 != -1)
12968                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12969             res = valuePop(ctxt);
12970             if (res != NULL) {
12971                 xmlXPathReleaseObject(ctxt->context, res);
12972             }
12973             valuePush(ctxt, obj);
12974             CHECK_ERROR0;
12975             return (total);
12976         }
12977         newlocset = xmlXPtrLocationSetCreate(NULL);
12978
12979         for (i = 0; i < oldlocset->locNr; i++) {
12980             /*
12981             * Run the evaluation with a node list made of a
12982             * single item in the nodelocset.
12983             */
12984             ctxt->context->node = oldlocset->locTab[i]->user;
12985             ctxt->context->contextSize = oldlocset->locNr;
12986             ctxt->context->proximityPosition = i + 1;
12987             if (tmp == NULL) {
12988                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12989                     ctxt->context->node);
12990             } else {
12991                 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12992                     ctxt->context->node);
12993             }
12994             valuePush(ctxt, tmp);
12995             if (op->ch2 != -1)
12996                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12997             if (ctxt->error != XPATH_EXPRESSION_OK) {
12998                 xmlXPathFreeObject(obj);
12999                 return(0);
13000             }
13001             /*
13002             * The result of the evaluation need to be tested to
13003             * decided whether the filter succeeded or not
13004             */
13005             res = valuePop(ctxt);
13006             if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13007                 xmlXPtrLocationSetAdd(newlocset,
13008                     xmlXPathCacheObjectCopy(ctxt->context,
13009                         oldlocset->locTab[i]));
13010             }
13011             /*
13012             * Cleanup
13013             */
13014             if (res != NULL) {
13015                 xmlXPathReleaseObject(ctxt->context, res);
13016             }
13017             if (ctxt->value == tmp) {
13018                 valuePop(ctxt);
13019                 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13020                 /*
13021                 * REVISIT TODO: Don't create a temporary nodeset
13022                 * for everly iteration.
13023                 */
13024                 /* OLD: xmlXPathFreeObject(res); */
13025             } else
13026                 tmp = NULL;
13027             ctxt->context->node = NULL;
13028             /*
13029             * Only put the first node in the result, then leave.
13030             */
13031             if (newlocset->locNr > 0) {
13032                 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13033                 break;
13034             }
13035         }
13036         if (tmp != NULL) {
13037             xmlXPathReleaseObject(ctxt->context, tmp);
13038         }
13039         /*
13040         * The result is used as the new evaluation locset.
13041         */
13042         xmlXPathReleaseObject(ctxt->context, obj);
13043         ctxt->context->node = NULL;
13044         ctxt->context->contextSize = -1;
13045         ctxt->context->proximityPosition = -1;
13046         valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13047         ctxt->context->node = oldnode;
13048         return (total);
13049     }
13050 #endif /* LIBXML_XPTR_ENABLED */
13051
13052     /*
13053     * Extract the old set, and then evaluate the result of the
13054     * expression for all the element in the set. use it to grow
13055     * up a new set.
13056     */
13057     CHECK_TYPE0(XPATH_NODESET);
13058     obj = valuePop(ctxt);
13059     oldset = obj->nodesetval;
13060
13061     oldnode = ctxt->context->node;
13062     oldDoc = ctxt->context->doc;
13063     ctxt->context->node = NULL;
13064
13065     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13066         ctxt->context->contextSize = 0;
13067         ctxt->context->proximityPosition = 0;
13068         /* QUESTION TODO: Why was this code commented out?
13069             if (op->ch2 != -1)
13070                 total +=
13071                     xmlXPathCompOpEval(ctxt,
13072                         &comp->steps[op->ch2]);
13073             CHECK_ERROR0;
13074             res = valuePop(ctxt);
13075             if (res != NULL)
13076                 xmlXPathFreeObject(res);
13077         */
13078         valuePush(ctxt, obj);
13079         ctxt->context->node = oldnode;
13080         CHECK_ERROR0;
13081     } else {
13082         xmlNodeSetPtr newset;
13083         xmlXPathObjectPtr tmp = NULL;
13084         /*
13085         * Initialize the new set.
13086         * Also set the xpath document in case things like
13087         * key() evaluation are attempted on the predicate
13088         */
13089         newset = xmlXPathNodeSetCreate(NULL);
13090         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13091
13092         for (i = 0; i < oldset->nodeNr; i++) {
13093             /*
13094             * Run the evaluation with a node list made of
13095             * a single item in the nodeset.
13096             */
13097             ctxt->context->node = oldset->nodeTab[i];
13098             if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13099                 (oldset->nodeTab[i]->doc != NULL))
13100                 ctxt->context->doc = oldset->nodeTab[i]->doc;
13101             if (tmp == NULL) {
13102                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13103                     ctxt->context->node);
13104             } else {
13105                 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13106                     ctxt->context->node);
13107             }
13108             valuePush(ctxt, tmp);
13109             ctxt->context->contextSize = oldset->nodeNr;
13110             ctxt->context->proximityPosition = i + 1;
13111             if (op->ch2 != -1)
13112                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13113             if (ctxt->error != XPATH_EXPRESSION_OK) {
13114                 xmlXPathFreeNodeSet(newset);
13115                 xmlXPathFreeObject(obj);
13116                 return(0);
13117             }
13118             /*
13119             * The result of the evaluation needs to be tested to
13120             * decide whether the filter succeeded or not
13121             */
13122             res = valuePop(ctxt);
13123             if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13124                 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13125             }
13126             /*
13127             * Cleanup
13128             */
13129             if (res != NULL) {
13130                 xmlXPathReleaseObject(ctxt->context, res);
13131             }
13132             if (ctxt->value == tmp) {
13133                 valuePop(ctxt);
13134                 /*
13135                 * Don't free the temporary nodeset
13136                 * in order to avoid massive recreation inside this
13137                 * loop.
13138                 */
13139                 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13140             } else
13141                 tmp = NULL;
13142             ctxt->context->node = NULL;
13143             /*
13144             * Only put the first node in the result, then leave.
13145             */
13146             if (newset->nodeNr > 0) {
13147                 *first = *(newset->nodeTab);
13148                 break;
13149             }
13150         }
13151         if (tmp != NULL) {
13152             xmlXPathReleaseObject(ctxt->context, tmp);
13153         }
13154         /*
13155         * The result is used as the new evaluation set.
13156         */
13157         xmlXPathReleaseObject(ctxt->context, obj);
13158         ctxt->context->node = NULL;
13159         ctxt->context->contextSize = -1;
13160         ctxt->context->proximityPosition = -1;
13161         /* may want to move this past the '}' later */
13162         ctxt->context->doc = oldDoc;
13163         valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13164     }
13165     ctxt->context->node = oldnode;
13166     return(total);
13167 }
13168 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13169
13170 /**
13171  * xmlXPathCompOpEval:
13172  * @ctxt:  the XPath parser context with the compiled expression
13173  * @op:  an XPath compiled operation
13174  *
13175  * Evaluate the Precompiled XPath operation
13176  * Returns the number of nodes traversed
13177  */
13178 static int
13179 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13180 {
13181     int total = 0;
13182     int equal, ret;
13183     xmlXPathCompExprPtr comp;
13184     xmlXPathObjectPtr arg1, arg2;
13185     xmlNodePtr bak;
13186     xmlDocPtr bakd;
13187     int pp;
13188     int cs;
13189
13190     CHECK_ERROR0;
13191     comp = ctxt->comp;
13192     switch (op->op) {
13193         case XPATH_OP_END:
13194             return (0);
13195         case XPATH_OP_AND:
13196             bakd = ctxt->context->doc;
13197             bak = ctxt->context->node;
13198             pp = ctxt->context->proximityPosition;
13199             cs = ctxt->context->contextSize;
13200             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13201             CHECK_ERROR0;
13202             xmlXPathBooleanFunction(ctxt, 1);
13203             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13204                 return (total);
13205             arg2 = valuePop(ctxt);
13206             ctxt->context->doc = bakd;
13207             ctxt->context->node = bak;
13208             ctxt->context->proximityPosition = pp;
13209             ctxt->context->contextSize = cs;
13210             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13211             if (ctxt->error) {
13212                 xmlXPathFreeObject(arg2);
13213                 return(0);
13214             }
13215             xmlXPathBooleanFunction(ctxt, 1);
13216             arg1 = valuePop(ctxt);
13217             arg1->boolval &= arg2->boolval;
13218             valuePush(ctxt, arg1);
13219             xmlXPathReleaseObject(ctxt->context, arg2);
13220             return (total);
13221         case XPATH_OP_OR:
13222             bakd = ctxt->context->doc;
13223             bak = ctxt->context->node;
13224             pp = ctxt->context->proximityPosition;
13225             cs = ctxt->context->contextSize;
13226             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13227             CHECK_ERROR0;
13228             xmlXPathBooleanFunction(ctxt, 1);
13229             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13230                 return (total);
13231             arg2 = valuePop(ctxt);
13232             ctxt->context->doc = bakd;
13233             ctxt->context->node = bak;
13234             ctxt->context->proximityPosition = pp;
13235             ctxt->context->contextSize = cs;
13236             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13237             if (ctxt->error) {
13238                 xmlXPathFreeObject(arg2);
13239                 return(0);
13240             }
13241             xmlXPathBooleanFunction(ctxt, 1);
13242             arg1 = valuePop(ctxt);
13243             arg1->boolval |= arg2->boolval;
13244             valuePush(ctxt, arg1);
13245             xmlXPathReleaseObject(ctxt->context, arg2);
13246             return (total);
13247         case XPATH_OP_EQUAL:
13248             bakd = ctxt->context->doc;
13249             bak = ctxt->context->node;
13250             pp = ctxt->context->proximityPosition;
13251             cs = ctxt->context->contextSize;
13252             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13253             CHECK_ERROR0;
13254             ctxt->context->doc = bakd;
13255             ctxt->context->node = bak;
13256             ctxt->context->proximityPosition = pp;
13257             ctxt->context->contextSize = cs;
13258             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13259             CHECK_ERROR0;
13260             if (op->value)
13261                 equal = xmlXPathEqualValues(ctxt);
13262             else
13263                 equal = xmlXPathNotEqualValues(ctxt);
13264             valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13265             return (total);
13266         case XPATH_OP_CMP:
13267             bakd = ctxt->context->doc;
13268             bak = ctxt->context->node;
13269             pp = ctxt->context->proximityPosition;
13270             cs = ctxt->context->contextSize;
13271             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13272             CHECK_ERROR0;
13273             ctxt->context->doc = bakd;
13274             ctxt->context->node = bak;
13275             ctxt->context->proximityPosition = pp;
13276             ctxt->context->contextSize = cs;
13277             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13278             CHECK_ERROR0;
13279             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13280             valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13281             return (total);
13282         case XPATH_OP_PLUS:
13283             bakd = ctxt->context->doc;
13284             bak = ctxt->context->node;
13285             pp = ctxt->context->proximityPosition;
13286             cs = ctxt->context->contextSize;
13287             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13288             CHECK_ERROR0;
13289             if (op->ch2 != -1) {
13290                 ctxt->context->doc = bakd;
13291                 ctxt->context->node = bak;
13292                 ctxt->context->proximityPosition = pp;
13293                 ctxt->context->contextSize = cs;
13294                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13295             }
13296             CHECK_ERROR0;
13297             if (op->value == 0)
13298                 xmlXPathSubValues(ctxt);
13299             else if (op->value == 1)
13300                 xmlXPathAddValues(ctxt);
13301             else if (op->value == 2)
13302                 xmlXPathValueFlipSign(ctxt);
13303             else if (op->value == 3) {
13304                 CAST_TO_NUMBER;
13305                 CHECK_TYPE0(XPATH_NUMBER);
13306             }
13307             return (total);
13308         case XPATH_OP_MULT:
13309             bakd = ctxt->context->doc;
13310             bak = ctxt->context->node;
13311             pp = ctxt->context->proximityPosition;
13312             cs = ctxt->context->contextSize;
13313             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13314             CHECK_ERROR0;
13315             ctxt->context->doc = bakd;
13316             ctxt->context->node = bak;
13317             ctxt->context->proximityPosition = pp;
13318             ctxt->context->contextSize = cs;
13319             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13320             CHECK_ERROR0;
13321             if (op->value == 0)
13322                 xmlXPathMultValues(ctxt);
13323             else if (op->value == 1)
13324                 xmlXPathDivValues(ctxt);
13325             else if (op->value == 2)
13326                 xmlXPathModValues(ctxt);
13327             return (total);
13328         case XPATH_OP_UNION:
13329             bakd = ctxt->context->doc;
13330             bak = ctxt->context->node;
13331             pp = ctxt->context->proximityPosition;
13332             cs = ctxt->context->contextSize;
13333             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13334             CHECK_ERROR0;
13335             ctxt->context->doc = bakd;
13336             ctxt->context->node = bak;
13337             ctxt->context->proximityPosition = pp;
13338             ctxt->context->contextSize = cs;
13339             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13340             CHECK_ERROR0;
13341             CHECK_TYPE0(XPATH_NODESET);
13342             arg2 = valuePop(ctxt);
13343
13344             CHECK_TYPE0(XPATH_NODESET);
13345             arg1 = valuePop(ctxt);
13346
13347             if ((arg1->nodesetval == NULL) ||
13348                 ((arg2->nodesetval != NULL) &&
13349                  (arg2->nodesetval->nodeNr != 0)))
13350             {
13351                 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13352                                                         arg2->nodesetval);
13353             }
13354
13355             valuePush(ctxt, arg1);
13356             xmlXPathReleaseObject(ctxt->context, arg2);
13357             return (total);
13358         case XPATH_OP_ROOT:
13359             xmlXPathRoot(ctxt);
13360             return (total);
13361         case XPATH_OP_NODE:
13362             if (op->ch1 != -1)
13363                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13364             CHECK_ERROR0;
13365             if (op->ch2 != -1)
13366                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13367             CHECK_ERROR0;
13368             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13369                 ctxt->context->node));
13370             return (total);
13371         case XPATH_OP_RESET:
13372             if (op->ch1 != -1)
13373                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13374             CHECK_ERROR0;
13375             if (op->ch2 != -1)
13376                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13377             CHECK_ERROR0;
13378             ctxt->context->node = NULL;
13379             return (total);
13380         case XPATH_OP_COLLECT:{
13381                 if (op->ch1 == -1)
13382                     return (total);
13383
13384                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13385                 CHECK_ERROR0;
13386
13387                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13388                 return (total);
13389             }
13390         case XPATH_OP_VALUE:
13391             valuePush(ctxt,
13392                       xmlXPathCacheObjectCopy(ctxt->context,
13393                         (xmlXPathObjectPtr) op->value4));
13394             return (total);
13395         case XPATH_OP_VARIABLE:{
13396                 xmlXPathObjectPtr val;
13397
13398                 if (op->ch1 != -1)
13399                     total +=
13400                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13401                 if (op->value5 == NULL) {
13402                     val = xmlXPathVariableLookup(ctxt->context, op->value4);
13403                     if (val == NULL) {
13404                         ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13405                         return(0);
13406                     }
13407                     valuePush(ctxt, val);
13408                 } else {
13409                     const xmlChar *URI;
13410
13411                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13412                     if (URI == NULL) {
13413                         xmlGenericError(xmlGenericErrorContext,
13414             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13415                                     (char *) op->value4, (char *)op->value5);
13416                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13417                         return (total);
13418                     }
13419                     val = xmlXPathVariableLookupNS(ctxt->context,
13420                                                        op->value4, URI);
13421                     if (val == NULL) {
13422                         ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13423                         return(0);
13424                     }
13425                     valuePush(ctxt, val);
13426                 }
13427                 return (total);
13428             }
13429         case XPATH_OP_FUNCTION:{
13430                 xmlXPathFunction func;
13431                 const xmlChar *oldFunc, *oldFuncURI;
13432                 int i;
13433                 int frame;
13434
13435                 frame = xmlXPathSetFrame(ctxt);
13436                 if (op->ch1 != -1)
13437                     total +=
13438                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13439                 if (ctxt->valueNr < op->value) {
13440                     xmlGenericError(xmlGenericErrorContext,
13441                             "xmlXPathCompOpEval: parameter error\n");
13442                     ctxt->error = XPATH_INVALID_OPERAND;
13443                     xmlXPathPopFrame(ctxt, frame);
13444                     return (total);
13445                 }
13446                 for (i = 0; i < op->value; i++) {
13447                     if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13448                         xmlGenericError(xmlGenericErrorContext,
13449                                 "xmlXPathCompOpEval: parameter error\n");
13450                         ctxt->error = XPATH_INVALID_OPERAND;
13451                         xmlXPathPopFrame(ctxt, frame);
13452                         return (total);
13453                     }
13454                 }
13455                 if (op->cache != NULL)
13456                     XML_CAST_FPTR(func) = op->cache;
13457                 else {
13458                     const xmlChar *URI = NULL;
13459
13460                     if (op->value5 == NULL)
13461                         func =
13462                             xmlXPathFunctionLookup(ctxt->context,
13463                                                    op->value4);
13464                     else {
13465                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13466                         if (URI == NULL) {
13467                             xmlGenericError(xmlGenericErrorContext,
13468             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13469                                     (char *)op->value4, (char *)op->value5);
13470                             xmlXPathPopFrame(ctxt, frame);
13471                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13472                             return (total);
13473                         }
13474                         func = xmlXPathFunctionLookupNS(ctxt->context,
13475                                                         op->value4, URI);
13476                     }
13477                     if (func == NULL) {
13478                         xmlGenericError(xmlGenericErrorContext,
13479                                 "xmlXPathCompOpEval: function %s not found\n",
13480                                         (char *)op->value4);
13481                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13482                     }
13483                     op->cache = XML_CAST_FPTR(func);
13484                     op->cacheURI = (void *) URI;
13485                 }
13486                 oldFunc = ctxt->context->function;
13487                 oldFuncURI = ctxt->context->functionURI;
13488                 ctxt->context->function = op->value4;
13489                 ctxt->context->functionURI = op->cacheURI;
13490                 func(ctxt, op->value);
13491                 ctxt->context->function = oldFunc;
13492                 ctxt->context->functionURI = oldFuncURI;
13493                 xmlXPathPopFrame(ctxt, frame);
13494                 return (total);
13495             }
13496         case XPATH_OP_ARG:
13497             bakd = ctxt->context->doc;
13498             bak = ctxt->context->node;
13499             pp = ctxt->context->proximityPosition;
13500             cs = ctxt->context->contextSize;
13501             if (op->ch1 != -1)
13502                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13503             ctxt->context->contextSize = cs;
13504             ctxt->context->proximityPosition = pp;
13505             ctxt->context->node = bak;
13506             ctxt->context->doc = bakd;
13507             CHECK_ERROR0;
13508             if (op->ch2 != -1) {
13509                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13510                 ctxt->context->doc = bakd;
13511                 ctxt->context->node = bak;
13512                 CHECK_ERROR0;
13513             }
13514             return (total);
13515         case XPATH_OP_PREDICATE:
13516         case XPATH_OP_FILTER:{
13517                 xmlXPathObjectPtr res;
13518                 xmlXPathObjectPtr obj, tmp;
13519                 xmlNodeSetPtr newset = NULL;
13520                 xmlNodeSetPtr oldset;
13521                 xmlNodePtr oldnode;
13522                 xmlDocPtr oldDoc;
13523                 int i;
13524
13525                 /*
13526                  * Optimization for ()[1] selection i.e. the first elem
13527                  */
13528                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13529 #ifdef XP_OPTIMIZED_FILTER_FIRST
13530                     /*
13531                     * FILTER TODO: Can we assume that the inner processing
13532                     *  will result in an ordered list if we have an
13533                     *  XPATH_OP_FILTER?
13534                     *  What about an additional field or flag on
13535                     *  xmlXPathObject like @sorted ? This way we wouln'd need
13536                     *  to assume anything, so it would be more robust and
13537                     *  easier to optimize.
13538                     */
13539                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13540                      (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13541 #else
13542                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13543 #endif
13544                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13545                     xmlXPathObjectPtr val;
13546
13547                     val = comp->steps[op->ch2].value4;
13548                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13549                         (val->floatval == 1.0)) {
13550                         xmlNodePtr first = NULL;
13551
13552                         total +=
13553                             xmlXPathCompOpEvalFirst(ctxt,
13554                                                     &comp->steps[op->ch1],
13555                                                     &first);
13556                         CHECK_ERROR0;
13557                         /*
13558                          * The nodeset should be in document order,
13559                          * Keep only the first value
13560                          */
13561                         if ((ctxt->value != NULL) &&
13562                             (ctxt->value->type == XPATH_NODESET) &&
13563                             (ctxt->value->nodesetval != NULL) &&
13564                             (ctxt->value->nodesetval->nodeNr > 1))
13565                             ctxt->value->nodesetval->nodeNr = 1;
13566                         return (total);
13567                     }
13568                 }
13569                 /*
13570                  * Optimization for ()[last()] selection i.e. the last elem
13571                  */
13572                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13573                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13574                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13575                     int f = comp->steps[op->ch2].ch1;
13576
13577                     if ((f != -1) &&
13578                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13579                         (comp->steps[f].value5 == NULL) &&
13580                         (comp->steps[f].value == 0) &&
13581                         (comp->steps[f].value4 != NULL) &&
13582                         (xmlStrEqual
13583                          (comp->steps[f].value4, BAD_CAST "last"))) {
13584                         xmlNodePtr last = NULL;
13585
13586                         total +=
13587                             xmlXPathCompOpEvalLast(ctxt,
13588                                                    &comp->steps[op->ch1],
13589                                                    &last);
13590                         CHECK_ERROR0;
13591                         /*
13592                          * The nodeset should be in document order,
13593                          * Keep only the last value
13594                          */
13595                         if ((ctxt->value != NULL) &&
13596                             (ctxt->value->type == XPATH_NODESET) &&
13597                             (ctxt->value->nodesetval != NULL) &&
13598                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13599                             (ctxt->value->nodesetval->nodeNr > 1)) {
13600                             ctxt->value->nodesetval->nodeTab[0] =
13601                                 ctxt->value->nodesetval->nodeTab[ctxt->
13602                                                                  value->
13603                                                                  nodesetval->
13604                                                                  nodeNr -
13605                                                                  1];
13606                             ctxt->value->nodesetval->nodeNr = 1;
13607                         }
13608                         return (total);
13609                     }
13610                 }
13611                 /*
13612                 * Process inner predicates first.
13613                 * Example "index[parent::book][1]":
13614                 * ...
13615                 *   PREDICATE   <-- we are here "[1]"
13616                 *     PREDICATE <-- process "[parent::book]" first
13617                 *       SORT
13618                 *         COLLECT  'parent' 'name' 'node' book
13619                 *           NODE
13620                 *     ELEM Object is a number : 1
13621                 */
13622                 if (op->ch1 != -1)
13623                     total +=
13624                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13625                 CHECK_ERROR0;
13626                 if (op->ch2 == -1)
13627                     return (total);
13628                 if (ctxt->value == NULL)
13629                     return (total);
13630
13631                 oldnode = ctxt->context->node;
13632
13633 #ifdef LIBXML_XPTR_ENABLED
13634                 /*
13635                  * Hum are we filtering the result of an XPointer expression
13636                  */
13637                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13638                     xmlLocationSetPtr newlocset = NULL;
13639                     xmlLocationSetPtr oldlocset;
13640
13641                     /*
13642                      * Extract the old locset, and then evaluate the result of the
13643                      * expression for all the element in the locset. use it to grow
13644                      * up a new locset.
13645                      */
13646                     CHECK_TYPE0(XPATH_LOCATIONSET);
13647                     obj = valuePop(ctxt);
13648                     oldlocset = obj->user;
13649                     ctxt->context->node = NULL;
13650
13651                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13652                         ctxt->context->contextSize = 0;
13653                         ctxt->context->proximityPosition = 0;
13654                         if (op->ch2 != -1)
13655                             total +=
13656                                 xmlXPathCompOpEval(ctxt,
13657                                                    &comp->steps[op->ch2]);
13658                         res = valuePop(ctxt);
13659                         if (res != NULL) {
13660                             xmlXPathReleaseObject(ctxt->context, res);
13661                         }
13662                         valuePush(ctxt, obj);
13663                         CHECK_ERROR0;
13664                         return (total);
13665                     }
13666                     newlocset = xmlXPtrLocationSetCreate(NULL);
13667
13668                     for (i = 0; i < oldlocset->locNr; i++) {
13669                         /*
13670                          * Run the evaluation with a node list made of a
13671                          * single item in the nodelocset.
13672                          */
13673                         ctxt->context->node = oldlocset->locTab[i]->user;
13674                         ctxt->context->contextSize = oldlocset->locNr;
13675                         ctxt->context->proximityPosition = i + 1;
13676                         tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13677                             ctxt->context->node);
13678                         valuePush(ctxt, tmp);
13679
13680                         if (op->ch2 != -1)
13681                             total +=
13682                                 xmlXPathCompOpEval(ctxt,
13683                                                    &comp->steps[op->ch2]);
13684                         if (ctxt->error != XPATH_EXPRESSION_OK) {
13685                             xmlXPathFreeObject(obj);
13686                             return(0);
13687                         }
13688
13689                         /*
13690                          * The result of the evaluation need to be tested to
13691                          * decided whether the filter succeeded or not
13692                          */
13693                         res = valuePop(ctxt);
13694                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13695                             xmlXPtrLocationSetAdd(newlocset,
13696                                                   xmlXPathObjectCopy
13697                                                   (oldlocset->locTab[i]));
13698                         }
13699
13700                         /*
13701                          * Cleanup
13702                          */
13703                         if (res != NULL) {
13704                             xmlXPathReleaseObject(ctxt->context, res);
13705                         }
13706                         if (ctxt->value == tmp) {
13707                             res = valuePop(ctxt);
13708                             xmlXPathReleaseObject(ctxt->context, res);
13709                         }
13710
13711                         ctxt->context->node = NULL;
13712                     }
13713
13714                     /*
13715                      * The result is used as the new evaluation locset.
13716                      */
13717                     xmlXPathReleaseObject(ctxt->context, obj);
13718                     ctxt->context->node = NULL;
13719                     ctxt->context->contextSize = -1;
13720                     ctxt->context->proximityPosition = -1;
13721                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13722                     ctxt->context->node = oldnode;
13723                     return (total);
13724                 }
13725 #endif /* LIBXML_XPTR_ENABLED */
13726
13727                 /*
13728                  * Extract the old set, and then evaluate the result of the
13729                  * expression for all the element in the set. use it to grow
13730                  * up a new set.
13731                  */
13732                 CHECK_TYPE0(XPATH_NODESET);
13733                 obj = valuePop(ctxt);
13734                 oldset = obj->nodesetval;
13735
13736                 oldnode = ctxt->context->node;
13737                 oldDoc = ctxt->context->doc;
13738                 ctxt->context->node = NULL;
13739
13740                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13741                     ctxt->context->contextSize = 0;
13742                     ctxt->context->proximityPosition = 0;
13743 /*
13744                     if (op->ch2 != -1)
13745                         total +=
13746                             xmlXPathCompOpEval(ctxt,
13747                                                &comp->steps[op->ch2]);
13748                     CHECK_ERROR0;
13749                     res = valuePop(ctxt);
13750                     if (res != NULL)
13751                         xmlXPathFreeObject(res);
13752 */
13753                     valuePush(ctxt, obj);
13754                     ctxt->context->node = oldnode;
13755                     CHECK_ERROR0;
13756                 } else {
13757                     tmp = NULL;
13758                     /*
13759                      * Initialize the new set.
13760                      * Also set the xpath document in case things like
13761                      * key() evaluation are attempted on the predicate
13762                      */
13763                     newset = xmlXPathNodeSetCreate(NULL);
13764                     /*
13765                     * SPEC XPath 1.0:
13766                     *  "For each node in the node-set to be filtered, the
13767                     *  PredicateExpr is evaluated with that node as the
13768                     *  context node, with the number of nodes in the
13769                     *  node-set as the context size, and with the proximity
13770                     *  position of the node in the node-set with respect to
13771                     *  the axis as the context position;"
13772                     * @oldset is the node-set" to be filtered.
13773                     *
13774                     * SPEC XPath 1.0:
13775                     *  "only predicates change the context position and
13776                     *  context size (see [2.4 Predicates])."
13777                     * Example:
13778                     *   node-set  context pos
13779                     *    nA         1
13780                     *    nB         2
13781                     *    nC         3
13782                     *   After applying predicate [position() > 1] :
13783                     *   node-set  context pos
13784                     *    nB         1
13785                     *    nC         2
13786                     *
13787                     * removed the first node in the node-set, then
13788                     * the context position of the
13789                     */
13790                     for (i = 0; i < oldset->nodeNr; i++) {
13791                         /*
13792                          * Run the evaluation with a node list made of
13793                          * a single item in the nodeset.
13794                          */
13795                         ctxt->context->node = oldset->nodeTab[i];
13796                         if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13797                             (oldset->nodeTab[i]->doc != NULL))
13798                             ctxt->context->doc = oldset->nodeTab[i]->doc;
13799                         if (tmp == NULL) {
13800                             tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13801                                 ctxt->context->node);
13802                         } else {
13803                             xmlXPathNodeSetAddUnique(tmp->nodesetval,
13804                                 ctxt->context->node);
13805                         }
13806                         valuePush(ctxt, tmp);
13807                         ctxt->context->contextSize = oldset->nodeNr;
13808                         ctxt->context->proximityPosition = i + 1;
13809                         /*
13810                         * Evaluate the predicate against the context node.
13811                         * Can/should we optimize position() predicates
13812                         * here (e.g. "[1]")?
13813                         */
13814                         if (op->ch2 != -1)
13815                             total +=
13816                                 xmlXPathCompOpEval(ctxt,
13817                                                    &comp->steps[op->ch2]);
13818                         if (ctxt->error != XPATH_EXPRESSION_OK) {
13819                             xmlXPathFreeNodeSet(newset);
13820                             xmlXPathFreeObject(obj);
13821                             return(0);
13822                         }
13823
13824                         /*
13825                          * The result of the evaluation needs to be tested to
13826                          * decide whether the filter succeeded or not
13827                          */
13828                         /*
13829                         * OPTIMIZE TODO: Can we use
13830                         * xmlXPathNodeSetAdd*Unique()* instead?
13831                         */
13832                         res = valuePop(ctxt);
13833                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13834                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13835                         }
13836
13837                         /*
13838                          * Cleanup
13839                          */
13840                         if (res != NULL) {
13841                             xmlXPathReleaseObject(ctxt->context, res);
13842                         }
13843                         if (ctxt->value == tmp) {
13844                             valuePop(ctxt);
13845                             xmlXPathNodeSetClear(tmp->nodesetval, 1);
13846                             /*
13847                             * Don't free the temporary nodeset
13848                             * in order to avoid massive recreation inside this
13849                             * loop.
13850                             */
13851                         } else
13852                             tmp = NULL;
13853                         ctxt->context->node = NULL;
13854                     }
13855                     if (tmp != NULL)
13856                         xmlXPathReleaseObject(ctxt->context, tmp);
13857                     /*
13858                      * The result is used as the new evaluation set.
13859                      */
13860                     xmlXPathReleaseObject(ctxt->context, obj);
13861                     ctxt->context->node = NULL;
13862                     ctxt->context->contextSize = -1;
13863                     ctxt->context->proximityPosition = -1;
13864                     /* may want to move this past the '}' later */
13865                     ctxt->context->doc = oldDoc;
13866                     valuePush(ctxt,
13867                         xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13868                 }
13869                 ctxt->context->node = oldnode;
13870                 return (total);
13871             }
13872         case XPATH_OP_SORT:
13873             if (op->ch1 != -1)
13874                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13875             CHECK_ERROR0;
13876             if ((ctxt->value != NULL) &&
13877                 (ctxt->value->type == XPATH_NODESET) &&
13878                 (ctxt->value->nodesetval != NULL) &&
13879                 (ctxt->value->nodesetval->nodeNr > 1))
13880             {
13881                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13882             }
13883             return (total);
13884 #ifdef LIBXML_XPTR_ENABLED
13885         case XPATH_OP_RANGETO:{
13886                 xmlXPathObjectPtr range;
13887                 xmlXPathObjectPtr res, obj;
13888                 xmlXPathObjectPtr tmp;
13889                 xmlLocationSetPtr newlocset = NULL;
13890                     xmlLocationSetPtr oldlocset;
13891                 xmlNodeSetPtr oldset;
13892                 int i, j;
13893
13894                 if (op->ch1 != -1)
13895                     total +=
13896                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13897                 if (op->ch2 == -1)
13898                     return (total);
13899
13900                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13901                     /*
13902                      * Extract the old locset, and then evaluate the result of the
13903                      * expression for all the element in the locset. use it to grow
13904                      * up a new locset.
13905                      */
13906                     CHECK_TYPE0(XPATH_LOCATIONSET);
13907                     obj = valuePop(ctxt);
13908                     oldlocset = obj->user;
13909
13910                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13911                         ctxt->context->node = NULL;
13912                         ctxt->context->contextSize = 0;
13913                         ctxt->context->proximityPosition = 0;
13914                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13915                         res = valuePop(ctxt);
13916                         if (res != NULL) {
13917                             xmlXPathReleaseObject(ctxt->context, res);
13918                         }
13919                         valuePush(ctxt, obj);
13920                         CHECK_ERROR0;
13921                         return (total);
13922                     }
13923                     newlocset = xmlXPtrLocationSetCreate(NULL);
13924
13925                     for (i = 0; i < oldlocset->locNr; i++) {
13926                         /*
13927                          * Run the evaluation with a node list made of a
13928                          * single item in the nodelocset.
13929                          */
13930                         ctxt->context->node = oldlocset->locTab[i]->user;
13931                         ctxt->context->contextSize = oldlocset->locNr;
13932                         ctxt->context->proximityPosition = i + 1;
13933                         tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13934                             ctxt->context->node);
13935                         valuePush(ctxt, tmp);
13936
13937                         if (op->ch2 != -1)
13938                             total +=
13939                                 xmlXPathCompOpEval(ctxt,
13940                                                    &comp->steps[op->ch2]);
13941                         if (ctxt->error != XPATH_EXPRESSION_OK) {
13942                             xmlXPathFreeObject(obj);
13943                             return(0);
13944                         }
13945
13946                         res = valuePop(ctxt);
13947                         if (res->type == XPATH_LOCATIONSET) {
13948                             xmlLocationSetPtr rloc =
13949                                 (xmlLocationSetPtr)res->user;
13950                             for (j=0; j<rloc->locNr; j++) {
13951                                 range = xmlXPtrNewRange(
13952                                   oldlocset->locTab[i]->user,
13953                                   oldlocset->locTab[i]->index,
13954                                   rloc->locTab[j]->user2,
13955                                   rloc->locTab[j]->index2);
13956                                 if (range != NULL) {
13957                                     xmlXPtrLocationSetAdd(newlocset, range);
13958                                 }
13959                             }
13960                         } else {
13961                             range = xmlXPtrNewRangeNodeObject(
13962                                 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13963                             if (range != NULL) {
13964                                 xmlXPtrLocationSetAdd(newlocset,range);
13965                             }
13966                         }
13967
13968                         /*
13969                          * Cleanup
13970                          */
13971                         if (res != NULL) {
13972                             xmlXPathReleaseObject(ctxt->context, res);
13973                         }
13974                         if (ctxt->value == tmp) {
13975                             res = valuePop(ctxt);
13976                             xmlXPathReleaseObject(ctxt->context, res);
13977                         }
13978
13979                         ctxt->context->node = NULL;
13980                     }
13981                 } else {        /* Not a location set */
13982                     CHECK_TYPE0(XPATH_NODESET);
13983                     obj = valuePop(ctxt);
13984                     oldset = obj->nodesetval;
13985                     ctxt->context->node = NULL;
13986
13987                     newlocset = xmlXPtrLocationSetCreate(NULL);
13988
13989                     if (oldset != NULL) {
13990                         for (i = 0; i < oldset->nodeNr; i++) {
13991                             /*
13992                              * Run the evaluation with a node list made of a single item
13993                              * in the nodeset.
13994                              */
13995                             ctxt->context->node = oldset->nodeTab[i];
13996                             /*
13997                             * OPTIMIZE TODO: Avoid recreation for every iteration.
13998                             */
13999                             tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14000                                 ctxt->context->node);
14001                             valuePush(ctxt, tmp);
14002
14003                             if (op->ch2 != -1)
14004                                 total +=
14005                                     xmlXPathCompOpEval(ctxt,
14006                                                    &comp->steps[op->ch2]);
14007                             if (ctxt->error != XPATH_EXPRESSION_OK) {
14008                                 xmlXPathFreeObject(obj);
14009                                 return(0);
14010                             }
14011
14012                             res = valuePop(ctxt);
14013                             range =
14014                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14015                                                       res);
14016                             if (range != NULL) {
14017                                 xmlXPtrLocationSetAdd(newlocset, range);
14018                             }
14019
14020                             /*
14021                              * Cleanup
14022                              */
14023                             if (res != NULL) {
14024                                 xmlXPathReleaseObject(ctxt->context, res);
14025                             }
14026                             if (ctxt->value == tmp) {
14027                                 res = valuePop(ctxt);
14028                                 xmlXPathReleaseObject(ctxt->context, res);
14029                             }
14030
14031                             ctxt->context->node = NULL;
14032                         }
14033                     }
14034                 }
14035
14036                 /*
14037                  * The result is used as the new evaluation set.
14038                  */
14039                 xmlXPathReleaseObject(ctxt->context, obj);
14040                 ctxt->context->node = NULL;
14041                 ctxt->context->contextSize = -1;
14042                 ctxt->context->proximityPosition = -1;
14043                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14044                 return (total);
14045             }
14046 #endif /* LIBXML_XPTR_ENABLED */
14047     }
14048     xmlGenericError(xmlGenericErrorContext,
14049                     "XPath: unknown precompiled operation %d\n", op->op);
14050     ctxt->error = XPATH_INVALID_OPERAND;
14051     return (total);
14052 }
14053
14054 /**
14055  * xmlXPathCompOpEvalToBoolean:
14056  * @ctxt:  the XPath parser context
14057  *
14058  * Evaluates if the expression evaluates to true.
14059  *
14060  * Returns 1 if true, 0 if false and -1 on API or internal errors.
14061  */
14062 static int
14063 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14064                             xmlXPathStepOpPtr op,
14065                             int isPredicate)
14066 {
14067     xmlXPathObjectPtr resObj = NULL;
14068
14069 start:
14070     /* comp = ctxt->comp; */
14071     switch (op->op) {
14072         case XPATH_OP_END:
14073             return (0);
14074         case XPATH_OP_VALUE:
14075             resObj = (xmlXPathObjectPtr) op->value4;
14076             if (isPredicate)
14077                 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14078             return(xmlXPathCastToBoolean(resObj));
14079         case XPATH_OP_SORT:
14080             /*
14081             * We don't need sorting for boolean results. Skip this one.
14082             */
14083             if (op->ch1 != -1) {
14084                 op = &ctxt->comp->steps[op->ch1];
14085                 goto start;
14086             }
14087             return(0);
14088         case XPATH_OP_COLLECT:
14089             if (op->ch1 == -1)
14090                 return(0);
14091
14092             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14093             if (ctxt->error != XPATH_EXPRESSION_OK)
14094                 return(-1);
14095
14096             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14097             if (ctxt->error != XPATH_EXPRESSION_OK)
14098                 return(-1);
14099
14100             resObj = valuePop(ctxt);
14101             if (resObj == NULL)
14102                 return(-1);
14103             break;
14104         default:
14105             /*
14106             * Fallback to call xmlXPathCompOpEval().
14107             */
14108             xmlXPathCompOpEval(ctxt, op);
14109             if (ctxt->error != XPATH_EXPRESSION_OK)
14110                 return(-1);
14111
14112             resObj = valuePop(ctxt);
14113             if (resObj == NULL)
14114                 return(-1);
14115             break;
14116     }
14117
14118     if (resObj) {
14119         int res;
14120
14121         if (resObj->type == XPATH_BOOLEAN) {
14122             res = resObj->boolval;
14123         } else if (isPredicate) {
14124             /*
14125             * For predicates a result of type "number" is handled
14126             * differently:
14127             * SPEC XPath 1.0:
14128             * "If the result is a number, the result will be converted
14129             *  to true if the number is equal to the context position
14130             *  and will be converted to false otherwise;"
14131             */
14132             res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14133         } else {
14134             res = xmlXPathCastToBoolean(resObj);
14135         }
14136         xmlXPathReleaseObject(ctxt->context, resObj);
14137         return(res);
14138     }
14139
14140     return(0);
14141 }
14142
14143 #ifdef XPATH_STREAMING
14144 /**
14145  * xmlXPathRunStreamEval:
14146  * @ctxt:  the XPath parser context with the compiled expression
14147  *
14148  * Evaluate the Precompiled Streamable XPath expression in the given context.
14149  */
14150 static int
14151 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14152                       xmlXPathObjectPtr *resultSeq, int toBool)
14153 {
14154     int max_depth, min_depth;
14155     int from_root;
14156     int ret, depth;
14157     int eval_all_nodes;
14158     xmlNodePtr cur = NULL, limit = NULL;
14159     xmlStreamCtxtPtr patstream = NULL;
14160
14161     int nb_nodes = 0;
14162
14163     if ((ctxt == NULL) || (comp == NULL))
14164         return(-1);
14165     max_depth = xmlPatternMaxDepth(comp);
14166     if (max_depth == -1)
14167         return(-1);
14168     if (max_depth == -2)
14169         max_depth = 10000;
14170     min_depth = xmlPatternMinDepth(comp);
14171     if (min_depth == -1)
14172         return(-1);
14173     from_root = xmlPatternFromRoot(comp);
14174     if (from_root < 0)
14175         return(-1);
14176 #if 0
14177     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14178 #endif
14179
14180     if (! toBool) {
14181         if (resultSeq == NULL)
14182             return(-1);
14183         *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14184         if (*resultSeq == NULL)
14185             return(-1);
14186     }
14187
14188     /*
14189      * handle the special cases of "/" amd "." being matched
14190      */
14191     if (min_depth == 0) {
14192         if (from_root) {
14193             /* Select "/" */
14194             if (toBool)
14195                 return(1);
14196             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14197                 (xmlNodePtr) ctxt->doc);
14198         } else {
14199             /* Select "self::node()" */
14200             if (toBool)
14201                 return(1);
14202             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14203         }
14204     }
14205     if (max_depth == 0) {
14206         return(0);
14207     }
14208
14209     if (from_root) {
14210         cur = (xmlNodePtr)ctxt->doc;
14211     } else if (ctxt->node != NULL) {
14212         switch (ctxt->node->type) {
14213             case XML_ELEMENT_NODE:
14214             case XML_DOCUMENT_NODE:
14215             case XML_DOCUMENT_FRAG_NODE:
14216             case XML_HTML_DOCUMENT_NODE:
14217 #ifdef LIBXML_DOCB_ENABLED
14218             case XML_DOCB_DOCUMENT_NODE:
14219 #endif
14220                 cur = ctxt->node;
14221                 break;
14222             case XML_ATTRIBUTE_NODE:
14223             case XML_TEXT_NODE:
14224             case XML_CDATA_SECTION_NODE:
14225             case XML_ENTITY_REF_NODE:
14226             case XML_ENTITY_NODE:
14227             case XML_PI_NODE:
14228             case XML_COMMENT_NODE:
14229             case XML_NOTATION_NODE:
14230             case XML_DTD_NODE:
14231             case XML_DOCUMENT_TYPE_NODE:
14232             case XML_ELEMENT_DECL:
14233             case XML_ATTRIBUTE_DECL:
14234             case XML_ENTITY_DECL:
14235             case XML_NAMESPACE_DECL:
14236             case XML_XINCLUDE_START:
14237             case XML_XINCLUDE_END:
14238                 break;
14239         }
14240         limit = cur;
14241     }
14242     if (cur == NULL) {
14243         return(0);
14244     }
14245
14246     patstream = xmlPatternGetStreamCtxt(comp);
14247     if (patstream == NULL) {
14248         /*
14249         * QUESTION TODO: Is this an error?
14250         */
14251         return(0);
14252     }
14253
14254     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14255
14256     if (from_root) {
14257         ret = xmlStreamPush(patstream, NULL, NULL);
14258         if (ret < 0) {
14259         } else if (ret == 1) {
14260             if (toBool)
14261                 goto return_1;
14262             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14263         }
14264     }
14265     depth = 0;
14266     goto scan_children;
14267 next_node:
14268     do {
14269         nb_nodes++;
14270
14271         switch (cur->type) {
14272             case XML_ELEMENT_NODE:
14273             case XML_TEXT_NODE:
14274             case XML_CDATA_SECTION_NODE:
14275             case XML_COMMENT_NODE:
14276             case XML_PI_NODE:
14277                 if (cur->type == XML_ELEMENT_NODE) {
14278                     ret = xmlStreamPush(patstream, cur->name,
14279                                 (cur->ns ? cur->ns->href : NULL));
14280                 } else if (eval_all_nodes)
14281                     ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14282                 else
14283                     break;
14284
14285                 if (ret < 0) {
14286                     /* NOP. */
14287                 } else if (ret == 1) {
14288                     if (toBool)
14289                         goto return_1;
14290                     xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14291                 }
14292                 if ((cur->children == NULL) || (depth >= max_depth)) {
14293                     ret = xmlStreamPop(patstream);
14294                     while (cur->next != NULL) {
14295                         cur = cur->next;
14296                         if ((cur->type != XML_ENTITY_DECL) &&
14297                             (cur->type != XML_DTD_NODE))
14298                             goto next_node;
14299                     }
14300                 }
14301             default:
14302                 break;
14303         }
14304
14305 scan_children:
14306         if ((cur->children != NULL) && (depth < max_depth)) {
14307             /*
14308              * Do not descend on entities declarations
14309              */
14310             if (cur->children->type != XML_ENTITY_DECL) {
14311                 cur = cur->children;
14312                 depth++;
14313                 /*
14314                  * Skip DTDs
14315                  */
14316                 if (cur->type != XML_DTD_NODE)
14317                     continue;
14318             }
14319         }
14320
14321         if (cur == limit)
14322             break;
14323
14324         while (cur->next != NULL) {
14325             cur = cur->next;
14326             if ((cur->type != XML_ENTITY_DECL) &&
14327                 (cur->type != XML_DTD_NODE))
14328                 goto next_node;
14329         }
14330
14331         do {
14332             cur = cur->parent;
14333             depth--;
14334             if ((cur == NULL) || (cur == limit))
14335                 goto done;
14336             if (cur->type == XML_ELEMENT_NODE) {
14337                 ret = xmlStreamPop(patstream);
14338             } else if ((eval_all_nodes) &&
14339                 ((cur->type == XML_TEXT_NODE) ||
14340                  (cur->type == XML_CDATA_SECTION_NODE) ||
14341                  (cur->type == XML_COMMENT_NODE) ||
14342                  (cur->type == XML_PI_NODE)))
14343             {
14344                 ret = xmlStreamPop(patstream);
14345             }
14346             if (cur->next != NULL) {
14347                 cur = cur->next;
14348                 break;
14349             }
14350         } while (cur != NULL);
14351
14352     } while ((cur != NULL) && (depth >= 0));
14353
14354 done:
14355
14356 #if 0
14357     printf("stream eval: checked %d nodes selected %d\n",
14358            nb_nodes, retObj->nodesetval->nodeNr);
14359 #endif
14360
14361     if (patstream)
14362         xmlFreeStreamCtxt(patstream);
14363     return(0);
14364
14365 return_1:
14366     if (patstream)
14367         xmlFreeStreamCtxt(patstream);
14368     return(1);
14369 }
14370 #endif /* XPATH_STREAMING */
14371
14372 /**
14373  * xmlXPathRunEval:
14374  * @ctxt:  the XPath parser context with the compiled expression
14375  * @toBool:  evaluate to a boolean result
14376  *
14377  * Evaluate the Precompiled XPath expression in the given context.
14378  */
14379 static int
14380 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14381 {
14382     xmlXPathCompExprPtr comp;
14383
14384     if ((ctxt == NULL) || (ctxt->comp == NULL))
14385         return(-1);
14386
14387     if (ctxt->valueTab == NULL) {
14388         /* Allocate the value stack */
14389         ctxt->valueTab = (xmlXPathObjectPtr *)
14390                          xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14391         if (ctxt->valueTab == NULL) {
14392             xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14393             xmlFree(ctxt);
14394         }
14395         ctxt->valueNr = 0;
14396         ctxt->valueMax = 10;
14397         ctxt->value = NULL;
14398         ctxt->valueFrame = 0;
14399     }
14400 #ifdef XPATH_STREAMING
14401     if (ctxt->comp->stream) {
14402         int res;
14403
14404         if (toBool) {
14405             /*
14406             * Evaluation to boolean result.
14407             */
14408             res = xmlXPathRunStreamEval(ctxt->context,
14409                 ctxt->comp->stream, NULL, 1);
14410             if (res != -1)
14411                 return(res);
14412         } else {
14413             xmlXPathObjectPtr resObj = NULL;
14414
14415             /*
14416             * Evaluation to a sequence.
14417             */
14418             res = xmlXPathRunStreamEval(ctxt->context,
14419                 ctxt->comp->stream, &resObj, 0);
14420
14421             if ((res != -1) && (resObj != NULL)) {
14422                 valuePush(ctxt, resObj);
14423                 return(0);
14424             }
14425             if (resObj != NULL)
14426                 xmlXPathReleaseObject(ctxt->context, resObj);
14427         }
14428         /*
14429         * QUESTION TODO: This falls back to normal XPath evaluation
14430         * if res == -1. Is this intended?
14431         */
14432     }
14433 #endif
14434     comp = ctxt->comp;
14435     if (comp->last < 0) {
14436         xmlGenericError(xmlGenericErrorContext,
14437             "xmlXPathRunEval: last is less than zero\n");
14438         return(-1);
14439     }
14440     if (toBool)
14441         return(xmlXPathCompOpEvalToBoolean(ctxt,
14442             &comp->steps[comp->last], 0));
14443     else
14444         xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14445
14446     return(0);
14447 }
14448
14449 /************************************************************************
14450  *                                                                      *
14451  *                      Public interfaces                               *
14452  *                                                                      *
14453  ************************************************************************/
14454
14455 /**
14456  * xmlXPathEvalPredicate:
14457  * @ctxt:  the XPath context
14458  * @res:  the Predicate Expression evaluation result
14459  *
14460  * Evaluate a predicate result for the current node.
14461  * A PredicateExpr is evaluated by evaluating the Expr and converting
14462  * the result to a boolean. If the result is a number, the result will
14463  * be converted to true if the number is equal to the position of the
14464  * context node in the context node list (as returned by the position
14465  * function) and will be converted to false otherwise; if the result
14466  * is not a number, then the result will be converted as if by a call
14467  * to the boolean function.
14468  *
14469  * Returns 1 if predicate is true, 0 otherwise
14470  */
14471 int
14472 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14473     if ((ctxt == NULL) || (res == NULL)) return(0);
14474     switch (res->type) {
14475         case XPATH_BOOLEAN:
14476             return(res->boolval);
14477         case XPATH_NUMBER:
14478             return(res->floatval == ctxt->proximityPosition);
14479         case XPATH_NODESET:
14480         case XPATH_XSLT_TREE:
14481             if (res->nodesetval == NULL)
14482                 return(0);
14483             return(res->nodesetval->nodeNr != 0);
14484         case XPATH_STRING:
14485             return((res->stringval != NULL) &&
14486                    (xmlStrlen(res->stringval) != 0));
14487         default:
14488             STRANGE
14489     }
14490     return(0);
14491 }
14492
14493 /**
14494  * xmlXPathEvaluatePredicateResult:
14495  * @ctxt:  the XPath Parser context
14496  * @res:  the Predicate Expression evaluation result
14497  *
14498  * Evaluate a predicate result for the current node.
14499  * A PredicateExpr is evaluated by evaluating the Expr and converting
14500  * the result to a boolean. If the result is a number, the result will
14501  * be converted to true if the number is equal to the position of the
14502  * context node in the context node list (as returned by the position
14503  * function) and will be converted to false otherwise; if the result
14504  * is not a number, then the result will be converted as if by a call
14505  * to the boolean function.
14506  *
14507  * Returns 1 if predicate is true, 0 otherwise
14508  */
14509 int
14510 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14511                                 xmlXPathObjectPtr res) {
14512     if ((ctxt == NULL) || (res == NULL)) return(0);
14513     switch (res->type) {
14514         case XPATH_BOOLEAN:
14515             return(res->boolval);
14516         case XPATH_NUMBER:
14517 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14518             return((res->floatval == ctxt->context->proximityPosition) &&
14519                    (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14520 #else
14521             return(res->floatval == ctxt->context->proximityPosition);
14522 #endif
14523         case XPATH_NODESET:
14524         case XPATH_XSLT_TREE:
14525             if (res->nodesetval == NULL)
14526                 return(0);
14527             return(res->nodesetval->nodeNr != 0);
14528         case XPATH_STRING:
14529             return((res->stringval != NULL) && (res->stringval[0] != 0));
14530 #ifdef LIBXML_XPTR_ENABLED
14531         case XPATH_LOCATIONSET:{
14532             xmlLocationSetPtr ptr = res->user;
14533             if (ptr == NULL)
14534                 return(0);
14535             return (ptr->locNr != 0);
14536             }
14537 #endif
14538         default:
14539             STRANGE
14540     }
14541     return(0);
14542 }
14543
14544 #ifdef XPATH_STREAMING
14545 /**
14546  * xmlXPathTryStreamCompile:
14547  * @ctxt: an XPath context
14548  * @str:  the XPath expression
14549  *
14550  * Try to compile the XPath expression as a streamable subset.
14551  *
14552  * Returns the compiled expression or NULL if failed to compile.
14553  */
14554 static xmlXPathCompExprPtr
14555 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14556     /*
14557      * Optimization: use streaming patterns when the XPath expression can
14558      * be compiled to a stream lookup
14559      */
14560     xmlPatternPtr stream;
14561     xmlXPathCompExprPtr comp;
14562     xmlDictPtr dict = NULL;
14563     const xmlChar **namespaces = NULL;
14564     xmlNsPtr ns;
14565     int i, j;
14566
14567     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14568         (!xmlStrchr(str, '@'))) {
14569         const xmlChar *tmp;
14570
14571         /*
14572          * We don't try to handle expressions using the verbose axis
14573          * specifiers ("::"), just the simplied form at this point.
14574          * Additionally, if there is no list of namespaces available and
14575          *  there's a ":" in the expression, indicating a prefixed QName,
14576          *  then we won't try to compile either. xmlPatterncompile() needs
14577          *  to have a list of namespaces at compilation time in order to
14578          *  compile prefixed name tests.
14579          */
14580         tmp = xmlStrchr(str, ':');
14581         if ((tmp != NULL) &&
14582             ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14583             return(NULL);
14584
14585         if (ctxt != NULL) {
14586             dict = ctxt->dict;
14587             if (ctxt->nsNr > 0) {
14588                 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14589                 if (namespaces == NULL) {
14590                     xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14591                     return(NULL);
14592                 }
14593                 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14594                     ns = ctxt->namespaces[j];
14595                     namespaces[i++] = ns->href;
14596                     namespaces[i++] = ns->prefix;
14597                 }
14598                 namespaces[i++] = NULL;
14599                 namespaces[i] = NULL;
14600             }
14601         }
14602
14603         stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14604                         &namespaces[0]);
14605         if (namespaces != NULL) {
14606             xmlFree((xmlChar **)namespaces);
14607         }
14608         if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14609             comp = xmlXPathNewCompExpr();
14610             if (comp == NULL) {
14611                 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14612                 return(NULL);
14613             }
14614             comp->stream = stream;
14615             comp->dict = dict;
14616             if (comp->dict)
14617                 xmlDictReference(comp->dict);
14618             return(comp);
14619         }
14620         xmlFreePattern(stream);
14621     }
14622     return(NULL);
14623 }
14624 #endif /* XPATH_STREAMING */
14625
14626 static int
14627 xmlXPathCanRewriteDosExpression(xmlChar *expr)
14628 {
14629     if (expr == NULL)
14630         return(0);
14631     do {
14632         if ((*expr == '/') && (*(++expr) == '/'))
14633             return(1);
14634     } while (*expr++);
14635     return(0);
14636 }
14637 static void
14638 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14639 {
14640     /*
14641     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14642     * internal representation.
14643     */
14644     if (op->ch1 != -1) {
14645         if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14646             ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14647             ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14648             ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14649         {
14650             /*
14651             * This is a "child::foo"
14652             */
14653             xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14654
14655             if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14656                 (prevop->ch1 != -1) &&
14657                 ((xmlXPathAxisVal) prevop->value ==
14658                     AXIS_DESCENDANT_OR_SELF) &&
14659                 (prevop->ch2 == -1) &&
14660                 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14661                 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14662                 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14663             {
14664                 /*
14665                 * This is a "/descendant-or-self::node()" without predicates.
14666                 * Eliminate it.
14667                 */
14668                 op->ch1 = prevop->ch1;
14669                 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14670             }
14671         }
14672         if (op->ch1 != -1)
14673             xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14674     }
14675     if (op->ch2 != -1)
14676         xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14677 }
14678
14679 /**
14680  * xmlXPathCtxtCompile:
14681  * @ctxt: an XPath context
14682  * @str:  the XPath expression
14683  *
14684  * Compile an XPath expression
14685  *
14686  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14687  *         the caller has to free the object.
14688  */
14689 xmlXPathCompExprPtr
14690 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14691     xmlXPathParserContextPtr pctxt;
14692     xmlXPathCompExprPtr comp;
14693
14694 #ifdef XPATH_STREAMING
14695     comp = xmlXPathTryStreamCompile(ctxt, str);
14696     if (comp != NULL)
14697         return(comp);
14698 #endif
14699
14700     xmlXPathInit();
14701
14702     pctxt = xmlXPathNewParserContext(str, ctxt);
14703     if (pctxt == NULL)
14704         return NULL;
14705     xmlXPathCompileExpr(pctxt, 1);
14706
14707     if( pctxt->error != XPATH_EXPRESSION_OK )
14708     {
14709         xmlXPathFreeParserContext(pctxt);
14710         return(NULL);
14711     }
14712
14713     if (*pctxt->cur != 0) {
14714         /*
14715          * aleksey: in some cases this line prints *second* error message
14716          * (see bug #78858) and probably this should be fixed.
14717          * However, we are not sure that all error messages are printed
14718          * out in other places. It's not critical so we leave it as-is for now
14719          */
14720         xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14721         comp = NULL;
14722     } else {
14723         comp = pctxt->comp;
14724         pctxt->comp = NULL;
14725     }
14726     xmlXPathFreeParserContext(pctxt);
14727
14728     if (comp != NULL) {
14729         comp->expr = xmlStrdup(str);
14730 #ifdef DEBUG_EVAL_COUNTS
14731         comp->string = xmlStrdup(str);
14732         comp->nb = 0;
14733 #endif
14734         if ((comp->expr != NULL) &&
14735             (comp->nbStep > 2) &&
14736             (comp->last >= 0) &&
14737             (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14738         {
14739             xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14740         }
14741     }
14742     return(comp);
14743 }
14744
14745 /**
14746  * xmlXPathCompile:
14747  * @str:  the XPath expression
14748  *
14749  * Compile an XPath expression
14750  *
14751  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14752  *         the caller has to free the object.
14753  */
14754 xmlXPathCompExprPtr
14755 xmlXPathCompile(const xmlChar *str) {
14756     return(xmlXPathCtxtCompile(NULL, str));
14757 }
14758
14759 /**
14760  * xmlXPathCompiledEvalInternal:
14761  * @comp:  the compiled XPath expression
14762  * @ctxt:  the XPath context
14763  * @resObj: the resulting XPath object or NULL
14764  * @toBool: 1 if only a boolean result is requested
14765  *
14766  * Evaluate the Precompiled XPath expression in the given context.
14767  * The caller has to free @resObj.
14768  *
14769  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14770  *         the caller has to free the object.
14771  */
14772 static int
14773 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14774                              xmlXPathContextPtr ctxt,
14775                              xmlXPathObjectPtr *resObj,
14776                              int toBool)
14777 {
14778     xmlXPathParserContextPtr pctxt;
14779 #ifndef LIBXML_THREAD_ENABLED
14780     static int reentance = 0;
14781 #endif
14782     int res;
14783
14784     CHECK_CTXT_NEG(ctxt)
14785
14786     if (comp == NULL)
14787         return(-1);
14788     xmlXPathInit();
14789
14790 #ifndef LIBXML_THREAD_ENABLED
14791     reentance++;
14792     if (reentance > 1)
14793         xmlXPathDisableOptimizer = 1;
14794 #endif
14795
14796 #ifdef DEBUG_EVAL_COUNTS
14797     comp->nb++;
14798     if ((comp->string != NULL) && (comp->nb > 100)) {
14799         fprintf(stderr, "100 x %s\n", comp->string);
14800         comp->nb = 0;
14801     }
14802 #endif
14803     pctxt = xmlXPathCompParserContext(comp, ctxt);
14804     res = xmlXPathRunEval(pctxt, toBool);
14805
14806     if (resObj) {
14807         if (pctxt->value == NULL) {
14808             xmlGenericError(xmlGenericErrorContext,
14809                 "xmlXPathCompiledEval: evaluation failed\n");
14810             *resObj = NULL;
14811         } else {
14812             *resObj = valuePop(pctxt);
14813         }
14814     }
14815
14816     /*
14817     * Pop all remaining objects from the stack.
14818     */
14819     if (pctxt->valueNr > 0) {
14820         xmlXPathObjectPtr tmp;
14821         int stack = 0;
14822
14823         do {
14824             tmp = valuePop(pctxt);
14825             if (tmp != NULL) {
14826                 stack++;
14827                 xmlXPathReleaseObject(ctxt, tmp);
14828             }
14829         } while (tmp != NULL);
14830         if ((stack != 0) &&
14831             ((toBool) || ((resObj) && (*resObj))))
14832         {
14833             xmlGenericError(xmlGenericErrorContext,
14834                 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14835                 stack);
14836         }
14837     }
14838
14839     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14840         xmlXPathFreeObject(*resObj);
14841         *resObj = NULL;
14842     }
14843     pctxt->comp = NULL;
14844     xmlXPathFreeParserContext(pctxt);
14845 #ifndef LIBXML_THREAD_ENABLED
14846     reentance--;
14847 #endif
14848
14849     return(res);
14850 }
14851
14852 /**
14853  * xmlXPathCompiledEval:
14854  * @comp:  the compiled XPath expression
14855  * @ctx:  the XPath context
14856  *
14857  * Evaluate the Precompiled XPath expression in the given context.
14858  *
14859  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14860  *         the caller has to free the object.
14861  */
14862 xmlXPathObjectPtr
14863 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14864 {
14865     xmlXPathObjectPtr res = NULL;
14866
14867     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14868     return(res);
14869 }
14870
14871 /**
14872  * xmlXPathCompiledEvalToBoolean:
14873  * @comp:  the compiled XPath expression
14874  * @ctxt:  the XPath context
14875  *
14876  * Applies the XPath boolean() function on the result of the given
14877  * compiled expression.
14878  *
14879  * Returns 1 if the expression evaluated to true, 0 if to false and
14880  *         -1 in API and internal errors.
14881  */
14882 int
14883 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14884                               xmlXPathContextPtr ctxt)
14885 {
14886     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14887 }
14888
14889 /**
14890  * xmlXPathEvalExpr:
14891  * @ctxt:  the XPath Parser context
14892  *
14893  * Parse and evaluate an XPath expression in the given context,
14894  * then push the result on the context stack
14895  */
14896 void
14897 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14898 #ifdef XPATH_STREAMING
14899     xmlXPathCompExprPtr comp;
14900 #endif
14901
14902     if (ctxt == NULL) return;
14903
14904 #ifdef XPATH_STREAMING
14905     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14906     if (comp != NULL) {
14907         if (ctxt->comp != NULL)
14908             xmlXPathFreeCompExpr(ctxt->comp);
14909         ctxt->comp = comp;
14910         if (ctxt->cur != NULL)
14911             while (*ctxt->cur != 0) ctxt->cur++;
14912     } else
14913 #endif
14914     {
14915         xmlXPathCompileExpr(ctxt, 1);
14916         /*
14917         * In this scenario the expression string will sit in ctxt->base.
14918         */
14919         if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14920             (ctxt->comp != NULL) &&
14921             (ctxt->base != NULL) &&
14922             (ctxt->comp->nbStep > 2) &&
14923             (ctxt->comp->last >= 0) &&
14924             (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14925         {
14926             xmlXPathRewriteDOSExpression(ctxt->comp,
14927                 &ctxt->comp->steps[ctxt->comp->last]);
14928         }
14929     }
14930     CHECK_ERROR;
14931     xmlXPathRunEval(ctxt, 0);
14932 }
14933
14934 /**
14935  * xmlXPathEval:
14936  * @str:  the XPath expression
14937  * @ctx:  the XPath context
14938  *
14939  * Evaluate the XPath Location Path in the given context.
14940  *
14941  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14942  *         the caller has to free the object.
14943  */
14944 xmlXPathObjectPtr
14945 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14946     xmlXPathParserContextPtr ctxt;
14947     xmlXPathObjectPtr res, tmp, init = NULL;
14948     int stack = 0;
14949
14950     CHECK_CTXT(ctx)
14951
14952     xmlXPathInit();
14953
14954     ctxt = xmlXPathNewParserContext(str, ctx);
14955     if (ctxt == NULL)
14956         return NULL;
14957     xmlXPathEvalExpr(ctxt);
14958
14959     if (ctxt->value == NULL) {
14960         xmlGenericError(xmlGenericErrorContext,
14961                 "xmlXPathEval: evaluation failed\n");
14962         res = NULL;
14963     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14964 #ifdef XPATH_STREAMING
14965             && (ctxt->comp->stream == NULL)
14966 #endif
14967               ) {
14968         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14969         res = NULL;
14970     } else {
14971         res = valuePop(ctxt);
14972     }
14973
14974     do {
14975         tmp = valuePop(ctxt);
14976         if (tmp != NULL) {
14977             if (tmp != init)
14978                 stack++;
14979             xmlXPathReleaseObject(ctx, tmp);
14980         }
14981     } while (tmp != NULL);
14982     if ((stack != 0) && (res != NULL)) {
14983         xmlGenericError(xmlGenericErrorContext,
14984                 "xmlXPathEval: %d object left on the stack\n",
14985                 stack);
14986     }
14987     if (ctxt->error != XPATH_EXPRESSION_OK) {
14988         xmlXPathFreeObject(res);
14989         res = NULL;
14990     }
14991
14992     xmlXPathFreeParserContext(ctxt);
14993     return(res);
14994 }
14995
14996 /**
14997  * xmlXPathEvalExpression:
14998  * @str:  the XPath expression
14999  * @ctxt:  the XPath context
15000  *
15001  * Evaluate the XPath expression in the given context.
15002  *
15003  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15004  *         the caller has to free the object.
15005  */
15006 xmlXPathObjectPtr
15007 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15008     xmlXPathParserContextPtr pctxt;
15009     xmlXPathObjectPtr res, tmp;
15010     int stack = 0;
15011
15012     CHECK_CTXT(ctxt)
15013
15014     xmlXPathInit();
15015
15016     pctxt = xmlXPathNewParserContext(str, ctxt);
15017     if (pctxt == NULL)
15018         return NULL;
15019     xmlXPathEvalExpr(pctxt);
15020
15021     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
15022         xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15023         res = NULL;
15024     } else {
15025         res = valuePop(pctxt);
15026     }
15027     do {
15028         tmp = valuePop(pctxt);
15029         if (tmp != NULL) {
15030             xmlXPathReleaseObject(ctxt, tmp);
15031             stack++;
15032         }
15033     } while (tmp != NULL);
15034     if ((stack != 0) && (res != NULL)) {
15035         xmlGenericError(xmlGenericErrorContext,
15036                 "xmlXPathEvalExpression: %d object left on the stack\n",
15037                 stack);
15038     }
15039     xmlXPathFreeParserContext(pctxt);
15040     return(res);
15041 }
15042
15043 /************************************************************************
15044  *                                                                      *
15045  *      Extra functions not pertaining to the XPath spec                *
15046  *                                                                      *
15047  ************************************************************************/
15048 /**
15049  * xmlXPathEscapeUriFunction:
15050  * @ctxt:  the XPath Parser context
15051  * @nargs:  the number of arguments
15052  *
15053  * Implement the escape-uri() XPath function
15054  *    string escape-uri(string $str, bool $escape-reserved)
15055  *
15056  * This function applies the URI escaping rules defined in section 2 of [RFC
15057  * 2396] to the string supplied as $uri-part, which typically represents all
15058  * or part of a URI. The effect of the function is to replace any special
15059  * character in the string by an escape sequence of the form %xx%yy...,
15060  * where xxyy... is the hexadecimal representation of the octets used to
15061  * represent the character in UTF-8.
15062  *
15063  * The set of characters that are escaped depends on the setting of the
15064  * boolean argument $escape-reserved.
15065  *
15066  * If $escape-reserved is true, all characters are escaped other than lower
15067  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15068  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15069  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15070  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15071  * A-F).
15072  *
15073  * If $escape-reserved is false, the behavior differs in that characters
15074  * referred to in [RFC 2396] as reserved characters are not escaped. These
15075  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15076  *
15077  * [RFC 2396] does not define whether escaped URIs should use lower case or
15078  * upper case for hexadecimal digits. To ensure that escaped URIs can be
15079  * compared using string comparison functions, this function must always use
15080  * the upper-case letters A-F.
15081  *
15082  * Generally, $escape-reserved should be set to true when escaping a string
15083  * that is to form a single part of a URI, and to false when escaping an
15084  * entire URI or URI reference.
15085  *
15086  * In the case of non-ascii characters, the string is encoded according to
15087  * utf-8 and then converted according to RFC 2396.
15088  *
15089  * Examples
15090  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15091  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15092  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15093  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15094  *
15095  */
15096 static void
15097 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15098     xmlXPathObjectPtr str;
15099     int escape_reserved;
15100     xmlBufferPtr target;
15101     xmlChar *cptr;
15102     xmlChar escape[4];
15103
15104     CHECK_ARITY(2);
15105
15106     escape_reserved = xmlXPathPopBoolean(ctxt);
15107
15108     CAST_TO_STRING;
15109     str = valuePop(ctxt);
15110
15111     target = xmlBufferCreate();
15112
15113     escape[0] = '%';
15114     escape[3] = 0;
15115
15116     if (target) {
15117         for (cptr = str->stringval; *cptr; cptr++) {
15118             if ((*cptr >= 'A' && *cptr <= 'Z') ||
15119                 (*cptr >= 'a' && *cptr <= 'z') ||
15120                 (*cptr >= '0' && *cptr <= '9') ||
15121                 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15122                 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15123                 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15124                 (*cptr == '%' &&
15125                  ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15126                   (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15127                   (cptr[1] >= '0' && cptr[1] <= '9')) &&
15128                  ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15129                   (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15130                   (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15131                 (!escape_reserved &&
15132                  (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15133                   *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15134                   *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15135                   *cptr == ','))) {
15136                 xmlBufferAdd(target, cptr, 1);
15137             } else {
15138                 if ((*cptr >> 4) < 10)
15139                     escape[1] = '0' + (*cptr >> 4);
15140                 else
15141                     escape[1] = 'A' - 10 + (*cptr >> 4);
15142                 if ((*cptr & 0xF) < 10)
15143                     escape[2] = '0' + (*cptr & 0xF);
15144                 else
15145                     escape[2] = 'A' - 10 + (*cptr & 0xF);
15146
15147                 xmlBufferAdd(target, &escape[0], 3);
15148             }
15149         }
15150     }
15151     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15152         xmlBufferContent(target)));
15153     xmlBufferFree(target);
15154     xmlXPathReleaseObject(ctxt->context, str);
15155 }
15156
15157 /**
15158  * xmlXPathRegisterAllFunctions:
15159  * @ctxt:  the XPath context
15160  *
15161  * Registers all default XPath functions in this context
15162  */
15163 void
15164 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15165 {
15166     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15167                          xmlXPathBooleanFunction);
15168     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15169                          xmlXPathCeilingFunction);
15170     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15171                          xmlXPathCountFunction);
15172     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15173                          xmlXPathConcatFunction);
15174     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15175                          xmlXPathContainsFunction);
15176     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15177                          xmlXPathIdFunction);
15178     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15179                          xmlXPathFalseFunction);
15180     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15181                          xmlXPathFloorFunction);
15182     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15183                          xmlXPathLastFunction);
15184     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15185                          xmlXPathLangFunction);
15186     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15187                          xmlXPathLocalNameFunction);
15188     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15189                          xmlXPathNotFunction);
15190     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15191                          xmlXPathNameFunction);
15192     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15193                          xmlXPathNamespaceURIFunction);
15194     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15195                          xmlXPathNormalizeFunction);
15196     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15197                          xmlXPathNumberFunction);
15198     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15199                          xmlXPathPositionFunction);
15200     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15201                          xmlXPathRoundFunction);
15202     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15203                          xmlXPathStringFunction);
15204     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15205                          xmlXPathStringLengthFunction);
15206     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15207                          xmlXPathStartsWithFunction);
15208     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15209                          xmlXPathSubstringFunction);
15210     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15211                          xmlXPathSubstringBeforeFunction);
15212     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15213                          xmlXPathSubstringAfterFunction);
15214     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15215                          xmlXPathSumFunction);
15216     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15217                          xmlXPathTrueFunction);
15218     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15219                          xmlXPathTranslateFunction);
15220
15221     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15222          (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15223                          xmlXPathEscapeUriFunction);
15224 }
15225
15226 #endif /* LIBXML_XPATH_ENABLED */
15227 #define bottom_xpath
15228 #include "elfgcchack.h"