Imported Upstream version 2.9.6
[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 /* To avoid EBCDIC trouble when parsing on zOS */
18 #if defined(__MVS__)
19 #pragma convert("ISO8859-1")
20 #endif
21
22 #define IN_LIBXML
23 #include "libxml.h"
24
25 #include <limits.h>
26 #include <string.h>
27
28 #ifdef HAVE_SYS_TYPES_H
29 #include <sys/types.h>
30 #endif
31 #ifdef HAVE_MATH_H
32 #include <math.h>
33 #endif
34 #ifdef HAVE_FLOAT_H
35 #include <float.h>
36 #endif
37 #ifdef HAVE_CTYPE_H
38 #include <ctype.h>
39 #endif
40 #ifdef HAVE_SIGNAL_H
41 #include <signal.h>
42 #endif
43
44 #include <libxml/xmlmemory.h>
45 #include <libxml/tree.h>
46 #include <libxml/valid.h>
47 #include <libxml/xpath.h>
48 #include <libxml/xpathInternals.h>
49 #include <libxml/parserInternals.h>
50 #include <libxml/hash.h>
51 #ifdef LIBXML_XPTR_ENABLED
52 #include <libxml/xpointer.h>
53 #endif
54 #ifdef LIBXML_DEBUG_ENABLED
55 #include <libxml/debugXML.h>
56 #endif
57 #include <libxml/xmlerror.h>
58 #include <libxml/threads.h>
59 #include <libxml/globals.h>
60 #ifdef LIBXML_PATTERN_ENABLED
61 #include <libxml/pattern.h>
62 #endif
63
64 #include "buf.h"
65
66 #ifdef LIBXML_PATTERN_ENABLED
67 #define XPATH_STREAMING
68 #endif
69
70 #define TODO                                                            \
71     xmlGenericError(xmlGenericErrorContext,                             \
72             "Unimplemented block at %s:%d\n",                           \
73             __FILE__, __LINE__);
74
75 /**
76  * WITH_TIM_SORT:
77  *
78  * Use the Timsort algorithm provided in timsort.h to sort
79  * nodeset as this is a great improvement over the old Shell sort
80  * used in xmlXPathNodeSetSort()
81  */
82 #define WITH_TIM_SORT
83
84 /*
85 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
86 * If defined, this will use xmlXPathCmpNodesExt() instead of
87 * xmlXPathCmpNodes(). The new function is optimized comparison of
88 * non-element nodes; actually it will speed up comparison only if
89 * xmlXPathOrderDocElems() was called in order to index the elements of
90 * a tree in document order; Libxslt does such an indexing, thus it will
91 * benefit from this optimization.
92 */
93 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
94
95 /*
96 * XP_OPTIMIZED_FILTER_FIRST:
97 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
98 * in a way, that it stop evaluation at the first node.
99 */
100 #define XP_OPTIMIZED_FILTER_FIRST
101
102 /*
103 * XP_DEBUG_OBJ_USAGE:
104 * Internal flag to enable tracking of how much XPath objects have been
105 * created.
106 */
107 /* #define XP_DEBUG_OBJ_USAGE */
108
109 /*
110  * XPATH_MAX_STEPS:
111  * when compiling an XPath expression we arbitrary limit the maximum
112  * number of step operation in the compiled expression. 1000000 is
113  * an insanely large value which should never be reached under normal
114  * circumstances
115  */
116 #define XPATH_MAX_STEPS 1000000
117
118 /*
119  * XPATH_MAX_STACK_DEPTH:
120  * when evaluating an XPath expression we arbitrary limit the maximum
121  * number of object allowed to be pushed on the stack. 1000000 is
122  * an insanely large value which should never be reached under normal
123  * circumstances
124  */
125 #define XPATH_MAX_STACK_DEPTH 1000000
126
127 /*
128  * XPATH_MAX_NODESET_LENGTH:
129  * when evaluating an XPath expression nodesets are created and we
130  * arbitrary limit the maximum length of those node set. 10000000 is
131  * an insanely large value which should never be reached under normal
132  * circumstances, one would first need to construct an in memory tree
133  * with more than 10 millions nodes.
134  */
135 #define XPATH_MAX_NODESET_LENGTH 10000000
136
137 /*
138  * TODO:
139  * There are a few spots where some tests are done which depend upon ascii
140  * data.  These should be enhanced for full UTF8 support (see particularly
141  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
142  */
143
144 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
145 /**
146  * xmlXPathCmpNodesExt:
147  * @node1:  the first node
148  * @node2:  the second node
149  *
150  * Compare two nodes w.r.t document order.
151  * This one is optimized for handling of non-element nodes.
152  *
153  * Returns -2 in case of error 1 if first point < second point, 0 if
154  *         it's the same node, -1 otherwise
155  */
156 static int
157 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
158     int depth1, depth2;
159     int misc = 0, precedence1 = 0, precedence2 = 0;
160     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
161     xmlNodePtr cur, root;
162     long l1, l2;
163
164     if ((node1 == NULL) || (node2 == NULL))
165         return(-2);
166
167     if (node1 == node2)
168         return(0);
169
170     /*
171      * a couple of optimizations which will avoid computations in most cases
172      */
173     switch (node1->type) {
174         case XML_ELEMENT_NODE:
175             if (node2->type == XML_ELEMENT_NODE) {
176                 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
177                     (0 > (long) node2->content) &&
178                     (node1->doc == node2->doc))
179                 {
180                     l1 = -((long) node1->content);
181                     l2 = -((long) node2->content);
182                     if (l1 < l2)
183                         return(1);
184                     if (l1 > l2)
185                         return(-1);
186                 } else
187                     goto turtle_comparison;
188             }
189             break;
190         case XML_ATTRIBUTE_NODE:
191             precedence1 = 1; /* element is owner */
192             miscNode1 = node1;
193             node1 = node1->parent;
194             misc = 1;
195             break;
196         case XML_TEXT_NODE:
197         case XML_CDATA_SECTION_NODE:
198         case XML_COMMENT_NODE:
199         case XML_PI_NODE: {
200             miscNode1 = node1;
201             /*
202             * Find nearest element node.
203             */
204             if (node1->prev != NULL) {
205                 do {
206                     node1 = node1->prev;
207                     if (node1->type == XML_ELEMENT_NODE) {
208                         precedence1 = 3; /* element in prev-sibl axis */
209                         break;
210                     }
211                     if (node1->prev == NULL) {
212                         precedence1 = 2; /* element is parent */
213                         /*
214                         * URGENT TODO: Are there any cases, where the
215                         * parent of such a node is not an element node?
216                         */
217                         node1 = node1->parent;
218                         break;
219                     }
220                 } while (1);
221             } else {
222                 precedence1 = 2; /* element is parent */
223                 node1 = node1->parent;
224             }
225             if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
226                 (0 <= (long) node1->content)) {
227                 /*
228                 * Fallback for whatever case.
229                 */
230                 node1 = miscNode1;
231                 precedence1 = 0;
232             } else
233                 misc = 1;
234         }
235             break;
236         case XML_NAMESPACE_DECL:
237             /*
238             * TODO: why do we return 1 for namespace nodes?
239             */
240             return(1);
241         default:
242             break;
243     }
244     switch (node2->type) {
245         case XML_ELEMENT_NODE:
246             break;
247         case XML_ATTRIBUTE_NODE:
248             precedence2 = 1; /* element is owner */
249             miscNode2 = node2;
250             node2 = node2->parent;
251             misc = 1;
252             break;
253         case XML_TEXT_NODE:
254         case XML_CDATA_SECTION_NODE:
255         case XML_COMMENT_NODE:
256         case XML_PI_NODE: {
257             miscNode2 = node2;
258             if (node2->prev != NULL) {
259                 do {
260                     node2 = node2->prev;
261                     if (node2->type == XML_ELEMENT_NODE) {
262                         precedence2 = 3; /* element in prev-sibl axis */
263                         break;
264                     }
265                     if (node2->prev == NULL) {
266                         precedence2 = 2; /* element is parent */
267                         node2 = node2->parent;
268                         break;
269                     }
270                 } while (1);
271             } else {
272                 precedence2 = 2; /* element is parent */
273                 node2 = node2->parent;
274             }
275             if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
276                 (0 <= (long) node2->content))
277             {
278                 node2 = miscNode2;
279                 precedence2 = 0;
280             } else
281                 misc = 1;
282         }
283             break;
284         case XML_NAMESPACE_DECL:
285             return(1);
286         default:
287             break;
288     }
289     if (misc) {
290         if (node1 == node2) {
291             if (precedence1 == precedence2) {
292                 /*
293                 * The ugly case; but normally there aren't many
294                 * adjacent non-element nodes around.
295                 */
296                 cur = miscNode2->prev;
297                 while (cur != NULL) {
298                     if (cur == miscNode1)
299                         return(1);
300                     if (cur->type == XML_ELEMENT_NODE)
301                         return(-1);
302                     cur = cur->prev;
303                 }
304                 return (-1);
305             } else {
306                 /*
307                 * Evaluate based on higher precedence wrt to the element.
308                 * TODO: This assumes attributes are sorted before content.
309                 *   Is this 100% correct?
310                 */
311                 if (precedence1 < precedence2)
312                     return(1);
313                 else
314                     return(-1);
315             }
316         }
317         /*
318         * Special case: One of the helper-elements is contained by the other.
319         * <foo>
320         *   <node2>
321         *     <node1>Text-1(precedence1 == 2)</node1>
322         *   </node2>
323         *   Text-6(precedence2 == 3)
324         * </foo>
325         */
326         if ((precedence2 == 3) && (precedence1 > 1)) {
327             cur = node1->parent;
328             while (cur) {
329                 if (cur == node2)
330                     return(1);
331                 cur = cur->parent;
332             }
333         }
334         if ((precedence1 == 3) && (precedence2 > 1)) {
335             cur = node2->parent;
336             while (cur) {
337                 if (cur == node1)
338                     return(-1);
339                 cur = cur->parent;
340             }
341         }
342     }
343
344     /*
345      * Speedup using document order if availble.
346      */
347     if ((node1->type == XML_ELEMENT_NODE) &&
348         (node2->type == XML_ELEMENT_NODE) &&
349         (0 > (long) node1->content) &&
350         (0 > (long) node2->content) &&
351         (node1->doc == node2->doc)) {
352
353         l1 = -((long) node1->content);
354         l2 = -((long) node2->content);
355         if (l1 < l2)
356             return(1);
357         if (l1 > l2)
358             return(-1);
359     }
360
361 turtle_comparison:
362
363     if (node1 == node2->prev)
364         return(1);
365     if (node1 == node2->next)
366         return(-1);
367     /*
368      * compute depth to root
369      */
370     for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
371         if (cur->parent == node1)
372             return(1);
373         depth2++;
374     }
375     root = cur;
376     for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
377         if (cur->parent == node2)
378             return(-1);
379         depth1++;
380     }
381     /*
382      * Distinct document (or distinct entities :-( ) case.
383      */
384     if (root != cur) {
385         return(-2);
386     }
387     /*
388      * get the nearest common ancestor.
389      */
390     while (depth1 > depth2) {
391         depth1--;
392         node1 = node1->parent;
393     }
394     while (depth2 > depth1) {
395         depth2--;
396         node2 = node2->parent;
397     }
398     while (node1->parent != node2->parent) {
399         node1 = node1->parent;
400         node2 = node2->parent;
401         /* should not happen but just in case ... */
402         if ((node1 == NULL) || (node2 == NULL))
403             return(-2);
404     }
405     /*
406      * Find who's first.
407      */
408     if (node1 == node2->prev)
409         return(1);
410     if (node1 == node2->next)
411         return(-1);
412     /*
413      * Speedup using document order if availble.
414      */
415     if ((node1->type == XML_ELEMENT_NODE) &&
416         (node2->type == XML_ELEMENT_NODE) &&
417         (0 > (long) node1->content) &&
418         (0 > (long) node2->content) &&
419         (node1->doc == node2->doc)) {
420
421         l1 = -((long) node1->content);
422         l2 = -((long) node2->content);
423         if (l1 < l2)
424             return(1);
425         if (l1 > l2)
426             return(-1);
427     }
428
429     for (cur = node1->next;cur != NULL;cur = cur->next)
430         if (cur == node2)
431             return(1);
432     return(-1); /* assume there is no sibling list corruption */
433 }
434 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
435
436 /*
437  * Wrapper for the Timsort argorithm from timsort.h
438  */
439 #ifdef WITH_TIM_SORT
440 #define SORT_NAME libxml_domnode
441 #define SORT_TYPE xmlNodePtr
442 /**
443  * wrap_cmp:
444  * @x: a node
445  * @y: another node
446  *
447  * Comparison function for the Timsort implementation
448  *
449  * Returns -2 in case of error -1 if first point < second point, 0 if
450  *         it's the same node, +1 otherwise
451  */
452 static
453 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
454 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
455     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
456     {
457         int res = xmlXPathCmpNodesExt(x, y);
458         return res == -2 ? res : -res;
459     }
460 #else
461     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
462     {
463         int res = xmlXPathCmpNodes(x, y);
464         return res == -2 ? res : -res;
465     }
466 #endif
467 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
468 #include "timsort.h"
469 #endif /* WITH_TIM_SORT */
470
471 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
472
473 /************************************************************************
474  *                                                                      *
475  *                      Floating point stuff                            *
476  *                                                                      *
477  ************************************************************************/
478
479 #ifndef TRIO_REPLACE_STDIO
480 #define TRIO_PUBLIC static
481 #endif
482 #include "trionan.c"
483
484 /*
485  * The lack of portability of this section of the libc is annoying !
486  */
487 double xmlXPathNAN = 0;
488 double xmlXPathPINF = 1;
489 double xmlXPathNINF = -1;
490 static double xmlXPathNZERO = 0; /* not exported from headers */
491 static int xmlXPathInitialized = 0;
492
493 /**
494  * xmlXPathInit:
495  *
496  * Initialize the XPath environment
497  */
498 void
499 xmlXPathInit(void) {
500     if (xmlXPathInitialized) return;
501
502     xmlXPathPINF = trio_pinf();
503     xmlXPathNINF = trio_ninf();
504     xmlXPathNAN = trio_nan();
505     xmlXPathNZERO = trio_nzero();
506
507     xmlXPathInitialized = 1;
508 }
509
510 /**
511  * xmlXPathIsNaN:
512  * @val:  a double value
513  *
514  * Provides a portable isnan() function to detect whether a double
515  * is a NotaNumber. Based on trio code
516  * http://sourceforge.net/projects/ctrio/
517  *
518  * Returns 1 if the value is a NaN, 0 otherwise
519  */
520 int
521 xmlXPathIsNaN(double val) {
522     return(trio_isnan(val));
523 }
524
525 /**
526  * xmlXPathIsInf:
527  * @val:  a double value
528  *
529  * Provides a portable isinf() function to detect whether a double
530  * is a +Infinite or -Infinite. Based on trio code
531  * http://sourceforge.net/projects/ctrio/
532  *
533  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
534  */
535 int
536 xmlXPathIsInf(double val) {
537     return(trio_isinf(val));
538 }
539
540 #endif /* SCHEMAS or XPATH */
541 #ifdef LIBXML_XPATH_ENABLED
542 /**
543  * xmlXPathGetSign:
544  * @val:  a double value
545  *
546  * Provides a portable function to detect the sign of a double
547  * Modified from trio code
548  * http://sourceforge.net/projects/ctrio/
549  *
550  * Returns 1 if the value is Negative, 0 if positive
551  */
552 static int
553 xmlXPathGetSign(double val) {
554     return(trio_signbit(val));
555 }
556
557
558 /*
559  * TODO: when compatibility allows remove all "fake node libxslt" strings
560  *       the test should just be name[0] = ' '
561  */
562 #ifdef DEBUG_XPATH_EXPRESSION
563 #define DEBUG_STEP
564 #define DEBUG_EXPR
565 #define DEBUG_EVAL_COUNTS
566 #endif
567
568 static xmlNs xmlXPathXMLNamespaceStruct = {
569     NULL,
570     XML_NAMESPACE_DECL,
571     XML_XML_NAMESPACE,
572     BAD_CAST "xml",
573     NULL,
574     NULL
575 };
576 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
577 #ifndef LIBXML_THREAD_ENABLED
578 /*
579  * Optimizer is disabled only when threaded apps are detected while
580  * the library ain't compiled for thread safety.
581  */
582 static int xmlXPathDisableOptimizer = 0;
583 #endif
584
585 /************************************************************************
586  *                                                                      *
587  *                      Error handling routines                         *
588  *                                                                      *
589  ************************************************************************/
590
591 /**
592  * XP_ERRORNULL:
593  * @X:  the error code
594  *
595  * Macro to raise an XPath error and return NULL.
596  */
597 #define XP_ERRORNULL(X)                                                 \
598     { xmlXPathErr(ctxt, X); return(NULL); }
599
600 /*
601  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
602  */
603 static const char *xmlXPathErrorMessages[] = {
604     "Ok\n",
605     "Number encoding\n",
606     "Unfinished literal\n",
607     "Start of literal\n",
608     "Expected $ for variable reference\n",
609     "Undefined variable\n",
610     "Invalid predicate\n",
611     "Invalid expression\n",
612     "Missing closing curly brace\n",
613     "Unregistered function\n",
614     "Invalid operand\n",
615     "Invalid type\n",
616     "Invalid number of arguments\n",
617     "Invalid context size\n",
618     "Invalid context position\n",
619     "Memory allocation error\n",
620     "Syntax error\n",
621     "Resource error\n",
622     "Sub resource error\n",
623     "Undefined namespace prefix\n",
624     "Encoding error\n",
625     "Char out of XML range\n",
626     "Invalid or incomplete context\n",
627     "Stack usage error\n",
628     "Forbidden variable\n",
629     "?? Unknown error ??\n"     /* Must be last in the list! */
630 };
631 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
632                    sizeof(xmlXPathErrorMessages[0])) - 1)
633 /**
634  * xmlXPathErrMemory:
635  * @ctxt:  an XPath context
636  * @extra:  extra informations
637  *
638  * Handle a redefinition of attribute error
639  */
640 static void
641 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
642 {
643     if (ctxt != NULL) {
644         if (extra) {
645             xmlChar buf[200];
646
647             xmlStrPrintf(buf, 200,
648                          "Memory allocation failed : %s\n",
649                          extra);
650             ctxt->lastError.message = (char *) xmlStrdup(buf);
651         } else {
652             ctxt->lastError.message = (char *)
653                xmlStrdup(BAD_CAST "Memory allocation failed\n");
654         }
655         ctxt->lastError.domain = XML_FROM_XPATH;
656         ctxt->lastError.code = XML_ERR_NO_MEMORY;
657         if (ctxt->error != NULL)
658             ctxt->error(ctxt->userData, &ctxt->lastError);
659     } else {
660         if (extra)
661             __xmlRaiseError(NULL, NULL, NULL,
662                             NULL, NULL, XML_FROM_XPATH,
663                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
664                             extra, NULL, NULL, 0, 0,
665                             "Memory allocation failed : %s\n", extra);
666         else
667             __xmlRaiseError(NULL, NULL, NULL,
668                             NULL, NULL, XML_FROM_XPATH,
669                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
670                             NULL, NULL, NULL, 0, 0,
671                             "Memory allocation failed\n");
672     }
673 }
674
675 /**
676  * xmlXPathPErrMemory:
677  * @ctxt:  an XPath parser context
678  * @extra:  extra informations
679  *
680  * Handle a redefinition of attribute error
681  */
682 static void
683 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
684 {
685     if (ctxt == NULL)
686         xmlXPathErrMemory(NULL, extra);
687     else {
688         ctxt->error = XPATH_MEMORY_ERROR;
689         xmlXPathErrMemory(ctxt->context, extra);
690     }
691 }
692
693 /**
694  * xmlXPathErr:
695  * @ctxt:  a XPath parser context
696  * @error:  the error code
697  *
698  * Handle an XPath error
699  */
700 void
701 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
702 {
703     if ((error < 0) || (error > MAXERRNO))
704         error = MAXERRNO;
705     if (ctxt == NULL) {
706         __xmlRaiseError(NULL, NULL, NULL,
707                         NULL, NULL, XML_FROM_XPATH,
708                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
709                         XML_ERR_ERROR, NULL, 0,
710                         NULL, NULL, NULL, 0, 0,
711                         "%s", xmlXPathErrorMessages[error]);
712         return;
713     }
714     ctxt->error = error;
715     if (ctxt->context == NULL) {
716         __xmlRaiseError(NULL, NULL, NULL,
717                         NULL, NULL, XML_FROM_XPATH,
718                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
719                         XML_ERR_ERROR, NULL, 0,
720                         (const char *) ctxt->base, NULL, NULL,
721                         ctxt->cur - ctxt->base, 0,
722                         "%s", xmlXPathErrorMessages[error]);
723         return;
724     }
725
726     /* cleanup current last error */
727     xmlResetError(&ctxt->context->lastError);
728
729     ctxt->context->lastError.domain = XML_FROM_XPATH;
730     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
731                            XPATH_EXPRESSION_OK;
732     ctxt->context->lastError.level = XML_ERR_ERROR;
733     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
734     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
735     ctxt->context->lastError.node = ctxt->context->debugNode;
736     if (ctxt->context->error != NULL) {
737         ctxt->context->error(ctxt->context->userData,
738                              &ctxt->context->lastError);
739     } else {
740         __xmlRaiseError(NULL, NULL, NULL,
741                         NULL, ctxt->context->debugNode, XML_FROM_XPATH,
742                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
743                         XML_ERR_ERROR, NULL, 0,
744                         (const char *) ctxt->base, NULL, NULL,
745                         ctxt->cur - ctxt->base, 0,
746                         "%s", xmlXPathErrorMessages[error]);
747     }
748
749 }
750
751 /**
752  * xmlXPatherror:
753  * @ctxt:  the XPath Parser context
754  * @file:  the file name
755  * @line:  the line number
756  * @no:  the error number
757  *
758  * Formats an error message.
759  */
760 void
761 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
762               int line ATTRIBUTE_UNUSED, int no) {
763     xmlXPathErr(ctxt, no);
764 }
765
766 /************************************************************************
767  *                                                                      *
768  *                      Utilities                                       *
769  *                                                                      *
770  ************************************************************************/
771
772 /**
773  * xsltPointerList:
774  *
775  * Pointer-list for various purposes.
776  */
777 typedef struct _xmlPointerList xmlPointerList;
778 typedef xmlPointerList *xmlPointerListPtr;
779 struct _xmlPointerList {
780     void **items;
781     int number;
782     int size;
783 };
784 /*
785 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
786 * and here, we should make the functions public.
787 */
788 static int
789 xmlPointerListAddSize(xmlPointerListPtr list,
790                        void *item,
791                        int initialSize)
792 {
793     if (list->items == NULL) {
794         if (initialSize <= 0)
795             initialSize = 1;
796         list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
797         if (list->items == NULL) {
798             xmlXPathErrMemory(NULL,
799                 "xmlPointerListCreate: allocating item\n");
800             return(-1);
801         }
802         list->number = 0;
803         list->size = initialSize;
804     } else if (list->size <= list->number) {
805         if (list->size > 50000000) {
806             xmlXPathErrMemory(NULL,
807                 "xmlPointerListAddSize: re-allocating item\n");
808             return(-1);
809         }
810         list->size *= 2;
811         list->items = (void **) xmlRealloc(list->items,
812             list->size * sizeof(void *));
813         if (list->items == NULL) {
814             xmlXPathErrMemory(NULL,
815                 "xmlPointerListAddSize: re-allocating item\n");
816             list->size = 0;
817             return(-1);
818         }
819     }
820     list->items[list->number++] = item;
821     return(0);
822 }
823
824 /**
825  * xsltPointerListCreate:
826  *
827  * Creates an xsltPointerList structure.
828  *
829  * Returns a xsltPointerList structure or NULL in case of an error.
830  */
831 static xmlPointerListPtr
832 xmlPointerListCreate(int initialSize)
833 {
834     xmlPointerListPtr ret;
835
836     ret = xmlMalloc(sizeof(xmlPointerList));
837     if (ret == NULL) {
838         xmlXPathErrMemory(NULL,
839             "xmlPointerListCreate: allocating item\n");
840         return (NULL);
841     }
842     memset(ret, 0, sizeof(xmlPointerList));
843     if (initialSize > 0) {
844         xmlPointerListAddSize(ret, NULL, initialSize);
845         ret->number = 0;
846     }
847     return (ret);
848 }
849
850 /**
851  * xsltPointerListFree:
852  *
853  * Frees the xsltPointerList structure. This does not free
854  * the content of the list.
855  */
856 static void
857 xmlPointerListFree(xmlPointerListPtr list)
858 {
859     if (list == NULL)
860         return;
861     if (list->items != NULL)
862         xmlFree(list->items);
863     xmlFree(list);
864 }
865
866 /************************************************************************
867  *                                                                      *
868  *                      Parser Types                                    *
869  *                                                                      *
870  ************************************************************************/
871
872 /*
873  * Types are private:
874  */
875
876 typedef enum {
877     XPATH_OP_END=0,
878     XPATH_OP_AND,
879     XPATH_OP_OR,
880     XPATH_OP_EQUAL,
881     XPATH_OP_CMP,
882     XPATH_OP_PLUS,
883     XPATH_OP_MULT,
884     XPATH_OP_UNION,
885     XPATH_OP_ROOT,
886     XPATH_OP_NODE,
887     XPATH_OP_RESET, /* 10 */
888     XPATH_OP_COLLECT,
889     XPATH_OP_VALUE, /* 12 */
890     XPATH_OP_VARIABLE,
891     XPATH_OP_FUNCTION,
892     XPATH_OP_ARG,
893     XPATH_OP_PREDICATE,
894     XPATH_OP_FILTER, /* 17 */
895     XPATH_OP_SORT /* 18 */
896 #ifdef LIBXML_XPTR_ENABLED
897     ,XPATH_OP_RANGETO
898 #endif
899 } xmlXPathOp;
900
901 typedef enum {
902     AXIS_ANCESTOR = 1,
903     AXIS_ANCESTOR_OR_SELF,
904     AXIS_ATTRIBUTE,
905     AXIS_CHILD,
906     AXIS_DESCENDANT,
907     AXIS_DESCENDANT_OR_SELF,
908     AXIS_FOLLOWING,
909     AXIS_FOLLOWING_SIBLING,
910     AXIS_NAMESPACE,
911     AXIS_PARENT,
912     AXIS_PRECEDING,
913     AXIS_PRECEDING_SIBLING,
914     AXIS_SELF
915 } xmlXPathAxisVal;
916
917 typedef enum {
918     NODE_TEST_NONE = 0,
919     NODE_TEST_TYPE = 1,
920     NODE_TEST_PI = 2,
921     NODE_TEST_ALL = 3,
922     NODE_TEST_NS = 4,
923     NODE_TEST_NAME = 5
924 } xmlXPathTestVal;
925
926 typedef enum {
927     NODE_TYPE_NODE = 0,
928     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
929     NODE_TYPE_TEXT = XML_TEXT_NODE,
930     NODE_TYPE_PI = XML_PI_NODE
931 } xmlXPathTypeVal;
932
933 typedef struct _xmlXPathStepOp xmlXPathStepOp;
934 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
935 struct _xmlXPathStepOp {
936     xmlXPathOp op;              /* The identifier of the operation */
937     int ch1;                    /* First child */
938     int ch2;                    /* Second child */
939     int value;
940     int value2;
941     int value3;
942     void *value4;
943     void *value5;
944     xmlXPathFunction cache;
945     void *cacheURI;
946 };
947
948 struct _xmlXPathCompExpr {
949     int nbStep;                 /* Number of steps in this expression */
950     int maxStep;                /* Maximum number of steps allocated */
951     xmlXPathStepOp *steps;      /* ops for computation of this expression */
952     int last;                   /* index of last step in expression */
953     xmlChar *expr;              /* the expression being computed */
954     xmlDictPtr dict;            /* the dictionary to use if any */
955 #ifdef DEBUG_EVAL_COUNTS
956     int nb;
957     xmlChar *string;
958 #endif
959 #ifdef XPATH_STREAMING
960     xmlPatternPtr stream;
961 #endif
962 };
963
964 /************************************************************************
965  *                                                                      *
966  *                      Forward declarations                            *
967  *                                                                      *
968  ************************************************************************/
969 static void
970 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
971 static void
972 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
973 static int
974 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
975                         xmlXPathStepOpPtr op, xmlNodePtr *first);
976 static int
977 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
978                             xmlXPathStepOpPtr op,
979                             int isPredicate);
980
981 /************************************************************************
982  *                                                                      *
983  *                      Parser Type functions                           *
984  *                                                                      *
985  ************************************************************************/
986
987 /**
988  * xmlXPathNewCompExpr:
989  *
990  * Create a new Xpath component
991  *
992  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
993  */
994 static xmlXPathCompExprPtr
995 xmlXPathNewCompExpr(void) {
996     xmlXPathCompExprPtr cur;
997
998     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
999     if (cur == NULL) {
1000         xmlXPathErrMemory(NULL, "allocating component\n");
1001         return(NULL);
1002     }
1003     memset(cur, 0, sizeof(xmlXPathCompExpr));
1004     cur->maxStep = 10;
1005     cur->nbStep = 0;
1006     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1007                                            sizeof(xmlXPathStepOp));
1008     if (cur->steps == NULL) {
1009         xmlXPathErrMemory(NULL, "allocating steps\n");
1010         xmlFree(cur);
1011         return(NULL);
1012     }
1013     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1014     cur->last = -1;
1015 #ifdef DEBUG_EVAL_COUNTS
1016     cur->nb = 0;
1017 #endif
1018     return(cur);
1019 }
1020
1021 /**
1022  * xmlXPathFreeCompExpr:
1023  * @comp:  an XPATH comp
1024  *
1025  * Free up the memory allocated by @comp
1026  */
1027 void
1028 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1029 {
1030     xmlXPathStepOpPtr op;
1031     int i;
1032
1033     if (comp == NULL)
1034         return;
1035     if (comp->dict == NULL) {
1036         for (i = 0; i < comp->nbStep; i++) {
1037             op = &comp->steps[i];
1038             if (op->value4 != NULL) {
1039                 if (op->op == XPATH_OP_VALUE)
1040                     xmlXPathFreeObject(op->value4);
1041                 else
1042                     xmlFree(op->value4);
1043             }
1044             if (op->value5 != NULL)
1045                 xmlFree(op->value5);
1046         }
1047     } else {
1048         for (i = 0; i < comp->nbStep; i++) {
1049             op = &comp->steps[i];
1050             if (op->value4 != NULL) {
1051                 if (op->op == XPATH_OP_VALUE)
1052                     xmlXPathFreeObject(op->value4);
1053             }
1054         }
1055         xmlDictFree(comp->dict);
1056     }
1057     if (comp->steps != NULL) {
1058         xmlFree(comp->steps);
1059     }
1060 #ifdef DEBUG_EVAL_COUNTS
1061     if (comp->string != NULL) {
1062         xmlFree(comp->string);
1063     }
1064 #endif
1065 #ifdef XPATH_STREAMING
1066     if (comp->stream != NULL) {
1067         xmlFreePatternList(comp->stream);
1068     }
1069 #endif
1070     if (comp->expr != NULL) {
1071         xmlFree(comp->expr);
1072     }
1073
1074     xmlFree(comp);
1075 }
1076
1077 /**
1078  * xmlXPathCompExprAdd:
1079  * @comp:  the compiled expression
1080  * @ch1: first child index
1081  * @ch2: second child index
1082  * @op:  an op
1083  * @value:  the first int value
1084  * @value2:  the second int value
1085  * @value3:  the third int value
1086  * @value4:  the first string value
1087  * @value5:  the second string value
1088  *
1089  * Add a step to an XPath Compiled Expression
1090  *
1091  * Returns -1 in case of failure, the index otherwise
1092  */
1093 static int
1094 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1095    xmlXPathOp op, int value,
1096    int value2, int value3, void *value4, void *value5) {
1097     if (comp->nbStep >= comp->maxStep) {
1098         xmlXPathStepOp *real;
1099
1100         if (comp->maxStep >= XPATH_MAX_STEPS) {
1101             xmlXPathErrMemory(NULL, "adding step\n");
1102             return(-1);
1103         }
1104         comp->maxStep *= 2;
1105         real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1106                                       comp->maxStep * sizeof(xmlXPathStepOp));
1107         if (real == NULL) {
1108             comp->maxStep /= 2;
1109             xmlXPathErrMemory(NULL, "adding step\n");
1110             return(-1);
1111         }
1112         comp->steps = real;
1113     }
1114     comp->last = comp->nbStep;
1115     comp->steps[comp->nbStep].ch1 = ch1;
1116     comp->steps[comp->nbStep].ch2 = ch2;
1117     comp->steps[comp->nbStep].op = op;
1118     comp->steps[comp->nbStep].value = value;
1119     comp->steps[comp->nbStep].value2 = value2;
1120     comp->steps[comp->nbStep].value3 = value3;
1121     if ((comp->dict != NULL) &&
1122         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1123          (op == XPATH_OP_COLLECT))) {
1124         if (value4 != NULL) {
1125             comp->steps[comp->nbStep].value4 = (xmlChar *)
1126                 (void *)xmlDictLookup(comp->dict, value4, -1);
1127             xmlFree(value4);
1128         } else
1129             comp->steps[comp->nbStep].value4 = NULL;
1130         if (value5 != NULL) {
1131             comp->steps[comp->nbStep].value5 = (xmlChar *)
1132                 (void *)xmlDictLookup(comp->dict, value5, -1);
1133             xmlFree(value5);
1134         } else
1135             comp->steps[comp->nbStep].value5 = NULL;
1136     } else {
1137         comp->steps[comp->nbStep].value4 = value4;
1138         comp->steps[comp->nbStep].value5 = value5;
1139     }
1140     comp->steps[comp->nbStep].cache = NULL;
1141     return(comp->nbStep++);
1142 }
1143
1144 /**
1145  * xmlXPathCompSwap:
1146  * @comp:  the compiled expression
1147  * @op: operation index
1148  *
1149  * Swaps 2 operations in the compiled expression
1150  */
1151 static void
1152 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1153     int tmp;
1154
1155 #ifndef LIBXML_THREAD_ENABLED
1156     /*
1157      * Since this manipulates possibly shared variables, this is
1158      * disabled if one detects that the library is used in a multithreaded
1159      * application
1160      */
1161     if (xmlXPathDisableOptimizer)
1162         return;
1163 #endif
1164
1165     tmp = op->ch1;
1166     op->ch1 = op->ch2;
1167     op->ch2 = tmp;
1168 }
1169
1170 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)       \
1171     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),                       \
1172                         (op), (val), (val2), (val3), (val4), (val5))
1173 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)                 \
1174     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,               \
1175                         (op), (val), (val2), (val3), (val4), (val5))
1176
1177 #define PUSH_LEAVE_EXPR(op, val, val2)                                  \
1178 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1179
1180 #define PUSH_UNARY_EXPR(op, ch, val, val2)                              \
1181 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1182
1183 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)                       \
1184 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),                     \
1185                         (val), (val2), 0 ,NULL ,NULL)
1186
1187 /************************************************************************
1188  *                                                                      *
1189  *              XPath object cache structures                           *
1190  *                                                                      *
1191  ************************************************************************/
1192
1193 /* #define XP_DEFAULT_CACHE_ON */
1194
1195 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1196
1197 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1198 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1199 struct _xmlXPathContextCache {
1200     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1201     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1202     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1203     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1204     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1205     int maxNodeset;
1206     int maxString;
1207     int maxBoolean;
1208     int maxNumber;
1209     int maxMisc;
1210 #ifdef XP_DEBUG_OBJ_USAGE
1211     int dbgCachedAll;
1212     int dbgCachedNodeset;
1213     int dbgCachedString;
1214     int dbgCachedBool;
1215     int dbgCachedNumber;
1216     int dbgCachedPoint;
1217     int dbgCachedRange;
1218     int dbgCachedLocset;
1219     int dbgCachedUsers;
1220     int dbgCachedXSLTTree;
1221     int dbgCachedUndefined;
1222
1223
1224     int dbgReusedAll;
1225     int dbgReusedNodeset;
1226     int dbgReusedString;
1227     int dbgReusedBool;
1228     int dbgReusedNumber;
1229     int dbgReusedPoint;
1230     int dbgReusedRange;
1231     int dbgReusedLocset;
1232     int dbgReusedUsers;
1233     int dbgReusedXSLTTree;
1234     int dbgReusedUndefined;
1235
1236 #endif
1237 };
1238
1239 /************************************************************************
1240  *                                                                      *
1241  *              Debugging related functions                             *
1242  *                                                                      *
1243  ************************************************************************/
1244
1245 #define STRANGE                                                 \
1246     xmlGenericError(xmlGenericErrorContext,                             \
1247             "Internal error at %s:%d\n",                                \
1248             __FILE__, __LINE__);
1249
1250 #ifdef LIBXML_DEBUG_ENABLED
1251 static void
1252 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1253     int i;
1254     char shift[100];
1255
1256     for (i = 0;((i < depth) && (i < 25));i++)
1257         shift[2 * i] = shift[2 * i + 1] = ' ';
1258     shift[2 * i] = shift[2 * i + 1] = 0;
1259     if (cur == NULL) {
1260         fprintf(output, "%s", shift);
1261         fprintf(output, "Node is NULL !\n");
1262         return;
1263
1264     }
1265
1266     if ((cur->type == XML_DOCUMENT_NODE) ||
1267              (cur->type == XML_HTML_DOCUMENT_NODE)) {
1268         fprintf(output, "%s", shift);
1269         fprintf(output, " /\n");
1270     } else if (cur->type == XML_ATTRIBUTE_NODE)
1271         xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1272     else
1273         xmlDebugDumpOneNode(output, cur, depth);
1274 }
1275 static void
1276 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1277     xmlNodePtr tmp;
1278     int i;
1279     char shift[100];
1280
1281     for (i = 0;((i < depth) && (i < 25));i++)
1282         shift[2 * i] = shift[2 * i + 1] = ' ';
1283     shift[2 * i] = shift[2 * i + 1] = 0;
1284     if (cur == NULL) {
1285         fprintf(output, "%s", shift);
1286         fprintf(output, "Node is NULL !\n");
1287         return;
1288
1289     }
1290
1291     while (cur != NULL) {
1292         tmp = cur;
1293         cur = cur->next;
1294         xmlDebugDumpOneNode(output, tmp, depth);
1295     }
1296 }
1297
1298 static void
1299 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1300     int i;
1301     char shift[100];
1302
1303     for (i = 0;((i < depth) && (i < 25));i++)
1304         shift[2 * i] = shift[2 * i + 1] = ' ';
1305     shift[2 * i] = shift[2 * i + 1] = 0;
1306
1307     if (cur == NULL) {
1308         fprintf(output, "%s", shift);
1309         fprintf(output, "NodeSet is NULL !\n");
1310         return;
1311
1312     }
1313
1314     if (cur != NULL) {
1315         fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1316         for (i = 0;i < cur->nodeNr;i++) {
1317             fprintf(output, "%s", shift);
1318             fprintf(output, "%d", i + 1);
1319             xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1320         }
1321     }
1322 }
1323
1324 static void
1325 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1326     int i;
1327     char shift[100];
1328
1329     for (i = 0;((i < depth) && (i < 25));i++)
1330         shift[2 * i] = shift[2 * i + 1] = ' ';
1331     shift[2 * i] = shift[2 * i + 1] = 0;
1332
1333     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1334         fprintf(output, "%s", shift);
1335         fprintf(output, "Value Tree is NULL !\n");
1336         return;
1337
1338     }
1339
1340     fprintf(output, "%s", shift);
1341     fprintf(output, "%d", i + 1);
1342     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1343 }
1344 #if defined(LIBXML_XPTR_ENABLED)
1345 static void
1346 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1347     int i;
1348     char shift[100];
1349
1350     for (i = 0;((i < depth) && (i < 25));i++)
1351         shift[2 * i] = shift[2 * i + 1] = ' ';
1352     shift[2 * i] = shift[2 * i + 1] = 0;
1353
1354     if (cur == NULL) {
1355         fprintf(output, "%s", shift);
1356         fprintf(output, "LocationSet is NULL !\n");
1357         return;
1358
1359     }
1360
1361     for (i = 0;i < cur->locNr;i++) {
1362         fprintf(output, "%s", shift);
1363         fprintf(output, "%d : ", i + 1);
1364         xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1365     }
1366 }
1367 #endif /* LIBXML_XPTR_ENABLED */
1368
1369 /**
1370  * xmlXPathDebugDumpObject:
1371  * @output:  the FILE * to dump the output
1372  * @cur:  the object to inspect
1373  * @depth:  indentation level
1374  *
1375  * Dump the content of the object for debugging purposes
1376  */
1377 void
1378 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1379     int i;
1380     char shift[100];
1381
1382     if (output == NULL) return;
1383
1384     for (i = 0;((i < depth) && (i < 25));i++)
1385         shift[2 * i] = shift[2 * i + 1] = ' ';
1386     shift[2 * i] = shift[2 * i + 1] = 0;
1387
1388
1389     fprintf(output, "%s", shift);
1390
1391     if (cur == NULL) {
1392         fprintf(output, "Object is empty (NULL)\n");
1393         return;
1394     }
1395     switch(cur->type) {
1396         case XPATH_UNDEFINED:
1397             fprintf(output, "Object is uninitialized\n");
1398             break;
1399         case XPATH_NODESET:
1400             fprintf(output, "Object is a Node Set :\n");
1401             xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1402             break;
1403         case XPATH_XSLT_TREE:
1404             fprintf(output, "Object is an XSLT value tree :\n");
1405             xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1406             break;
1407         case XPATH_BOOLEAN:
1408             fprintf(output, "Object is a Boolean : ");
1409             if (cur->boolval) fprintf(output, "true\n");
1410             else fprintf(output, "false\n");
1411             break;
1412         case XPATH_NUMBER:
1413             switch (xmlXPathIsInf(cur->floatval)) {
1414             case 1:
1415                 fprintf(output, "Object is a number : Infinity\n");
1416                 break;
1417             case -1:
1418                 fprintf(output, "Object is a number : -Infinity\n");
1419                 break;
1420             default:
1421                 if (xmlXPathIsNaN(cur->floatval)) {
1422                     fprintf(output, "Object is a number : NaN\n");
1423                 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1424                     fprintf(output, "Object is a number : 0\n");
1425                 } else {
1426                     fprintf(output, "Object is a number : %0g\n", cur->floatval);
1427                 }
1428             }
1429             break;
1430         case XPATH_STRING:
1431             fprintf(output, "Object is a string : ");
1432             xmlDebugDumpString(output, cur->stringval);
1433             fprintf(output, "\n");
1434             break;
1435         case XPATH_POINT:
1436             fprintf(output, "Object is a point : index %d in node", cur->index);
1437             xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1438             fprintf(output, "\n");
1439             break;
1440         case XPATH_RANGE:
1441             if ((cur->user2 == NULL) ||
1442                 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1443                 fprintf(output, "Object is a collapsed range :\n");
1444                 fprintf(output, "%s", shift);
1445                 if (cur->index >= 0)
1446                     fprintf(output, "index %d in ", cur->index);
1447                 fprintf(output, "node\n");
1448                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1449                                       depth + 1);
1450             } else  {
1451                 fprintf(output, "Object is a range :\n");
1452                 fprintf(output, "%s", shift);
1453                 fprintf(output, "From ");
1454                 if (cur->index >= 0)
1455                     fprintf(output, "index %d in ", cur->index);
1456                 fprintf(output, "node\n");
1457                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1458                                       depth + 1);
1459                 fprintf(output, "%s", shift);
1460                 fprintf(output, "To ");
1461                 if (cur->index2 >= 0)
1462                     fprintf(output, "index %d in ", cur->index2);
1463                 fprintf(output, "node\n");
1464                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1465                                       depth + 1);
1466                 fprintf(output, "\n");
1467             }
1468             break;
1469         case XPATH_LOCATIONSET:
1470 #if defined(LIBXML_XPTR_ENABLED)
1471             fprintf(output, "Object is a Location Set:\n");
1472             xmlXPathDebugDumpLocationSet(output,
1473                     (xmlLocationSetPtr) cur->user, depth);
1474 #endif
1475             break;
1476         case XPATH_USERS:
1477             fprintf(output, "Object is user defined\n");
1478             break;
1479     }
1480 }
1481
1482 static void
1483 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1484                              xmlXPathStepOpPtr op, int depth) {
1485     int i;
1486     char shift[100];
1487
1488     for (i = 0;((i < depth) && (i < 25));i++)
1489         shift[2 * i] = shift[2 * i + 1] = ' ';
1490     shift[2 * i] = shift[2 * i + 1] = 0;
1491
1492     fprintf(output, "%s", shift);
1493     if (op == NULL) {
1494         fprintf(output, "Step is NULL\n");
1495         return;
1496     }
1497     switch (op->op) {
1498         case XPATH_OP_END:
1499             fprintf(output, "END"); break;
1500         case XPATH_OP_AND:
1501             fprintf(output, "AND"); break;
1502         case XPATH_OP_OR:
1503             fprintf(output, "OR"); break;
1504         case XPATH_OP_EQUAL:
1505              if (op->value)
1506                  fprintf(output, "EQUAL =");
1507              else
1508                  fprintf(output, "EQUAL !=");
1509              break;
1510         case XPATH_OP_CMP:
1511              if (op->value)
1512                  fprintf(output, "CMP <");
1513              else
1514                  fprintf(output, "CMP >");
1515              if (!op->value2)
1516                  fprintf(output, "=");
1517              break;
1518         case XPATH_OP_PLUS:
1519              if (op->value == 0)
1520                  fprintf(output, "PLUS -");
1521              else if (op->value == 1)
1522                  fprintf(output, "PLUS +");
1523              else if (op->value == 2)
1524                  fprintf(output, "PLUS unary -");
1525              else if (op->value == 3)
1526                  fprintf(output, "PLUS unary - -");
1527              break;
1528         case XPATH_OP_MULT:
1529              if (op->value == 0)
1530                  fprintf(output, "MULT *");
1531              else if (op->value == 1)
1532                  fprintf(output, "MULT div");
1533              else
1534                  fprintf(output, "MULT mod");
1535              break;
1536         case XPATH_OP_UNION:
1537              fprintf(output, "UNION"); break;
1538         case XPATH_OP_ROOT:
1539              fprintf(output, "ROOT"); break;
1540         case XPATH_OP_NODE:
1541              fprintf(output, "NODE"); break;
1542         case XPATH_OP_RESET:
1543              fprintf(output, "RESET"); break;
1544         case XPATH_OP_SORT:
1545              fprintf(output, "SORT"); break;
1546         case XPATH_OP_COLLECT: {
1547             xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1548             xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1549             xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1550             const xmlChar *prefix = op->value4;
1551             const xmlChar *name = op->value5;
1552
1553             fprintf(output, "COLLECT ");
1554             switch (axis) {
1555                 case AXIS_ANCESTOR:
1556                     fprintf(output, " 'ancestors' "); break;
1557                 case AXIS_ANCESTOR_OR_SELF:
1558                     fprintf(output, " 'ancestors-or-self' "); break;
1559                 case AXIS_ATTRIBUTE:
1560                     fprintf(output, " 'attributes' "); break;
1561                 case AXIS_CHILD:
1562                     fprintf(output, " 'child' "); break;
1563                 case AXIS_DESCENDANT:
1564                     fprintf(output, " 'descendant' "); break;
1565                 case AXIS_DESCENDANT_OR_SELF:
1566                     fprintf(output, " 'descendant-or-self' "); break;
1567                 case AXIS_FOLLOWING:
1568                     fprintf(output, " 'following' "); break;
1569                 case AXIS_FOLLOWING_SIBLING:
1570                     fprintf(output, " 'following-siblings' "); break;
1571                 case AXIS_NAMESPACE:
1572                     fprintf(output, " 'namespace' "); break;
1573                 case AXIS_PARENT:
1574                     fprintf(output, " 'parent' "); break;
1575                 case AXIS_PRECEDING:
1576                     fprintf(output, " 'preceding' "); break;
1577                 case AXIS_PRECEDING_SIBLING:
1578                     fprintf(output, " 'preceding-sibling' "); break;
1579                 case AXIS_SELF:
1580                     fprintf(output, " 'self' "); break;
1581             }
1582             switch (test) {
1583                 case NODE_TEST_NONE:
1584                     fprintf(output, "'none' "); break;
1585                 case NODE_TEST_TYPE:
1586                     fprintf(output, "'type' "); break;
1587                 case NODE_TEST_PI:
1588                     fprintf(output, "'PI' "); break;
1589                 case NODE_TEST_ALL:
1590                     fprintf(output, "'all' "); break;
1591                 case NODE_TEST_NS:
1592                     fprintf(output, "'namespace' "); break;
1593                 case NODE_TEST_NAME:
1594                     fprintf(output, "'name' "); break;
1595             }
1596             switch (type) {
1597                 case NODE_TYPE_NODE:
1598                     fprintf(output, "'node' "); break;
1599                 case NODE_TYPE_COMMENT:
1600                     fprintf(output, "'comment' "); break;
1601                 case NODE_TYPE_TEXT:
1602                     fprintf(output, "'text' "); break;
1603                 case NODE_TYPE_PI:
1604                     fprintf(output, "'PI' "); break;
1605             }
1606             if (prefix != NULL)
1607                 fprintf(output, "%s:", prefix);
1608             if (name != NULL)
1609                 fprintf(output, "%s", (const char *) name);
1610             break;
1611
1612         }
1613         case XPATH_OP_VALUE: {
1614             xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1615
1616             fprintf(output, "ELEM ");
1617             xmlXPathDebugDumpObject(output, object, 0);
1618             goto finish;
1619         }
1620         case XPATH_OP_VARIABLE: {
1621             const xmlChar *prefix = op->value5;
1622             const xmlChar *name = op->value4;
1623
1624             if (prefix != NULL)
1625                 fprintf(output, "VARIABLE %s:%s", prefix, name);
1626             else
1627                 fprintf(output, "VARIABLE %s", name);
1628             break;
1629         }
1630         case XPATH_OP_FUNCTION: {
1631             int nbargs = op->value;
1632             const xmlChar *prefix = op->value5;
1633             const xmlChar *name = op->value4;
1634
1635             if (prefix != NULL)
1636                 fprintf(output, "FUNCTION %s:%s(%d args)",
1637                         prefix, name, nbargs);
1638             else
1639                 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1640             break;
1641         }
1642         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1643         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1644         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1645 #ifdef LIBXML_XPTR_ENABLED
1646         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1647 #endif
1648         default:
1649         fprintf(output, "UNKNOWN %d\n", op->op); return;
1650     }
1651     fprintf(output, "\n");
1652 finish:
1653     if (op->ch1 >= 0)
1654         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1655     if (op->ch2 >= 0)
1656         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1657 }
1658
1659 /**
1660  * xmlXPathDebugDumpCompExpr:
1661  * @output:  the FILE * for the output
1662  * @comp:  the precompiled XPath expression
1663  * @depth:  the indentation level.
1664  *
1665  * Dumps the tree of the compiled XPath expression.
1666  */
1667 void
1668 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1669                           int depth) {
1670     int i;
1671     char shift[100];
1672
1673     if ((output == NULL) || (comp == NULL)) return;
1674
1675     for (i = 0;((i < depth) && (i < 25));i++)
1676         shift[2 * i] = shift[2 * i + 1] = ' ';
1677     shift[2 * i] = shift[2 * i + 1] = 0;
1678
1679     fprintf(output, "%s", shift);
1680
1681 #ifdef XPATH_STREAMING
1682     if (comp->stream) {
1683         fprintf(output, "Streaming Expression\n");
1684     } else
1685 #endif
1686     {
1687         fprintf(output, "Compiled Expression : %d elements\n",
1688                 comp->nbStep);
1689         i = comp->last;
1690         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1691     }
1692 }
1693
1694 #ifdef XP_DEBUG_OBJ_USAGE
1695
1696 /*
1697 * XPath object usage related debugging variables.
1698 */
1699 static int xmlXPathDebugObjCounterUndefined = 0;
1700 static int xmlXPathDebugObjCounterNodeset = 0;
1701 static int xmlXPathDebugObjCounterBool = 0;
1702 static int xmlXPathDebugObjCounterNumber = 0;
1703 static int xmlXPathDebugObjCounterString = 0;
1704 static int xmlXPathDebugObjCounterPoint = 0;
1705 static int xmlXPathDebugObjCounterRange = 0;
1706 static int xmlXPathDebugObjCounterLocset = 0;
1707 static int xmlXPathDebugObjCounterUsers = 0;
1708 static int xmlXPathDebugObjCounterXSLTTree = 0;
1709 static int xmlXPathDebugObjCounterAll = 0;
1710
1711 static int xmlXPathDebugObjTotalUndefined = 0;
1712 static int xmlXPathDebugObjTotalNodeset = 0;
1713 static int xmlXPathDebugObjTotalBool = 0;
1714 static int xmlXPathDebugObjTotalNumber = 0;
1715 static int xmlXPathDebugObjTotalString = 0;
1716 static int xmlXPathDebugObjTotalPoint = 0;
1717 static int xmlXPathDebugObjTotalRange = 0;
1718 static int xmlXPathDebugObjTotalLocset = 0;
1719 static int xmlXPathDebugObjTotalUsers = 0;
1720 static int xmlXPathDebugObjTotalXSLTTree = 0;
1721 static int xmlXPathDebugObjTotalAll = 0;
1722
1723 static int xmlXPathDebugObjMaxUndefined = 0;
1724 static int xmlXPathDebugObjMaxNodeset = 0;
1725 static int xmlXPathDebugObjMaxBool = 0;
1726 static int xmlXPathDebugObjMaxNumber = 0;
1727 static int xmlXPathDebugObjMaxString = 0;
1728 static int xmlXPathDebugObjMaxPoint = 0;
1729 static int xmlXPathDebugObjMaxRange = 0;
1730 static int xmlXPathDebugObjMaxLocset = 0;
1731 static int xmlXPathDebugObjMaxUsers = 0;
1732 static int xmlXPathDebugObjMaxXSLTTree = 0;
1733 static int xmlXPathDebugObjMaxAll = 0;
1734
1735 /* REVISIT TODO: Make this static when committing */
1736 static void
1737 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1738 {
1739     if (ctxt != NULL) {
1740         if (ctxt->cache != NULL) {
1741             xmlXPathContextCachePtr cache =
1742                 (xmlXPathContextCachePtr) ctxt->cache;
1743
1744             cache->dbgCachedAll = 0;
1745             cache->dbgCachedNodeset = 0;
1746             cache->dbgCachedString = 0;
1747             cache->dbgCachedBool = 0;
1748             cache->dbgCachedNumber = 0;
1749             cache->dbgCachedPoint = 0;
1750             cache->dbgCachedRange = 0;
1751             cache->dbgCachedLocset = 0;
1752             cache->dbgCachedUsers = 0;
1753             cache->dbgCachedXSLTTree = 0;
1754             cache->dbgCachedUndefined = 0;
1755
1756             cache->dbgReusedAll = 0;
1757             cache->dbgReusedNodeset = 0;
1758             cache->dbgReusedString = 0;
1759             cache->dbgReusedBool = 0;
1760             cache->dbgReusedNumber = 0;
1761             cache->dbgReusedPoint = 0;
1762             cache->dbgReusedRange = 0;
1763             cache->dbgReusedLocset = 0;
1764             cache->dbgReusedUsers = 0;
1765             cache->dbgReusedXSLTTree = 0;
1766             cache->dbgReusedUndefined = 0;
1767         }
1768     }
1769
1770     xmlXPathDebugObjCounterUndefined = 0;
1771     xmlXPathDebugObjCounterNodeset = 0;
1772     xmlXPathDebugObjCounterBool = 0;
1773     xmlXPathDebugObjCounterNumber = 0;
1774     xmlXPathDebugObjCounterString = 0;
1775     xmlXPathDebugObjCounterPoint = 0;
1776     xmlXPathDebugObjCounterRange = 0;
1777     xmlXPathDebugObjCounterLocset = 0;
1778     xmlXPathDebugObjCounterUsers = 0;
1779     xmlXPathDebugObjCounterXSLTTree = 0;
1780     xmlXPathDebugObjCounterAll = 0;
1781
1782     xmlXPathDebugObjTotalUndefined = 0;
1783     xmlXPathDebugObjTotalNodeset = 0;
1784     xmlXPathDebugObjTotalBool = 0;
1785     xmlXPathDebugObjTotalNumber = 0;
1786     xmlXPathDebugObjTotalString = 0;
1787     xmlXPathDebugObjTotalPoint = 0;
1788     xmlXPathDebugObjTotalRange = 0;
1789     xmlXPathDebugObjTotalLocset = 0;
1790     xmlXPathDebugObjTotalUsers = 0;
1791     xmlXPathDebugObjTotalXSLTTree = 0;
1792     xmlXPathDebugObjTotalAll = 0;
1793
1794     xmlXPathDebugObjMaxUndefined = 0;
1795     xmlXPathDebugObjMaxNodeset = 0;
1796     xmlXPathDebugObjMaxBool = 0;
1797     xmlXPathDebugObjMaxNumber = 0;
1798     xmlXPathDebugObjMaxString = 0;
1799     xmlXPathDebugObjMaxPoint = 0;
1800     xmlXPathDebugObjMaxRange = 0;
1801     xmlXPathDebugObjMaxLocset = 0;
1802     xmlXPathDebugObjMaxUsers = 0;
1803     xmlXPathDebugObjMaxXSLTTree = 0;
1804     xmlXPathDebugObjMaxAll = 0;
1805
1806 }
1807
1808 static void
1809 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1810                               xmlXPathObjectType objType)
1811 {
1812     int isCached = 0;
1813
1814     if (ctxt != NULL) {
1815         if (ctxt->cache != NULL) {
1816             xmlXPathContextCachePtr cache =
1817                 (xmlXPathContextCachePtr) ctxt->cache;
1818
1819             isCached = 1;
1820
1821             cache->dbgReusedAll++;
1822             switch (objType) {
1823                 case XPATH_UNDEFINED:
1824                     cache->dbgReusedUndefined++;
1825                     break;
1826                 case XPATH_NODESET:
1827                     cache->dbgReusedNodeset++;
1828                     break;
1829                 case XPATH_BOOLEAN:
1830                     cache->dbgReusedBool++;
1831                     break;
1832                 case XPATH_NUMBER:
1833                     cache->dbgReusedNumber++;
1834                     break;
1835                 case XPATH_STRING:
1836                     cache->dbgReusedString++;
1837                     break;
1838                 case XPATH_POINT:
1839                     cache->dbgReusedPoint++;
1840                     break;
1841                 case XPATH_RANGE:
1842                     cache->dbgReusedRange++;
1843                     break;
1844                 case XPATH_LOCATIONSET:
1845                     cache->dbgReusedLocset++;
1846                     break;
1847                 case XPATH_USERS:
1848                     cache->dbgReusedUsers++;
1849                     break;
1850                 case XPATH_XSLT_TREE:
1851                     cache->dbgReusedXSLTTree++;
1852                     break;
1853                 default:
1854                     break;
1855             }
1856         }
1857     }
1858
1859     switch (objType) {
1860         case XPATH_UNDEFINED:
1861             if (! isCached)
1862                 xmlXPathDebugObjTotalUndefined++;
1863             xmlXPathDebugObjCounterUndefined++;
1864             if (xmlXPathDebugObjCounterUndefined >
1865                 xmlXPathDebugObjMaxUndefined)
1866                 xmlXPathDebugObjMaxUndefined =
1867                     xmlXPathDebugObjCounterUndefined;
1868             break;
1869         case XPATH_NODESET:
1870             if (! isCached)
1871                 xmlXPathDebugObjTotalNodeset++;
1872             xmlXPathDebugObjCounterNodeset++;
1873             if (xmlXPathDebugObjCounterNodeset >
1874                 xmlXPathDebugObjMaxNodeset)
1875                 xmlXPathDebugObjMaxNodeset =
1876                     xmlXPathDebugObjCounterNodeset;
1877             break;
1878         case XPATH_BOOLEAN:
1879             if (! isCached)
1880                 xmlXPathDebugObjTotalBool++;
1881             xmlXPathDebugObjCounterBool++;
1882             if (xmlXPathDebugObjCounterBool >
1883                 xmlXPathDebugObjMaxBool)
1884                 xmlXPathDebugObjMaxBool =
1885                     xmlXPathDebugObjCounterBool;
1886             break;
1887         case XPATH_NUMBER:
1888             if (! isCached)
1889                 xmlXPathDebugObjTotalNumber++;
1890             xmlXPathDebugObjCounterNumber++;
1891             if (xmlXPathDebugObjCounterNumber >
1892                 xmlXPathDebugObjMaxNumber)
1893                 xmlXPathDebugObjMaxNumber =
1894                     xmlXPathDebugObjCounterNumber;
1895             break;
1896         case XPATH_STRING:
1897             if (! isCached)
1898                 xmlXPathDebugObjTotalString++;
1899             xmlXPathDebugObjCounterString++;
1900             if (xmlXPathDebugObjCounterString >
1901                 xmlXPathDebugObjMaxString)
1902                 xmlXPathDebugObjMaxString =
1903                     xmlXPathDebugObjCounterString;
1904             break;
1905         case XPATH_POINT:
1906             if (! isCached)
1907                 xmlXPathDebugObjTotalPoint++;
1908             xmlXPathDebugObjCounterPoint++;
1909             if (xmlXPathDebugObjCounterPoint >
1910                 xmlXPathDebugObjMaxPoint)
1911                 xmlXPathDebugObjMaxPoint =
1912                     xmlXPathDebugObjCounterPoint;
1913             break;
1914         case XPATH_RANGE:
1915             if (! isCached)
1916                 xmlXPathDebugObjTotalRange++;
1917             xmlXPathDebugObjCounterRange++;
1918             if (xmlXPathDebugObjCounterRange >
1919                 xmlXPathDebugObjMaxRange)
1920                 xmlXPathDebugObjMaxRange =
1921                     xmlXPathDebugObjCounterRange;
1922             break;
1923         case XPATH_LOCATIONSET:
1924             if (! isCached)
1925                 xmlXPathDebugObjTotalLocset++;
1926             xmlXPathDebugObjCounterLocset++;
1927             if (xmlXPathDebugObjCounterLocset >
1928                 xmlXPathDebugObjMaxLocset)
1929                 xmlXPathDebugObjMaxLocset =
1930                     xmlXPathDebugObjCounterLocset;
1931             break;
1932         case XPATH_USERS:
1933             if (! isCached)
1934                 xmlXPathDebugObjTotalUsers++;
1935             xmlXPathDebugObjCounterUsers++;
1936             if (xmlXPathDebugObjCounterUsers >
1937                 xmlXPathDebugObjMaxUsers)
1938                 xmlXPathDebugObjMaxUsers =
1939                     xmlXPathDebugObjCounterUsers;
1940             break;
1941         case XPATH_XSLT_TREE:
1942             if (! isCached)
1943                 xmlXPathDebugObjTotalXSLTTree++;
1944             xmlXPathDebugObjCounterXSLTTree++;
1945             if (xmlXPathDebugObjCounterXSLTTree >
1946                 xmlXPathDebugObjMaxXSLTTree)
1947                 xmlXPathDebugObjMaxXSLTTree =
1948                     xmlXPathDebugObjCounterXSLTTree;
1949             break;
1950         default:
1951             break;
1952     }
1953     if (! isCached)
1954         xmlXPathDebugObjTotalAll++;
1955     xmlXPathDebugObjCounterAll++;
1956     if (xmlXPathDebugObjCounterAll >
1957         xmlXPathDebugObjMaxAll)
1958         xmlXPathDebugObjMaxAll =
1959             xmlXPathDebugObjCounterAll;
1960 }
1961
1962 static void
1963 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1964                               xmlXPathObjectType objType)
1965 {
1966     int isCached = 0;
1967
1968     if (ctxt != NULL) {
1969         if (ctxt->cache != NULL) {
1970             xmlXPathContextCachePtr cache =
1971                 (xmlXPathContextCachePtr) ctxt->cache;
1972
1973             isCached = 1;
1974
1975             cache->dbgCachedAll++;
1976             switch (objType) {
1977                 case XPATH_UNDEFINED:
1978                     cache->dbgCachedUndefined++;
1979                     break;
1980                 case XPATH_NODESET:
1981                     cache->dbgCachedNodeset++;
1982                     break;
1983                 case XPATH_BOOLEAN:
1984                     cache->dbgCachedBool++;
1985                     break;
1986                 case XPATH_NUMBER:
1987                     cache->dbgCachedNumber++;
1988                     break;
1989                 case XPATH_STRING:
1990                     cache->dbgCachedString++;
1991                     break;
1992                 case XPATH_POINT:
1993                     cache->dbgCachedPoint++;
1994                     break;
1995                 case XPATH_RANGE:
1996                     cache->dbgCachedRange++;
1997                     break;
1998                 case XPATH_LOCATIONSET:
1999                     cache->dbgCachedLocset++;
2000                     break;
2001                 case XPATH_USERS:
2002                     cache->dbgCachedUsers++;
2003                     break;
2004                 case XPATH_XSLT_TREE:
2005                     cache->dbgCachedXSLTTree++;
2006                     break;
2007                 default:
2008                     break;
2009             }
2010
2011         }
2012     }
2013     switch (objType) {
2014         case XPATH_UNDEFINED:
2015             xmlXPathDebugObjCounterUndefined--;
2016             break;
2017         case XPATH_NODESET:
2018             xmlXPathDebugObjCounterNodeset--;
2019             break;
2020         case XPATH_BOOLEAN:
2021             xmlXPathDebugObjCounterBool--;
2022             break;
2023         case XPATH_NUMBER:
2024             xmlXPathDebugObjCounterNumber--;
2025             break;
2026         case XPATH_STRING:
2027             xmlXPathDebugObjCounterString--;
2028             break;
2029         case XPATH_POINT:
2030             xmlXPathDebugObjCounterPoint--;
2031             break;
2032         case XPATH_RANGE:
2033             xmlXPathDebugObjCounterRange--;
2034             break;
2035         case XPATH_LOCATIONSET:
2036             xmlXPathDebugObjCounterLocset--;
2037             break;
2038         case XPATH_USERS:
2039             xmlXPathDebugObjCounterUsers--;
2040             break;
2041         case XPATH_XSLT_TREE:
2042             xmlXPathDebugObjCounterXSLTTree--;
2043             break;
2044         default:
2045             break;
2046     }
2047     xmlXPathDebugObjCounterAll--;
2048 }
2049
2050 /* REVISIT TODO: Make this static when committing */
2051 static void
2052 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2053 {
2054     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2055         reqXSLTTree, reqUndefined;
2056     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2057         caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2058     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2059         reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2060     int leftObjs = xmlXPathDebugObjCounterAll;
2061
2062     reqAll = xmlXPathDebugObjTotalAll;
2063     reqNodeset = xmlXPathDebugObjTotalNodeset;
2064     reqString = xmlXPathDebugObjTotalString;
2065     reqBool = xmlXPathDebugObjTotalBool;
2066     reqNumber = xmlXPathDebugObjTotalNumber;
2067     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2068     reqUndefined = xmlXPathDebugObjTotalUndefined;
2069
2070     printf("# XPath object usage:\n");
2071
2072     if (ctxt != NULL) {
2073         if (ctxt->cache != NULL) {
2074             xmlXPathContextCachePtr cache =
2075                 (xmlXPathContextCachePtr) ctxt->cache;
2076
2077             reAll = cache->dbgReusedAll;
2078             reqAll += reAll;
2079             reNodeset = cache->dbgReusedNodeset;
2080             reqNodeset += reNodeset;
2081             reString = cache->dbgReusedString;
2082             reqString += reString;
2083             reBool = cache->dbgReusedBool;
2084             reqBool += reBool;
2085             reNumber = cache->dbgReusedNumber;
2086             reqNumber += reNumber;
2087             reXSLTTree = cache->dbgReusedXSLTTree;
2088             reqXSLTTree += reXSLTTree;
2089             reUndefined = cache->dbgReusedUndefined;
2090             reqUndefined += reUndefined;
2091
2092             caAll = cache->dbgCachedAll;
2093             caBool = cache->dbgCachedBool;
2094             caNodeset = cache->dbgCachedNodeset;
2095             caString = cache->dbgCachedString;
2096             caNumber = cache->dbgCachedNumber;
2097             caXSLTTree = cache->dbgCachedXSLTTree;
2098             caUndefined = cache->dbgCachedUndefined;
2099
2100             if (cache->nodesetObjs)
2101                 leftObjs -= cache->nodesetObjs->number;
2102             if (cache->stringObjs)
2103                 leftObjs -= cache->stringObjs->number;
2104             if (cache->booleanObjs)
2105                 leftObjs -= cache->booleanObjs->number;
2106             if (cache->numberObjs)
2107                 leftObjs -= cache->numberObjs->number;
2108             if (cache->miscObjs)
2109                 leftObjs -= cache->miscObjs->number;
2110         }
2111     }
2112
2113     printf("# all\n");
2114     printf("#   total  : %d\n", reqAll);
2115     printf("#   left  : %d\n", leftObjs);
2116     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2117     printf("#   reused : %d\n", reAll);
2118     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2119
2120     printf("# node-sets\n");
2121     printf("#   total  : %d\n", reqNodeset);
2122     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2123     printf("#   reused : %d\n", reNodeset);
2124     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2125
2126     printf("# strings\n");
2127     printf("#   total  : %d\n", reqString);
2128     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2129     printf("#   reused : %d\n", reString);
2130     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2131
2132     printf("# booleans\n");
2133     printf("#   total  : %d\n", reqBool);
2134     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2135     printf("#   reused : %d\n", reBool);
2136     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2137
2138     printf("# numbers\n");
2139     printf("#   total  : %d\n", reqNumber);
2140     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2141     printf("#   reused : %d\n", reNumber);
2142     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2143
2144     printf("# XSLT result tree fragments\n");
2145     printf("#   total  : %d\n", reqXSLTTree);
2146     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2147     printf("#   reused : %d\n", reXSLTTree);
2148     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2149
2150     printf("# undefined\n");
2151     printf("#   total  : %d\n", reqUndefined);
2152     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2153     printf("#   reused : %d\n", reUndefined);
2154     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2155
2156 }
2157
2158 #endif /* XP_DEBUG_OBJ_USAGE */
2159
2160 #endif /* LIBXML_DEBUG_ENABLED */
2161
2162 /************************************************************************
2163  *                                                                      *
2164  *                      XPath object caching                            *
2165  *                                                                      *
2166  ************************************************************************/
2167
2168 /**
2169  * xmlXPathNewCache:
2170  *
2171  * Create a new object cache
2172  *
2173  * Returns the xmlXPathCache just allocated.
2174  */
2175 static xmlXPathContextCachePtr
2176 xmlXPathNewCache(void)
2177 {
2178     xmlXPathContextCachePtr ret;
2179
2180     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2181     if (ret == NULL) {
2182         xmlXPathErrMemory(NULL, "creating object cache\n");
2183         return(NULL);
2184     }
2185     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2186     ret->maxNodeset = 100;
2187     ret->maxString = 100;
2188     ret->maxBoolean = 100;
2189     ret->maxNumber = 100;
2190     ret->maxMisc = 100;
2191     return(ret);
2192 }
2193
2194 static void
2195 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2196 {
2197     int i;
2198     xmlXPathObjectPtr obj;
2199
2200     if (list == NULL)
2201         return;
2202
2203     for (i = 0; i < list->number; i++) {
2204         obj = list->items[i];
2205         /*
2206         * Note that it is already assured that we don't need to
2207         * look out for namespace nodes in the node-set.
2208         */
2209         if (obj->nodesetval != NULL) {
2210             if (obj->nodesetval->nodeTab != NULL)
2211                 xmlFree(obj->nodesetval->nodeTab);
2212             xmlFree(obj->nodesetval);
2213         }
2214         xmlFree(obj);
2215 #ifdef XP_DEBUG_OBJ_USAGE
2216         xmlXPathDebugObjCounterAll--;
2217 #endif
2218     }
2219     xmlPointerListFree(list);
2220 }
2221
2222 static void
2223 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2224 {
2225     if (cache == NULL)
2226         return;
2227     if (cache->nodesetObjs)
2228         xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2229     if (cache->stringObjs)
2230         xmlXPathCacheFreeObjectList(cache->stringObjs);
2231     if (cache->booleanObjs)
2232         xmlXPathCacheFreeObjectList(cache->booleanObjs);
2233     if (cache->numberObjs)
2234         xmlXPathCacheFreeObjectList(cache->numberObjs);
2235     if (cache->miscObjs)
2236         xmlXPathCacheFreeObjectList(cache->miscObjs);
2237     xmlFree(cache);
2238 }
2239
2240 /**
2241  * xmlXPathContextSetCache:
2242  *
2243  * @ctxt:  the XPath context
2244  * @active: enables/disables (creates/frees) the cache
2245  * @value: a value with semantics dependant on @options
2246  * @options: options (currently only the value 0 is used)
2247  *
2248  * Creates/frees an object cache on the XPath context.
2249  * If activates XPath objects (xmlXPathObject) will be cached internally
2250  * to be reused.
2251  * @options:
2252  *   0: This will set the XPath object caching:
2253  *      @value:
2254  *        This will set the maximum number of XPath objects
2255  *        to be cached per slot
2256  *        There are 5 slots for: node-set, string, number, boolean, and
2257  *        misc objects. Use <0 for the default number (100).
2258  *   Other values for @options have currently no effect.
2259  *
2260  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2261  */
2262 int
2263 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2264                         int active,
2265                         int value,
2266                         int options)
2267 {
2268     if (ctxt == NULL)
2269         return(-1);
2270     if (active) {
2271         xmlXPathContextCachePtr cache;
2272
2273         if (ctxt->cache == NULL) {
2274             ctxt->cache = xmlXPathNewCache();
2275             if (ctxt->cache == NULL)
2276                 return(-1);
2277         }
2278         cache = (xmlXPathContextCachePtr) ctxt->cache;
2279         if (options == 0) {
2280             if (value < 0)
2281                 value = 100;
2282             cache->maxNodeset = value;
2283             cache->maxString = value;
2284             cache->maxNumber = value;
2285             cache->maxBoolean = value;
2286             cache->maxMisc = value;
2287         }
2288     } else if (ctxt->cache != NULL) {
2289         xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2290         ctxt->cache = NULL;
2291     }
2292     return(0);
2293 }
2294
2295 /**
2296  * xmlXPathCacheWrapNodeSet:
2297  * @ctxt: the XPath context
2298  * @val:  the NodePtr value
2299  *
2300  * This is the cached version of xmlXPathWrapNodeSet().
2301  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2302  *
2303  * Returns the created or reused object.
2304  */
2305 static xmlXPathObjectPtr
2306 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2307 {
2308     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2309         xmlXPathContextCachePtr cache =
2310             (xmlXPathContextCachePtr) ctxt->cache;
2311
2312         if ((cache->miscObjs != NULL) &&
2313             (cache->miscObjs->number != 0))
2314         {
2315             xmlXPathObjectPtr ret;
2316
2317             ret = (xmlXPathObjectPtr)
2318                 cache->miscObjs->items[--cache->miscObjs->number];
2319             ret->type = XPATH_NODESET;
2320             ret->nodesetval = val;
2321 #ifdef XP_DEBUG_OBJ_USAGE
2322             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2323 #endif
2324             return(ret);
2325         }
2326     }
2327
2328     return(xmlXPathWrapNodeSet(val));
2329
2330 }
2331
2332 /**
2333  * xmlXPathCacheWrapString:
2334  * @ctxt: the XPath context
2335  * @val:  the xmlChar * value
2336  *
2337  * This is the cached version of xmlXPathWrapString().
2338  * Wraps the @val string into an XPath object.
2339  *
2340  * Returns the created or reused object.
2341  */
2342 static xmlXPathObjectPtr
2343 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2344 {
2345     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2346         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2347
2348         if ((cache->stringObjs != NULL) &&
2349             (cache->stringObjs->number != 0))
2350         {
2351
2352             xmlXPathObjectPtr ret;
2353
2354             ret = (xmlXPathObjectPtr)
2355                 cache->stringObjs->items[--cache->stringObjs->number];
2356             ret->type = XPATH_STRING;
2357             ret->stringval = val;
2358 #ifdef XP_DEBUG_OBJ_USAGE
2359             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2360 #endif
2361             return(ret);
2362         } else if ((cache->miscObjs != NULL) &&
2363             (cache->miscObjs->number != 0))
2364         {
2365             xmlXPathObjectPtr ret;
2366             /*
2367             * Fallback to misc-cache.
2368             */
2369             ret = (xmlXPathObjectPtr)
2370                 cache->miscObjs->items[--cache->miscObjs->number];
2371
2372             ret->type = XPATH_STRING;
2373             ret->stringval = val;
2374 #ifdef XP_DEBUG_OBJ_USAGE
2375             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2376 #endif
2377             return(ret);
2378         }
2379     }
2380     return(xmlXPathWrapString(val));
2381 }
2382
2383 /**
2384  * xmlXPathCacheNewNodeSet:
2385  * @ctxt: the XPath context
2386  * @val:  the NodePtr value
2387  *
2388  * This is the cached version of xmlXPathNewNodeSet().
2389  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2390  * it with the single Node @val
2391  *
2392  * Returns the created or reused object.
2393  */
2394 static xmlXPathObjectPtr
2395 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2396 {
2397     if ((ctxt != NULL) && (ctxt->cache)) {
2398         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2399
2400         if ((cache->nodesetObjs != NULL) &&
2401             (cache->nodesetObjs->number != 0))
2402         {
2403             xmlXPathObjectPtr ret;
2404             /*
2405             * Use the nodset-cache.
2406             */
2407             ret = (xmlXPathObjectPtr)
2408                 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2409             ret->type = XPATH_NODESET;
2410             ret->boolval = 0;
2411             if (val) {
2412                 if ((ret->nodesetval->nodeMax == 0) ||
2413                     (val->type == XML_NAMESPACE_DECL))
2414                 {
2415                     xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2416                 } else {
2417                     ret->nodesetval->nodeTab[0] = val;
2418                     ret->nodesetval->nodeNr = 1;
2419                 }
2420             }
2421 #ifdef XP_DEBUG_OBJ_USAGE
2422             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2423 #endif
2424             return(ret);
2425         } else if ((cache->miscObjs != NULL) &&
2426             (cache->miscObjs->number != 0))
2427         {
2428             xmlXPathObjectPtr ret;
2429             /*
2430             * Fallback to misc-cache.
2431             */
2432
2433             ret = (xmlXPathObjectPtr)
2434                 cache->miscObjs->items[--cache->miscObjs->number];
2435
2436             ret->type = XPATH_NODESET;
2437             ret->boolval = 0;
2438             ret->nodesetval = xmlXPathNodeSetCreate(val);
2439             if (ret->nodesetval == NULL) {
2440                 ctxt->lastError.domain = XML_FROM_XPATH;
2441                 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2442                 return(NULL);
2443             }
2444 #ifdef XP_DEBUG_OBJ_USAGE
2445             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2446 #endif
2447             return(ret);
2448         }
2449     }
2450     return(xmlXPathNewNodeSet(val));
2451 }
2452
2453 /**
2454  * xmlXPathCacheNewCString:
2455  * @ctxt: the XPath context
2456  * @val:  the char * value
2457  *
2458  * This is the cached version of xmlXPathNewCString().
2459  * Acquire an xmlXPathObjectPtr of type string and of value @val
2460  *
2461  * Returns the created or reused object.
2462  */
2463 static xmlXPathObjectPtr
2464 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2465 {
2466     if ((ctxt != NULL) && (ctxt->cache)) {
2467         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2468
2469         if ((cache->stringObjs != NULL) &&
2470             (cache->stringObjs->number != 0))
2471         {
2472             xmlXPathObjectPtr ret;
2473
2474             ret = (xmlXPathObjectPtr)
2475                 cache->stringObjs->items[--cache->stringObjs->number];
2476
2477             ret->type = XPATH_STRING;
2478             ret->stringval = xmlStrdup(BAD_CAST val);
2479 #ifdef XP_DEBUG_OBJ_USAGE
2480             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2481 #endif
2482             return(ret);
2483         } else if ((cache->miscObjs != NULL) &&
2484             (cache->miscObjs->number != 0))
2485         {
2486             xmlXPathObjectPtr ret;
2487
2488             ret = (xmlXPathObjectPtr)
2489                 cache->miscObjs->items[--cache->miscObjs->number];
2490
2491             ret->type = XPATH_STRING;
2492             ret->stringval = xmlStrdup(BAD_CAST val);
2493 #ifdef XP_DEBUG_OBJ_USAGE
2494             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2495 #endif
2496             return(ret);
2497         }
2498     }
2499     return(xmlXPathNewCString(val));
2500 }
2501
2502 /**
2503  * xmlXPathCacheNewString:
2504  * @ctxt: the XPath context
2505  * @val:  the xmlChar * value
2506  *
2507  * This is the cached version of xmlXPathNewString().
2508  * Acquire an xmlXPathObjectPtr of type string and of value @val
2509  *
2510  * Returns the created or reused object.
2511  */
2512 static xmlXPathObjectPtr
2513 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2514 {
2515     if ((ctxt != NULL) && (ctxt->cache)) {
2516         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2517
2518         if ((cache->stringObjs != NULL) &&
2519             (cache->stringObjs->number != 0))
2520         {
2521             xmlXPathObjectPtr ret;
2522
2523             ret = (xmlXPathObjectPtr)
2524                 cache->stringObjs->items[--cache->stringObjs->number];
2525             ret->type = XPATH_STRING;
2526             if (val != NULL)
2527                 ret->stringval = xmlStrdup(val);
2528             else
2529                 ret->stringval = xmlStrdup((const xmlChar *)"");
2530 #ifdef XP_DEBUG_OBJ_USAGE
2531             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2532 #endif
2533             return(ret);
2534         } else if ((cache->miscObjs != NULL) &&
2535             (cache->miscObjs->number != 0))
2536         {
2537             xmlXPathObjectPtr ret;
2538
2539             ret = (xmlXPathObjectPtr)
2540                 cache->miscObjs->items[--cache->miscObjs->number];
2541
2542             ret->type = XPATH_STRING;
2543             if (val != NULL)
2544                 ret->stringval = xmlStrdup(val);
2545             else
2546                 ret->stringval = xmlStrdup((const xmlChar *)"");
2547 #ifdef XP_DEBUG_OBJ_USAGE
2548             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2549 #endif
2550             return(ret);
2551         }
2552     }
2553     return(xmlXPathNewString(val));
2554 }
2555
2556 /**
2557  * xmlXPathCacheNewBoolean:
2558  * @ctxt: the XPath context
2559  * @val:  the boolean value
2560  *
2561  * This is the cached version of xmlXPathNewBoolean().
2562  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2563  *
2564  * Returns the created or reused object.
2565  */
2566 static xmlXPathObjectPtr
2567 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2568 {
2569     if ((ctxt != NULL) && (ctxt->cache)) {
2570         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2571
2572         if ((cache->booleanObjs != NULL) &&
2573             (cache->booleanObjs->number != 0))
2574         {
2575             xmlXPathObjectPtr ret;
2576
2577             ret = (xmlXPathObjectPtr)
2578                 cache->booleanObjs->items[--cache->booleanObjs->number];
2579             ret->type = XPATH_BOOLEAN;
2580             ret->boolval = (val != 0);
2581 #ifdef XP_DEBUG_OBJ_USAGE
2582             xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2583 #endif
2584             return(ret);
2585         } else if ((cache->miscObjs != NULL) &&
2586             (cache->miscObjs->number != 0))
2587         {
2588             xmlXPathObjectPtr ret;
2589
2590             ret = (xmlXPathObjectPtr)
2591                 cache->miscObjs->items[--cache->miscObjs->number];
2592
2593             ret->type = XPATH_BOOLEAN;
2594             ret->boolval = (val != 0);
2595 #ifdef XP_DEBUG_OBJ_USAGE
2596             xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2597 #endif
2598             return(ret);
2599         }
2600     }
2601     return(xmlXPathNewBoolean(val));
2602 }
2603
2604 /**
2605  * xmlXPathCacheNewFloat:
2606  * @ctxt: the XPath context
2607  * @val:  the double value
2608  *
2609  * This is the cached version of xmlXPathNewFloat().
2610  * Acquires an xmlXPathObjectPtr of type double and of value @val
2611  *
2612  * Returns the created or reused object.
2613  */
2614 static xmlXPathObjectPtr
2615 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2616 {
2617      if ((ctxt != NULL) && (ctxt->cache)) {
2618         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2619
2620         if ((cache->numberObjs != NULL) &&
2621             (cache->numberObjs->number != 0))
2622         {
2623             xmlXPathObjectPtr ret;
2624
2625             ret = (xmlXPathObjectPtr)
2626                 cache->numberObjs->items[--cache->numberObjs->number];
2627             ret->type = XPATH_NUMBER;
2628             ret->floatval = val;
2629 #ifdef XP_DEBUG_OBJ_USAGE
2630             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2631 #endif
2632             return(ret);
2633         } else if ((cache->miscObjs != NULL) &&
2634             (cache->miscObjs->number != 0))
2635         {
2636             xmlXPathObjectPtr ret;
2637
2638             ret = (xmlXPathObjectPtr)
2639                 cache->miscObjs->items[--cache->miscObjs->number];
2640
2641             ret->type = XPATH_NUMBER;
2642             ret->floatval = val;
2643 #ifdef XP_DEBUG_OBJ_USAGE
2644             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2645 #endif
2646             return(ret);
2647         }
2648     }
2649     return(xmlXPathNewFloat(val));
2650 }
2651
2652 /**
2653  * xmlXPathCacheConvertString:
2654  * @ctxt: the XPath context
2655  * @val:  an XPath object
2656  *
2657  * This is the cached version of xmlXPathConvertString().
2658  * Converts an existing object to its string() equivalent
2659  *
2660  * Returns a created or reused object, the old one is freed (cached)
2661  *         (or the operation is done directly on @val)
2662  */
2663
2664 static xmlXPathObjectPtr
2665 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2666     xmlChar *res = NULL;
2667
2668     if (val == NULL)
2669         return(xmlXPathCacheNewCString(ctxt, ""));
2670
2671     switch (val->type) {
2672     case XPATH_UNDEFINED:
2673 #ifdef DEBUG_EXPR
2674         xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2675 #endif
2676         break;
2677     case XPATH_NODESET:
2678     case XPATH_XSLT_TREE:
2679         res = xmlXPathCastNodeSetToString(val->nodesetval);
2680         break;
2681     case XPATH_STRING:
2682         return(val);
2683     case XPATH_BOOLEAN:
2684         res = xmlXPathCastBooleanToString(val->boolval);
2685         break;
2686     case XPATH_NUMBER:
2687         res = xmlXPathCastNumberToString(val->floatval);
2688         break;
2689     case XPATH_USERS:
2690     case XPATH_POINT:
2691     case XPATH_RANGE:
2692     case XPATH_LOCATIONSET:
2693         TODO;
2694         break;
2695     }
2696     xmlXPathReleaseObject(ctxt, val);
2697     if (res == NULL)
2698         return(xmlXPathCacheNewCString(ctxt, ""));
2699     return(xmlXPathCacheWrapString(ctxt, res));
2700 }
2701
2702 /**
2703  * xmlXPathCacheObjectCopy:
2704  * @ctxt: the XPath context
2705  * @val:  the original object
2706  *
2707  * This is the cached version of xmlXPathObjectCopy().
2708  * Acquire a copy of a given object
2709  *
2710  * Returns a created or reused created object.
2711  */
2712 static xmlXPathObjectPtr
2713 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2714 {
2715     if (val == NULL)
2716         return(NULL);
2717
2718     if (XP_HAS_CACHE(ctxt)) {
2719         switch (val->type) {
2720             case XPATH_NODESET:
2721                 return(xmlXPathCacheWrapNodeSet(ctxt,
2722                     xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2723             case XPATH_STRING:
2724                 return(xmlXPathCacheNewString(ctxt, val->stringval));
2725             case XPATH_BOOLEAN:
2726                 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2727             case XPATH_NUMBER:
2728                 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2729             default:
2730                 break;
2731         }
2732     }
2733     return(xmlXPathObjectCopy(val));
2734 }
2735
2736 /**
2737  * xmlXPathCacheConvertBoolean:
2738  * @ctxt: the XPath context
2739  * @val:  an XPath object
2740  *
2741  * This is the cached version of xmlXPathConvertBoolean().
2742  * Converts an existing object to its boolean() equivalent
2743  *
2744  * Returns a created or reused object, the old one is freed (or the operation
2745  *         is done directly on @val)
2746  */
2747 static xmlXPathObjectPtr
2748 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2749     xmlXPathObjectPtr ret;
2750
2751     if (val == NULL)
2752         return(xmlXPathCacheNewBoolean(ctxt, 0));
2753     if (val->type == XPATH_BOOLEAN)
2754         return(val);
2755     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2756     xmlXPathReleaseObject(ctxt, val);
2757     return(ret);
2758 }
2759
2760 /**
2761  * xmlXPathCacheConvertNumber:
2762  * @ctxt: the XPath context
2763  * @val:  an XPath object
2764  *
2765  * This is the cached version of xmlXPathConvertNumber().
2766  * Converts an existing object to its number() equivalent
2767  *
2768  * Returns a created or reused object, the old one is freed (or the operation
2769  *         is done directly on @val)
2770  */
2771 static xmlXPathObjectPtr
2772 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2773     xmlXPathObjectPtr ret;
2774
2775     if (val == NULL)
2776         return(xmlXPathCacheNewFloat(ctxt, 0.0));
2777     if (val->type == XPATH_NUMBER)
2778         return(val);
2779     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2780     xmlXPathReleaseObject(ctxt, val);
2781     return(ret);
2782 }
2783
2784 /************************************************************************
2785  *                                                                      *
2786  *              Parser stacks related functions and macros              *
2787  *                                                                      *
2788  ************************************************************************/
2789
2790 /**
2791  * xmlXPathSetFrame:
2792  * @ctxt: an XPath parser context
2793  *
2794  * Set the callee evaluation frame
2795  *
2796  * Returns the previous frame value to be restored once done
2797  */
2798 static int
2799 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2800     int ret;
2801
2802     if (ctxt == NULL)
2803         return(0);
2804     ret = ctxt->valueFrame;
2805     ctxt->valueFrame = ctxt->valueNr;
2806     return(ret);
2807 }
2808
2809 /**
2810  * xmlXPathPopFrame:
2811  * @ctxt: an XPath parser context
2812  * @frame: the previous frame value
2813  *
2814  * Remove the callee evaluation frame
2815  */
2816 static void
2817 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2818     if (ctxt == NULL)
2819         return;
2820     if (ctxt->valueNr < ctxt->valueFrame) {
2821         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2822     }
2823     ctxt->valueFrame = frame;
2824 }
2825
2826 /**
2827  * valuePop:
2828  * @ctxt: an XPath evaluation context
2829  *
2830  * Pops the top XPath object from the value stack
2831  *
2832  * Returns the XPath object just removed
2833  */
2834 xmlXPathObjectPtr
2835 valuePop(xmlXPathParserContextPtr ctxt)
2836 {
2837     xmlXPathObjectPtr ret;
2838
2839     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2840         return (NULL);
2841
2842     if (ctxt->valueNr <= ctxt->valueFrame) {
2843         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2844         return (NULL);
2845     }
2846
2847     ctxt->valueNr--;
2848     if (ctxt->valueNr > 0)
2849         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2850     else
2851         ctxt->value = NULL;
2852     ret = ctxt->valueTab[ctxt->valueNr];
2853     ctxt->valueTab[ctxt->valueNr] = NULL;
2854     return (ret);
2855 }
2856 /**
2857  * valuePush:
2858  * @ctxt:  an XPath evaluation context
2859  * @value:  the XPath object
2860  *
2861  * Pushes a new XPath object on top of the value stack
2862  *
2863  * returns the number of items on the value stack
2864  */
2865 int
2866 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2867 {
2868     if ((ctxt == NULL) || (value == NULL)) return(-1);
2869     if (ctxt->valueNr >= ctxt->valueMax) {
2870         xmlXPathObjectPtr *tmp;
2871
2872         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2873             xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2874             ctxt->error = XPATH_MEMORY_ERROR;
2875             return (0);
2876         }
2877         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2878                                              2 * ctxt->valueMax *
2879                                              sizeof(ctxt->valueTab[0]));
2880         if (tmp == NULL) {
2881             xmlXPathErrMemory(NULL, "pushing value\n");
2882             ctxt->error = XPATH_MEMORY_ERROR;
2883             return (0);
2884         }
2885         ctxt->valueMax *= 2;
2886         ctxt->valueTab = tmp;
2887     }
2888     ctxt->valueTab[ctxt->valueNr] = value;
2889     ctxt->value = value;
2890     return (ctxt->valueNr++);
2891 }
2892
2893 /**
2894  * xmlXPathPopBoolean:
2895  * @ctxt:  an XPath parser context
2896  *
2897  * Pops a boolean from the stack, handling conversion if needed.
2898  * Check error with #xmlXPathCheckError.
2899  *
2900  * Returns the boolean
2901  */
2902 int
2903 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2904     xmlXPathObjectPtr obj;
2905     int ret;
2906
2907     obj = valuePop(ctxt);
2908     if (obj == NULL) {
2909         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2910         return(0);
2911     }
2912     if (obj->type != XPATH_BOOLEAN)
2913         ret = xmlXPathCastToBoolean(obj);
2914     else
2915         ret = obj->boolval;
2916     xmlXPathReleaseObject(ctxt->context, obj);
2917     return(ret);
2918 }
2919
2920 /**
2921  * xmlXPathPopNumber:
2922  * @ctxt:  an XPath parser context
2923  *
2924  * Pops a number from the stack, handling conversion if needed.
2925  * Check error with #xmlXPathCheckError.
2926  *
2927  * Returns the number
2928  */
2929 double
2930 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2931     xmlXPathObjectPtr obj;
2932     double ret;
2933
2934     obj = valuePop(ctxt);
2935     if (obj == NULL) {
2936         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2937         return(0);
2938     }
2939     if (obj->type != XPATH_NUMBER)
2940         ret = xmlXPathCastToNumber(obj);
2941     else
2942         ret = obj->floatval;
2943     xmlXPathReleaseObject(ctxt->context, obj);
2944     return(ret);
2945 }
2946
2947 /**
2948  * xmlXPathPopString:
2949  * @ctxt:  an XPath parser context
2950  *
2951  * Pops a string from the stack, handling conversion if needed.
2952  * Check error with #xmlXPathCheckError.
2953  *
2954  * Returns the string
2955  */
2956 xmlChar *
2957 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2958     xmlXPathObjectPtr obj;
2959     xmlChar * ret;
2960
2961     obj = valuePop(ctxt);
2962     if (obj == NULL) {
2963         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2964         return(NULL);
2965     }
2966     ret = xmlXPathCastToString(obj);    /* this does required strdup */
2967     /* TODO: needs refactoring somewhere else */
2968     if (obj->stringval == ret)
2969         obj->stringval = NULL;
2970     xmlXPathReleaseObject(ctxt->context, obj);
2971     return(ret);
2972 }
2973
2974 /**
2975  * xmlXPathPopNodeSet:
2976  * @ctxt:  an XPath parser context
2977  *
2978  * Pops a node-set from the stack, handling conversion if needed.
2979  * Check error with #xmlXPathCheckError.
2980  *
2981  * Returns the node-set
2982  */
2983 xmlNodeSetPtr
2984 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2985     xmlXPathObjectPtr obj;
2986     xmlNodeSetPtr ret;
2987
2988     if (ctxt == NULL) return(NULL);
2989     if (ctxt->value == NULL) {
2990         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2991         return(NULL);
2992     }
2993     if (!xmlXPathStackIsNodeSet(ctxt)) {
2994         xmlXPathSetTypeError(ctxt);
2995         return(NULL);
2996     }
2997     obj = valuePop(ctxt);
2998     ret = obj->nodesetval;
2999 #if 0
3000     /* to fix memory leak of not clearing obj->user */
3001     if (obj->boolval && obj->user != NULL)
3002         xmlFreeNodeList((xmlNodePtr) obj->user);
3003 #endif
3004     obj->nodesetval = NULL;
3005     xmlXPathReleaseObject(ctxt->context, obj);
3006     return(ret);
3007 }
3008
3009 /**
3010  * xmlXPathPopExternal:
3011  * @ctxt:  an XPath parser context
3012  *
3013  * Pops an external object from the stack, handling conversion if needed.
3014  * Check error with #xmlXPathCheckError.
3015  *
3016  * Returns the object
3017  */
3018 void *
3019 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3020     xmlXPathObjectPtr obj;
3021     void * ret;
3022
3023     if ((ctxt == NULL) || (ctxt->value == NULL)) {
3024         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3025         return(NULL);
3026     }
3027     if (ctxt->value->type != XPATH_USERS) {
3028         xmlXPathSetTypeError(ctxt);
3029         return(NULL);
3030     }
3031     obj = valuePop(ctxt);
3032     ret = obj->user;
3033     obj->user = NULL;
3034     xmlXPathReleaseObject(ctxt->context, obj);
3035     return(ret);
3036 }
3037
3038 /*
3039  * Macros for accessing the content. Those should be used only by the parser,
3040  * and not exported.
3041  *
3042  * Dirty macros, i.e. one need to make assumption on the context to use them
3043  *
3044  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3045  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3046  *           in ISO-Latin or UTF-8.
3047  *           This should be used internally by the parser
3048  *           only to compare to ASCII values otherwise it would break when
3049  *           running with UTF-8 encoding.
3050  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3051  *           to compare on ASCII based substring.
3052  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3053  *           strings within the parser.
3054  *   CURRENT Returns the current char value, with the full decoding of
3055  *           UTF-8 if we are using this mode. It returns an int.
3056  *   NEXT    Skip to the next character, this does the proper decoding
3057  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3058  *           It returns the pointer to the current xmlChar.
3059  */
3060
3061 #define CUR (*ctxt->cur)
3062 #define SKIP(val) ctxt->cur += (val)
3063 #define NXT(val) ctxt->cur[(val)]
3064 #define CUR_PTR ctxt->cur
3065 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3066
3067 #define COPY_BUF(l,b,i,v)                                              \
3068     if (l == 1) b[i++] = (xmlChar) v;                                  \
3069     else i += xmlCopyChar(l,&b[i],v)
3070
3071 #define NEXTL(l)  ctxt->cur += l
3072
3073 #define SKIP_BLANKS                                                     \
3074     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3075
3076 #define CURRENT (*ctxt->cur)
3077 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3078
3079
3080 #ifndef DBL_DIG
3081 #define DBL_DIG 16
3082 #endif
3083 #ifndef DBL_EPSILON
3084 #define DBL_EPSILON 1E-9
3085 #endif
3086
3087 #define UPPER_DOUBLE 1E9
3088 #define LOWER_DOUBLE 1E-5
3089 #define LOWER_DOUBLE_EXP 5
3090
3091 #define INTEGER_DIGITS DBL_DIG
3092 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3093 #define EXPONENT_DIGITS (3 + 2)
3094
3095 /**
3096  * xmlXPathFormatNumber:
3097  * @number:     number to format
3098  * @buffer:     output buffer
3099  * @buffersize: size of output buffer
3100  *
3101  * Convert the number into a string representation.
3102  */
3103 static void
3104 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3105 {
3106     switch (xmlXPathIsInf(number)) {
3107     case 1:
3108         if (buffersize > (int)sizeof("Infinity"))
3109             snprintf(buffer, buffersize, "Infinity");
3110         break;
3111     case -1:
3112         if (buffersize > (int)sizeof("-Infinity"))
3113             snprintf(buffer, buffersize, "-Infinity");
3114         break;
3115     default:
3116         if (xmlXPathIsNaN(number)) {
3117             if (buffersize > (int)sizeof("NaN"))
3118                 snprintf(buffer, buffersize, "NaN");
3119         } else if (number == 0 && xmlXPathGetSign(number) != 0) {
3120             snprintf(buffer, buffersize, "0");
3121         } else if ((number > INT_MIN) && (number < INT_MAX) &&
3122                    (number == (int) number)) {
3123             char work[30];
3124             char *ptr, *cur;
3125             int value = (int) number;
3126
3127             ptr = &buffer[0];
3128             if (value == 0) {
3129                 *ptr++ = '0';
3130             } else {
3131                 snprintf(work, 29, "%d", value);
3132                 cur = &work[0];
3133                 while ((*cur) && (ptr - buffer < buffersize)) {
3134                     *ptr++ = *cur++;
3135                 }
3136             }
3137             if (ptr - buffer < buffersize) {
3138                 *ptr = 0;
3139             } else if (buffersize > 0) {
3140                 ptr--;
3141                 *ptr = 0;
3142             }
3143         } else {
3144             /*
3145               For the dimension of work,
3146                   DBL_DIG is number of significant digits
3147                   EXPONENT is only needed for "scientific notation"
3148                   3 is sign, decimal point, and terminating zero
3149                   LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3150               Note that this dimension is slightly (a few characters)
3151               larger than actually necessary.
3152             */
3153             char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3154             int integer_place, fraction_place;
3155             char *ptr;
3156             char *after_fraction;
3157             double absolute_value;
3158             int size;
3159
3160             absolute_value = fabs(number);
3161
3162             /*
3163              * First choose format - scientific or regular floating point.
3164              * In either case, result is in work, and after_fraction points
3165              * just past the fractional part.
3166             */
3167             if ( ((absolute_value > UPPER_DOUBLE) ||
3168                   (absolute_value < LOWER_DOUBLE)) &&
3169                  (absolute_value != 0.0) ) {
3170                 /* Use scientific notation */
3171                 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3172                 fraction_place = DBL_DIG - 1;
3173                 size = snprintf(work, sizeof(work),"%*.*e",
3174                          integer_place, fraction_place, number);
3175                 while ((size > 0) && (work[size] != 'e')) size--;
3176
3177             }
3178             else {
3179                 /* Use regular notation */
3180                 if (absolute_value > 0.0) {
3181                     integer_place = (int)log10(absolute_value);
3182                     if (integer_place > 0)
3183                         fraction_place = DBL_DIG - integer_place - 1;
3184                     else
3185                         fraction_place = DBL_DIG - integer_place;
3186                 } else {
3187                     fraction_place = 1;
3188                 }
3189                 size = snprintf(work, sizeof(work), "%0.*f",
3190                                 fraction_place, number);
3191             }
3192
3193             /* Remove leading spaces sometimes inserted by snprintf */
3194             while (work[0] == ' ') {
3195                 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3196                 size--;
3197             }
3198
3199             /* Remove fractional trailing zeroes */
3200             after_fraction = work + size;
3201             ptr = after_fraction;
3202             while (*(--ptr) == '0')
3203                 ;
3204             if (*ptr != '.')
3205                 ptr++;
3206             while ((*ptr++ = *after_fraction++) != 0);
3207
3208             /* Finally copy result back to caller */
3209             size = strlen(work) + 1;
3210             if (size > buffersize) {
3211                 work[buffersize - 1] = 0;
3212                 size = buffersize;
3213             }
3214             memmove(buffer, work, size);
3215         }
3216         break;
3217     }
3218 }
3219
3220
3221 /************************************************************************
3222  *                                                                      *
3223  *                      Routines to handle NodeSets                     *
3224  *                                                                      *
3225  ************************************************************************/
3226
3227 /**
3228  * xmlXPathOrderDocElems:
3229  * @doc:  an input document
3230  *
3231  * Call this routine to speed up XPath computation on static documents.
3232  * This stamps all the element nodes with the document order
3233  * Like for line information, the order is kept in the element->content
3234  * field, the value stored is actually - the node number (starting at -1)
3235  * to be able to differentiate from line numbers.
3236  *
3237  * Returns the number of elements found in the document or -1 in case
3238  *    of error.
3239  */
3240 long
3241 xmlXPathOrderDocElems(xmlDocPtr doc) {
3242     long count = 0;
3243     xmlNodePtr cur;
3244
3245     if (doc == NULL)
3246         return(-1);
3247     cur = doc->children;
3248     while (cur != NULL) {
3249         if (cur->type == XML_ELEMENT_NODE) {
3250             cur->content = (void *) (-(++count));
3251             if (cur->children != NULL) {
3252                 cur = cur->children;
3253                 continue;
3254             }
3255         }
3256         if (cur->next != NULL) {
3257             cur = cur->next;
3258             continue;
3259         }
3260         do {
3261             cur = cur->parent;
3262             if (cur == NULL)
3263                 break;
3264             if (cur == (xmlNodePtr) doc) {
3265                 cur = NULL;
3266                 break;
3267             }
3268             if (cur->next != NULL) {
3269                 cur = cur->next;
3270                 break;
3271             }
3272         } while (cur != NULL);
3273     }
3274     return(count);
3275 }
3276
3277 /**
3278  * xmlXPathCmpNodes:
3279  * @node1:  the first node
3280  * @node2:  the second node
3281  *
3282  * Compare two nodes w.r.t document order
3283  *
3284  * Returns -2 in case of error 1 if first point < second point, 0 if
3285  *         it's the same node, -1 otherwise
3286  */
3287 int
3288 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3289     int depth1, depth2;
3290     int attr1 = 0, attr2 = 0;
3291     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3292     xmlNodePtr cur, root;
3293
3294     if ((node1 == NULL) || (node2 == NULL))
3295         return(-2);
3296     /*
3297      * a couple of optimizations which will avoid computations in most cases
3298      */
3299     if (node1 == node2)         /* trivial case */
3300         return(0);
3301     if (node1->type == XML_ATTRIBUTE_NODE) {
3302         attr1 = 1;
3303         attrNode1 = node1;
3304         node1 = node1->parent;
3305     }
3306     if (node2->type == XML_ATTRIBUTE_NODE) {
3307         attr2 = 1;
3308         attrNode2 = node2;
3309         node2 = node2->parent;
3310     }
3311     if (node1 == node2) {
3312         if (attr1 == attr2) {
3313             /* not required, but we keep attributes in order */
3314             if (attr1 != 0) {
3315                 cur = attrNode2->prev;
3316                 while (cur != NULL) {
3317                     if (cur == attrNode1)
3318                         return (1);
3319                     cur = cur->prev;
3320                 }
3321                 return (-1);
3322             }
3323             return(0);
3324         }
3325         if (attr2 == 1)
3326             return(1);
3327         return(-1);
3328     }
3329     if ((node1->type == XML_NAMESPACE_DECL) ||
3330         (node2->type == XML_NAMESPACE_DECL))
3331         return(1);
3332     if (node1 == node2->prev)
3333         return(1);
3334     if (node1 == node2->next)
3335         return(-1);
3336
3337     /*
3338      * Speedup using document order if availble.
3339      */
3340     if ((node1->type == XML_ELEMENT_NODE) &&
3341         (node2->type == XML_ELEMENT_NODE) &&
3342         (0 > (long) node1->content) &&
3343         (0 > (long) node2->content) &&
3344         (node1->doc == node2->doc)) {
3345         long l1, l2;
3346
3347         l1 = -((long) node1->content);
3348         l2 = -((long) node2->content);
3349         if (l1 < l2)
3350             return(1);
3351         if (l1 > l2)
3352             return(-1);
3353     }
3354
3355     /*
3356      * compute depth to root
3357      */
3358     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3359         if (cur->parent == node1)
3360             return(1);
3361         depth2++;
3362     }
3363     root = cur;
3364     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3365         if (cur->parent == node2)
3366             return(-1);
3367         depth1++;
3368     }
3369     /*
3370      * Distinct document (or distinct entities :-( ) case.
3371      */
3372     if (root != cur) {
3373         return(-2);
3374     }
3375     /*
3376      * get the nearest common ancestor.
3377      */
3378     while (depth1 > depth2) {
3379         depth1--;
3380         node1 = node1->parent;
3381     }
3382     while (depth2 > depth1) {
3383         depth2--;
3384         node2 = node2->parent;
3385     }
3386     while (node1->parent != node2->parent) {
3387         node1 = node1->parent;
3388         node2 = node2->parent;
3389         /* should not happen but just in case ... */
3390         if ((node1 == NULL) || (node2 == NULL))
3391             return(-2);
3392     }
3393     /*
3394      * Find who's first.
3395      */
3396     if (node1 == node2->prev)
3397         return(1);
3398     if (node1 == node2->next)
3399         return(-1);
3400     /*
3401      * Speedup using document order if availble.
3402      */
3403     if ((node1->type == XML_ELEMENT_NODE) &&
3404         (node2->type == XML_ELEMENT_NODE) &&
3405         (0 > (long) node1->content) &&
3406         (0 > (long) node2->content) &&
3407         (node1->doc == node2->doc)) {
3408         long l1, l2;
3409
3410         l1 = -((long) node1->content);
3411         l2 = -((long) node2->content);
3412         if (l1 < l2)
3413             return(1);
3414         if (l1 > l2)
3415             return(-1);
3416     }
3417
3418     for (cur = node1->next;cur != NULL;cur = cur->next)
3419         if (cur == node2)
3420             return(1);
3421     return(-1); /* assume there is no sibling list corruption */
3422 }
3423
3424 /**
3425  * xmlXPathNodeSetSort:
3426  * @set:  the node set
3427  *
3428  * Sort the node set in document order
3429  */
3430 void
3431 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3432 #ifndef WITH_TIM_SORT
3433     int i, j, incr, len;
3434     xmlNodePtr tmp;
3435 #endif
3436
3437     if (set == NULL)
3438         return;
3439
3440 #ifndef WITH_TIM_SORT
3441     /*
3442      * Use the old Shell's sort implementation to sort the node-set
3443      * Timsort ought to be quite faster
3444      */
3445     len = set->nodeNr;
3446     for (incr = len / 2; incr > 0; incr /= 2) {
3447         for (i = incr; i < len; i++) {
3448             j = i - incr;
3449             while (j >= 0) {
3450 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3451                 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3452                         set->nodeTab[j + incr]) == -1)
3453 #else
3454                 if (xmlXPathCmpNodes(set->nodeTab[j],
3455                         set->nodeTab[j + incr]) == -1)
3456 #endif
3457                 {
3458                     tmp = set->nodeTab[j];
3459                     set->nodeTab[j] = set->nodeTab[j + incr];
3460                     set->nodeTab[j + incr] = tmp;
3461                     j -= incr;
3462                 } else
3463                     break;
3464             }
3465         }
3466     }
3467 #else /* WITH_TIM_SORT */
3468     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3469 #endif /* WITH_TIM_SORT */
3470 }
3471
3472 #define XML_NODESET_DEFAULT     10
3473 /**
3474  * xmlXPathNodeSetDupNs:
3475  * @node:  the parent node of the namespace XPath node
3476  * @ns:  the libxml namespace declaration node.
3477  *
3478  * Namespace node in libxml don't match the XPath semantic. In a node set
3479  * the namespace nodes are duplicated and the next pointer is set to the
3480  * parent node in the XPath semantic.
3481  *
3482  * Returns the newly created object.
3483  */
3484 static xmlNodePtr
3485 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3486     xmlNsPtr cur;
3487
3488     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3489         return(NULL);
3490     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3491         return((xmlNodePtr) ns);
3492
3493     /*
3494      * Allocate a new Namespace and fill the fields.
3495      */
3496     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3497     if (cur == NULL) {
3498         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3499         return(NULL);
3500     }
3501     memset(cur, 0, sizeof(xmlNs));
3502     cur->type = XML_NAMESPACE_DECL;
3503     if (ns->href != NULL)
3504         cur->href = xmlStrdup(ns->href);
3505     if (ns->prefix != NULL)
3506         cur->prefix = xmlStrdup(ns->prefix);
3507     cur->next = (xmlNsPtr) node;
3508     return((xmlNodePtr) cur);
3509 }
3510
3511 /**
3512  * xmlXPathNodeSetFreeNs:
3513  * @ns:  the XPath namespace node found in a nodeset.
3514  *
3515  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3516  * the namespace nodes are duplicated and the next pointer is set to the
3517  * parent node in the XPath semantic. Check if such a node needs to be freed
3518  */
3519 void
3520 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3521     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3522         return;
3523
3524     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3525         if (ns->href != NULL)
3526             xmlFree((xmlChar *)ns->href);
3527         if (ns->prefix != NULL)
3528             xmlFree((xmlChar *)ns->prefix);
3529         xmlFree(ns);
3530     }
3531 }
3532
3533 /**
3534  * xmlXPathNodeSetCreate:
3535  * @val:  an initial xmlNodePtr, or NULL
3536  *
3537  * Create a new xmlNodeSetPtr of type double and of value @val
3538  *
3539  * Returns the newly created object.
3540  */
3541 xmlNodeSetPtr
3542 xmlXPathNodeSetCreate(xmlNodePtr val) {
3543     xmlNodeSetPtr ret;
3544
3545     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3546     if (ret == NULL) {
3547         xmlXPathErrMemory(NULL, "creating nodeset\n");
3548         return(NULL);
3549     }
3550     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3551     if (val != NULL) {
3552         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3553                                              sizeof(xmlNodePtr));
3554         if (ret->nodeTab == NULL) {
3555             xmlXPathErrMemory(NULL, "creating nodeset\n");
3556             xmlFree(ret);
3557             return(NULL);
3558         }
3559         memset(ret->nodeTab, 0 ,
3560                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3561         ret->nodeMax = XML_NODESET_DEFAULT;
3562         if (val->type == XML_NAMESPACE_DECL) {
3563             xmlNsPtr ns = (xmlNsPtr) val;
3564
3565             ret->nodeTab[ret->nodeNr++] =
3566                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3567         } else
3568             ret->nodeTab[ret->nodeNr++] = val;
3569     }
3570     return(ret);
3571 }
3572
3573 /**
3574  * xmlXPathNodeSetCreateSize:
3575  * @size:  the initial size of the set
3576  *
3577  * Create a new xmlNodeSetPtr of type double and of value @val
3578  *
3579  * Returns the newly created object.
3580  */
3581 static xmlNodeSetPtr
3582 xmlXPathNodeSetCreateSize(int size) {
3583     xmlNodeSetPtr ret;
3584
3585     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3586     if (ret == NULL) {
3587         xmlXPathErrMemory(NULL, "creating nodeset\n");
3588         return(NULL);
3589     }
3590     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3591     if (size < XML_NODESET_DEFAULT)
3592         size = XML_NODESET_DEFAULT;
3593     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3594     if (ret->nodeTab == NULL) {
3595         xmlXPathErrMemory(NULL, "creating nodeset\n");
3596         xmlFree(ret);
3597         return(NULL);
3598     }
3599     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3600     ret->nodeMax = size;
3601     return(ret);
3602 }
3603
3604 /**
3605  * xmlXPathNodeSetContains:
3606  * @cur:  the node-set
3607  * @val:  the node
3608  *
3609  * checks whether @cur contains @val
3610  *
3611  * Returns true (1) if @cur contains @val, false (0) otherwise
3612  */
3613 int
3614 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3615     int i;
3616
3617     if ((cur == NULL) || (val == NULL)) return(0);
3618     if (val->type == XML_NAMESPACE_DECL) {
3619         for (i = 0; i < cur->nodeNr; i++) {
3620             if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3621                 xmlNsPtr ns1, ns2;
3622
3623                 ns1 = (xmlNsPtr) val;
3624                 ns2 = (xmlNsPtr) cur->nodeTab[i];
3625                 if (ns1 == ns2)
3626                     return(1);
3627                 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3628                     (xmlStrEqual(ns1->prefix, ns2->prefix)))
3629                     return(1);
3630             }
3631         }
3632     } else {
3633         for (i = 0; i < cur->nodeNr; i++) {
3634             if (cur->nodeTab[i] == val)
3635                 return(1);
3636         }
3637     }
3638     return(0);
3639 }
3640
3641 /**
3642  * xmlXPathNodeSetAddNs:
3643  * @cur:  the initial node set
3644  * @node:  the hosting node
3645  * @ns:  a the namespace node
3646  *
3647  * add a new namespace node to an existing NodeSet
3648  *
3649  * Returns 0 in case of success and -1 in case of error
3650  */
3651 int
3652 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3653     int i;
3654
3655
3656     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3657         (ns->type != XML_NAMESPACE_DECL) ||
3658         (node->type != XML_ELEMENT_NODE))
3659         return(-1);
3660
3661     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3662     /*
3663      * prevent duplicates
3664      */
3665     for (i = 0;i < cur->nodeNr;i++) {
3666         if ((cur->nodeTab[i] != NULL) &&
3667             (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3668             (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3669             (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3670             return(0);
3671     }
3672
3673     /*
3674      * grow the nodeTab if needed
3675      */
3676     if (cur->nodeMax == 0) {
3677         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3678                                              sizeof(xmlNodePtr));
3679         if (cur->nodeTab == NULL) {
3680             xmlXPathErrMemory(NULL, "growing nodeset\n");
3681             return(-1);
3682         }
3683         memset(cur->nodeTab, 0 ,
3684                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3685         cur->nodeMax = XML_NODESET_DEFAULT;
3686     } else if (cur->nodeNr == cur->nodeMax) {
3687         xmlNodePtr *temp;
3688
3689         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3690             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3691             return(-1);
3692         }
3693         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3694                                       sizeof(xmlNodePtr));
3695         if (temp == NULL) {
3696             xmlXPathErrMemory(NULL, "growing nodeset\n");
3697             return(-1);
3698         }
3699         cur->nodeMax *= 2;
3700         cur->nodeTab = temp;
3701     }
3702     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3703     return(0);
3704 }
3705
3706 /**
3707  * xmlXPathNodeSetAdd:
3708  * @cur:  the initial node set
3709  * @val:  a new xmlNodePtr
3710  *
3711  * add a new xmlNodePtr to an existing NodeSet
3712  *
3713  * Returns 0 in case of success, and -1 in case of error
3714  */
3715 int
3716 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3717     int i;
3718
3719     if ((cur == NULL) || (val == NULL)) return(-1);
3720
3721     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3722     /*
3723      * prevent duplicates
3724      */
3725     for (i = 0;i < cur->nodeNr;i++)
3726         if (cur->nodeTab[i] == val) return(0);
3727
3728     /*
3729      * grow the nodeTab if needed
3730      */
3731     if (cur->nodeMax == 0) {
3732         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3733                                              sizeof(xmlNodePtr));
3734         if (cur->nodeTab == NULL) {
3735             xmlXPathErrMemory(NULL, "growing nodeset\n");
3736             return(-1);
3737         }
3738         memset(cur->nodeTab, 0 ,
3739                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3740         cur->nodeMax = XML_NODESET_DEFAULT;
3741     } else if (cur->nodeNr == cur->nodeMax) {
3742         xmlNodePtr *temp;
3743
3744         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3745             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3746             return(-1);
3747         }
3748         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3749                                       sizeof(xmlNodePtr));
3750         if (temp == NULL) {
3751             xmlXPathErrMemory(NULL, "growing nodeset\n");
3752             return(-1);
3753         }
3754         cur->nodeMax *= 2;
3755         cur->nodeTab = temp;
3756     }
3757     if (val->type == XML_NAMESPACE_DECL) {
3758         xmlNsPtr ns = (xmlNsPtr) val;
3759
3760         cur->nodeTab[cur->nodeNr++] =
3761             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3762     } else
3763         cur->nodeTab[cur->nodeNr++] = val;
3764     return(0);
3765 }
3766
3767 /**
3768  * xmlXPathNodeSetAddUnique:
3769  * @cur:  the initial node set
3770  * @val:  a new xmlNodePtr
3771  *
3772  * add a new xmlNodePtr to an existing NodeSet, optimized version
3773  * when we are sure the node is not already in the set.
3774  *
3775  * Returns 0 in case of success and -1 in case of failure
3776  */
3777 int
3778 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3779     if ((cur == NULL) || (val == NULL)) return(-1);
3780
3781     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3782     /*
3783      * grow the nodeTab if needed
3784      */
3785     if (cur->nodeMax == 0) {
3786         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3787                                              sizeof(xmlNodePtr));
3788         if (cur->nodeTab == NULL) {
3789             xmlXPathErrMemory(NULL, "growing nodeset\n");
3790             return(-1);
3791         }
3792         memset(cur->nodeTab, 0 ,
3793                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3794         cur->nodeMax = XML_NODESET_DEFAULT;
3795     } else if (cur->nodeNr == cur->nodeMax) {
3796         xmlNodePtr *temp;
3797
3798         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3799             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3800             return(-1);
3801         }
3802         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3803                                       sizeof(xmlNodePtr));
3804         if (temp == NULL) {
3805             xmlXPathErrMemory(NULL, "growing nodeset\n");
3806             return(-1);
3807         }
3808         cur->nodeTab = temp;
3809         cur->nodeMax *= 2;
3810     }
3811     if (val->type == XML_NAMESPACE_DECL) {
3812         xmlNsPtr ns = (xmlNsPtr) val;
3813
3814         cur->nodeTab[cur->nodeNr++] =
3815             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3816     } else
3817         cur->nodeTab[cur->nodeNr++] = val;
3818     return(0);
3819 }
3820
3821 /**
3822  * xmlXPathNodeSetMerge:
3823  * @val1:  the first NodeSet or NULL
3824  * @val2:  the second NodeSet
3825  *
3826  * Merges two nodesets, all nodes from @val2 are added to @val1
3827  * if @val1 is NULL, a new set is created and copied from @val2
3828  *
3829  * Returns @val1 once extended or NULL in case of error.
3830  */
3831 xmlNodeSetPtr
3832 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3833     int i, j, initNr, skip;
3834     xmlNodePtr n1, n2;
3835
3836     if (val2 == NULL) return(val1);
3837     if (val1 == NULL) {
3838         val1 = xmlXPathNodeSetCreate(NULL);
3839     if (val1 == NULL)
3840         return (NULL);
3841 #if 0
3842         /*
3843         * TODO: The optimization won't work in every case, since
3844         *  those nasty namespace nodes need to be added with
3845         *  xmlXPathNodeSetDupNs() to the set; thus a pure
3846         *  memcpy is not possible.
3847         *  If there was a flag on the nodesetval, indicating that
3848         *  some temporary nodes are in, that would be helpfull.
3849         */
3850         /*
3851         * Optimization: Create an equally sized node-set
3852         * and memcpy the content.
3853         */
3854         val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3855         if (val1 == NULL)
3856             return(NULL);
3857         if (val2->nodeNr != 0) {
3858             if (val2->nodeNr == 1)
3859                 *(val1->nodeTab) = *(val2->nodeTab);
3860             else {
3861                 memcpy(val1->nodeTab, val2->nodeTab,
3862                     val2->nodeNr * sizeof(xmlNodePtr));
3863             }
3864             val1->nodeNr = val2->nodeNr;
3865         }
3866         return(val1);
3867 #endif
3868     }
3869
3870     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3871     initNr = val1->nodeNr;
3872
3873     for (i = 0;i < val2->nodeNr;i++) {
3874         n2 = val2->nodeTab[i];
3875         /*
3876          * check against duplicates
3877          */
3878         skip = 0;
3879         for (j = 0; j < initNr; j++) {
3880             n1 = val1->nodeTab[j];
3881             if (n1 == n2) {
3882                 skip = 1;
3883                 break;
3884             } else if ((n1->type == XML_NAMESPACE_DECL) &&
3885                        (n2->type == XML_NAMESPACE_DECL)) {
3886                 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3887                     (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3888                         ((xmlNsPtr) n2)->prefix)))
3889                 {
3890                     skip = 1;
3891                     break;
3892                 }
3893             }
3894         }
3895         if (skip)
3896             continue;
3897
3898         /*
3899          * grow the nodeTab if needed
3900          */
3901         if (val1->nodeMax == 0) {
3902             val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3903                                                     sizeof(xmlNodePtr));
3904             if (val1->nodeTab == NULL) {
3905                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3906                 return(NULL);
3907             }
3908             memset(val1->nodeTab, 0 ,
3909                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3910             val1->nodeMax = XML_NODESET_DEFAULT;
3911         } else if (val1->nodeNr == val1->nodeMax) {
3912             xmlNodePtr *temp;
3913
3914             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3915                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3916                 return(NULL);
3917             }
3918             temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3919                                              sizeof(xmlNodePtr));
3920             if (temp == NULL) {
3921                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3922                 return(NULL);
3923             }
3924             val1->nodeTab = temp;
3925             val1->nodeMax *= 2;
3926         }
3927         if (n2->type == XML_NAMESPACE_DECL) {
3928             xmlNsPtr ns = (xmlNsPtr) n2;
3929
3930             val1->nodeTab[val1->nodeNr++] =
3931                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3932         } else
3933             val1->nodeTab[val1->nodeNr++] = n2;
3934     }
3935
3936     return(val1);
3937 }
3938
3939
3940 /**
3941  * xmlXPathNodeSetMergeAndClear:
3942  * @set1:  the first NodeSet or NULL
3943  * @set2:  the second NodeSet
3944  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3945  *
3946  * Merges two nodesets, all nodes from @set2 are added to @set1
3947  * if @set1 is NULL, a new set is created and copied from @set2.
3948  * Checks for duplicate nodes. Clears set2.
3949  *
3950  * Returns @set1 once extended or NULL in case of error.
3951  */
3952 static xmlNodeSetPtr
3953 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3954                              int hasNullEntries)
3955 {
3956     if ((set1 == NULL) && (hasNullEntries == 0)) {
3957         /*
3958         * Note that doing a memcpy of the list, namespace nodes are
3959         * just assigned to set1, since set2 is cleared anyway.
3960         */
3961         set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3962         if (set1 == NULL)
3963             return(NULL);
3964         if (set2->nodeNr != 0) {
3965             memcpy(set1->nodeTab, set2->nodeTab,
3966                 set2->nodeNr * sizeof(xmlNodePtr));
3967             set1->nodeNr = set2->nodeNr;
3968         }
3969     } else {
3970         int i, j, initNbSet1;
3971         xmlNodePtr n1, n2;
3972
3973         if (set1 == NULL)
3974             set1 = xmlXPathNodeSetCreate(NULL);
3975         if (set1 == NULL)
3976             return (NULL);
3977
3978         initNbSet1 = set1->nodeNr;
3979         for (i = 0;i < set2->nodeNr;i++) {
3980             n2 = set2->nodeTab[i];
3981             /*
3982             * Skip NULLed entries.
3983             */
3984             if (n2 == NULL)
3985                 continue;
3986             /*
3987             * Skip duplicates.
3988             */
3989             for (j = 0; j < initNbSet1; j++) {
3990                 n1 = set1->nodeTab[j];
3991                 if (n1 == n2) {
3992                     goto skip_node;
3993                 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3994                     (n2->type == XML_NAMESPACE_DECL))
3995                 {
3996                     if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3997                         (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3998                         ((xmlNsPtr) n2)->prefix)))
3999                     {
4000                         /*
4001                         * Free the namespace node.
4002                         */
4003                         set2->nodeTab[i] = NULL;
4004                         xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
4005                         goto skip_node;
4006                     }
4007                 }
4008             }
4009             /*
4010             * grow the nodeTab if needed
4011             */
4012             if (set1->nodeMax == 0) {
4013                 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4014                     XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4015                 if (set1->nodeTab == NULL) {
4016                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4017                     return(NULL);
4018                 }
4019                 memset(set1->nodeTab, 0,
4020                     XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4021                 set1->nodeMax = XML_NODESET_DEFAULT;
4022             } else if (set1->nodeNr >= set1->nodeMax) {
4023                 xmlNodePtr *temp;
4024
4025                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4026                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4027                     return(NULL);
4028                 }
4029                 temp = (xmlNodePtr *) xmlRealloc(
4030                     set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4031                 if (temp == NULL) {
4032                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4033                     return(NULL);
4034                 }
4035                 set1->nodeTab = temp;
4036                 set1->nodeMax *= 2;
4037             }
4038             set1->nodeTab[set1->nodeNr++] = n2;
4039 skip_node:
4040             {}
4041         }
4042     }
4043     set2->nodeNr = 0;
4044     return(set1);
4045 }
4046
4047 /**
4048  * xmlXPathNodeSetMergeAndClearNoDupls:
4049  * @set1:  the first NodeSet or NULL
4050  * @set2:  the second NodeSet
4051  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4052  *
4053  * Merges two nodesets, all nodes from @set2 are added to @set1
4054  * if @set1 is NULL, a new set is created and copied from @set2.
4055  * Doesn't chack for duplicate nodes. Clears set2.
4056  *
4057  * Returns @set1 once extended or NULL in case of error.
4058  */
4059 static xmlNodeSetPtr
4060 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4061                                     int hasNullEntries)
4062 {
4063     if (set2 == NULL)
4064         return(set1);
4065     if ((set1 == NULL) && (hasNullEntries == 0)) {
4066         /*
4067         * Note that doing a memcpy of the list, namespace nodes are
4068         * just assigned to set1, since set2 is cleared anyway.
4069         */
4070         set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4071         if (set1 == NULL)
4072             return(NULL);
4073         if (set2->nodeNr != 0) {
4074             memcpy(set1->nodeTab, set2->nodeTab,
4075                 set2->nodeNr * sizeof(xmlNodePtr));
4076             set1->nodeNr = set2->nodeNr;
4077         }
4078     } else {
4079         int i;
4080         xmlNodePtr n2;
4081
4082         if (set1 == NULL)
4083             set1 = xmlXPathNodeSetCreate(NULL);
4084         if (set1 == NULL)
4085             return (NULL);
4086
4087         for (i = 0;i < set2->nodeNr;i++) {
4088             n2 = set2->nodeTab[i];
4089             /*
4090             * Skip NULLed entries.
4091             */
4092             if (n2 == NULL)
4093                 continue;
4094             if (set1->nodeMax == 0) {
4095                 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4096                     XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4097                 if (set1->nodeTab == NULL) {
4098                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4099                     return(NULL);
4100                 }
4101                 memset(set1->nodeTab, 0,
4102                     XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4103                 set1->nodeMax = XML_NODESET_DEFAULT;
4104             } else if (set1->nodeNr >= set1->nodeMax) {
4105                 xmlNodePtr *temp;
4106
4107                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4108                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4109                     return(NULL);
4110                 }
4111                 temp = (xmlNodePtr *) xmlRealloc(
4112                     set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4113                 if (temp == NULL) {
4114                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4115                     return(NULL);
4116                 }
4117                 set1->nodeTab = temp;
4118                 set1->nodeMax *= 2;
4119             }
4120             set1->nodeTab[set1->nodeNr++] = n2;
4121         }
4122     }
4123     set2->nodeNr = 0;
4124     return(set1);
4125 }
4126
4127 /**
4128  * xmlXPathNodeSetDel:
4129  * @cur:  the initial node set
4130  * @val:  an xmlNodePtr
4131  *
4132  * Removes an xmlNodePtr from an existing NodeSet
4133  */
4134 void
4135 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4136     int i;
4137
4138     if (cur == NULL) return;
4139     if (val == NULL) return;
4140
4141     /*
4142      * find node in nodeTab
4143      */
4144     for (i = 0;i < cur->nodeNr;i++)
4145         if (cur->nodeTab[i] == val) break;
4146
4147     if (i >= cur->nodeNr) {     /* not found */
4148 #ifdef DEBUG
4149         xmlGenericError(xmlGenericErrorContext,
4150                 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4151                 val->name);
4152 #endif
4153         return;
4154     }
4155     if ((cur->nodeTab[i] != NULL) &&
4156         (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4157         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4158     cur->nodeNr--;
4159     for (;i < cur->nodeNr;i++)
4160         cur->nodeTab[i] = cur->nodeTab[i + 1];
4161     cur->nodeTab[cur->nodeNr] = NULL;
4162 }
4163
4164 /**
4165  * xmlXPathNodeSetRemove:
4166  * @cur:  the initial node set
4167  * @val:  the index to remove
4168  *
4169  * Removes an entry from an existing NodeSet list.
4170  */
4171 void
4172 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4173     if (cur == NULL) return;
4174     if (val >= cur->nodeNr) return;
4175     if ((cur->nodeTab[val] != NULL) &&
4176         (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4177         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4178     cur->nodeNr--;
4179     for (;val < cur->nodeNr;val++)
4180         cur->nodeTab[val] = cur->nodeTab[val + 1];
4181     cur->nodeTab[cur->nodeNr] = NULL;
4182 }
4183
4184 /**
4185  * xmlXPathFreeNodeSet:
4186  * @obj:  the xmlNodeSetPtr to free
4187  *
4188  * Free the NodeSet compound (not the actual nodes !).
4189  */
4190 void
4191 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4192     if (obj == NULL) return;
4193     if (obj->nodeTab != NULL) {
4194         int i;
4195
4196         /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4197         for (i = 0;i < obj->nodeNr;i++)
4198             if ((obj->nodeTab[i] != NULL) &&
4199                 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4200                 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4201         xmlFree(obj->nodeTab);
4202     }
4203     xmlFree(obj);
4204 }
4205
4206 /**
4207  * xmlXPathNodeSetClearFromPos:
4208  * @set: the node set to be cleared
4209  * @pos: the start position to clear from
4210  *
4211  * Clears the list from temporary XPath objects (e.g. namespace nodes
4212  * are feed) starting with the entry at @pos, but does *not* free the list
4213  * itself. Sets the length of the list to @pos.
4214  */
4215 static void
4216 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4217 {
4218     if ((set == NULL) || (pos >= set->nodeNr))
4219         return;
4220     else if ((hasNsNodes)) {
4221         int i;
4222         xmlNodePtr node;
4223
4224         for (i = pos; i < set->nodeNr; i++) {
4225             node = set->nodeTab[i];
4226             if ((node != NULL) &&
4227                 (node->type == XML_NAMESPACE_DECL))
4228                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4229         }
4230     }
4231     set->nodeNr = pos;
4232 }
4233
4234 /**
4235  * xmlXPathNodeSetClear:
4236  * @set:  the node set to clear
4237  *
4238  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4239  * are feed), but does *not* free the list itself. Sets the length of the
4240  * list to 0.
4241  */
4242 static void
4243 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4244 {
4245     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4246 }
4247
4248 /**
4249  * xmlXPathNodeSetKeepLast:
4250  * @set: the node set to be cleared
4251  *
4252  * Move the last node to the first position and clear temporary XPath objects
4253  * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4254  * to 1.
4255  */
4256 static void
4257 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4258 {
4259     int i;
4260     xmlNodePtr node;
4261
4262     if ((set == NULL) || (set->nodeNr <= 1))
4263         return;
4264     for (i = 0; i < set->nodeNr - 1; i++) {
4265         node = set->nodeTab[i];
4266         if ((node != NULL) &&
4267             (node->type == XML_NAMESPACE_DECL))
4268             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4269     }
4270     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4271     set->nodeNr = 1;
4272 }
4273
4274 /**
4275  * xmlXPathFreeValueTree:
4276  * @obj:  the xmlNodeSetPtr to free
4277  *
4278  * Free the NodeSet compound and the actual tree, this is different
4279  * from xmlXPathFreeNodeSet()
4280  */
4281 static void
4282 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4283     int i;
4284
4285     if (obj == NULL) return;
4286
4287     if (obj->nodeTab != NULL) {
4288         for (i = 0;i < obj->nodeNr;i++) {
4289             if (obj->nodeTab[i] != NULL) {
4290                 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4291                     xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4292                 } else {
4293                     xmlFreeNodeList(obj->nodeTab[i]);
4294                 }
4295             }
4296         }
4297         xmlFree(obj->nodeTab);
4298     }
4299     xmlFree(obj);
4300 }
4301
4302 #if defined(DEBUG) || defined(DEBUG_STEP)
4303 /**
4304  * xmlGenericErrorContextNodeSet:
4305  * @output:  a FILE * for the output
4306  * @obj:  the xmlNodeSetPtr to display
4307  *
4308  * Quick display of a NodeSet
4309  */
4310 void
4311 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4312     int i;
4313
4314     if (output == NULL) output = xmlGenericErrorContext;
4315     if (obj == NULL)  {
4316         fprintf(output, "NodeSet == NULL !\n");
4317         return;
4318     }
4319     if (obj->nodeNr == 0) {
4320         fprintf(output, "NodeSet is empty\n");
4321         return;
4322     }
4323     if (obj->nodeTab == NULL) {
4324         fprintf(output, " nodeTab == NULL !\n");
4325         return;
4326     }
4327     for (i = 0; i < obj->nodeNr; i++) {
4328         if (obj->nodeTab[i] == NULL) {
4329             fprintf(output, " NULL !\n");
4330             return;
4331         }
4332         if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4333             (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4334             fprintf(output, " /");
4335         else if (obj->nodeTab[i]->name == NULL)
4336             fprintf(output, " noname!");
4337         else fprintf(output, " %s", obj->nodeTab[i]->name);
4338     }
4339     fprintf(output, "\n");
4340 }
4341 #endif
4342
4343 /**
4344  * xmlXPathNewNodeSet:
4345  * @val:  the NodePtr value
4346  *
4347  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4348  * it with the single Node @val
4349  *
4350  * Returns the newly created object.
4351  */
4352 xmlXPathObjectPtr
4353 xmlXPathNewNodeSet(xmlNodePtr val) {
4354     xmlXPathObjectPtr ret;
4355
4356     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4357     if (ret == NULL) {
4358         xmlXPathErrMemory(NULL, "creating nodeset\n");
4359         return(NULL);
4360     }
4361     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4362     ret->type = XPATH_NODESET;
4363     ret->boolval = 0;
4364     ret->nodesetval = xmlXPathNodeSetCreate(val);
4365     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4366 #ifdef XP_DEBUG_OBJ_USAGE
4367     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4368 #endif
4369     return(ret);
4370 }
4371
4372 /**
4373  * xmlXPathNewValueTree:
4374  * @val:  the NodePtr value
4375  *
4376  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4377  * it with the tree root @val
4378  *
4379  * Returns the newly created object.
4380  */
4381 xmlXPathObjectPtr
4382 xmlXPathNewValueTree(xmlNodePtr val) {
4383     xmlXPathObjectPtr ret;
4384
4385     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4386     if (ret == NULL) {
4387         xmlXPathErrMemory(NULL, "creating result value tree\n");
4388         return(NULL);
4389     }
4390     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4391     ret->type = XPATH_XSLT_TREE;
4392     ret->boolval = 1;
4393     ret->user = (void *) val;
4394     ret->nodesetval = xmlXPathNodeSetCreate(val);
4395 #ifdef XP_DEBUG_OBJ_USAGE
4396     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4397 #endif
4398     return(ret);
4399 }
4400
4401 /**
4402  * xmlXPathNewNodeSetList:
4403  * @val:  an existing NodeSet
4404  *
4405  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4406  * it with the Nodeset @val
4407  *
4408  * Returns the newly created object.
4409  */
4410 xmlXPathObjectPtr
4411 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4412 {
4413     xmlXPathObjectPtr ret;
4414     int i;
4415
4416     if (val == NULL)
4417         ret = NULL;
4418     else if (val->nodeTab == NULL)
4419         ret = xmlXPathNewNodeSet(NULL);
4420     else {
4421         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4422         if (ret) {
4423             for (i = 1; i < val->nodeNr; ++i) {
4424                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4425                     < 0) break;
4426             }
4427         }
4428     }
4429
4430     return (ret);
4431 }
4432
4433 /**
4434  * xmlXPathWrapNodeSet:
4435  * @val:  the NodePtr value
4436  *
4437  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4438  *
4439  * Returns the newly created object.
4440  */
4441 xmlXPathObjectPtr
4442 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4443     xmlXPathObjectPtr ret;
4444
4445     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4446     if (ret == NULL) {
4447         xmlXPathErrMemory(NULL, "creating node set object\n");
4448         return(NULL);
4449     }
4450     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4451     ret->type = XPATH_NODESET;
4452     ret->nodesetval = val;
4453 #ifdef XP_DEBUG_OBJ_USAGE
4454     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4455 #endif
4456     return(ret);
4457 }
4458
4459 /**
4460  * xmlXPathFreeNodeSetList:
4461  * @obj:  an existing NodeSetList object
4462  *
4463  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4464  * the list contrary to xmlXPathFreeObject().
4465  */
4466 void
4467 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4468     if (obj == NULL) return;
4469 #ifdef XP_DEBUG_OBJ_USAGE
4470     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4471 #endif
4472     xmlFree(obj);
4473 }
4474
4475 /**
4476  * xmlXPathDifference:
4477  * @nodes1:  a node-set
4478  * @nodes2:  a node-set
4479  *
4480  * Implements the EXSLT - Sets difference() function:
4481  *    node-set set:difference (node-set, node-set)
4482  *
4483  * Returns the difference between the two node sets, or nodes1 if
4484  *         nodes2 is empty
4485  */
4486 xmlNodeSetPtr
4487 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4488     xmlNodeSetPtr ret;
4489     int i, l1;
4490     xmlNodePtr cur;
4491
4492     if (xmlXPathNodeSetIsEmpty(nodes2))
4493         return(nodes1);
4494
4495     ret = xmlXPathNodeSetCreate(NULL);
4496     if (xmlXPathNodeSetIsEmpty(nodes1))
4497         return(ret);
4498
4499     l1 = xmlXPathNodeSetGetLength(nodes1);
4500
4501     for (i = 0; i < l1; i++) {
4502         cur = xmlXPathNodeSetItem(nodes1, i);
4503         if (!xmlXPathNodeSetContains(nodes2, cur)) {
4504             if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4505                 break;
4506         }
4507     }
4508     return(ret);
4509 }
4510
4511 /**
4512  * xmlXPathIntersection:
4513  * @nodes1:  a node-set
4514  * @nodes2:  a node-set
4515  *
4516  * Implements the EXSLT - Sets intersection() function:
4517  *    node-set set:intersection (node-set, node-set)
4518  *
4519  * Returns a node set comprising the nodes that are within both the
4520  *         node sets passed as arguments
4521  */
4522 xmlNodeSetPtr
4523 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4524     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4525     int i, l1;
4526     xmlNodePtr cur;
4527
4528     if (ret == NULL)
4529         return(ret);
4530     if (xmlXPathNodeSetIsEmpty(nodes1))
4531         return(ret);
4532     if (xmlXPathNodeSetIsEmpty(nodes2))
4533         return(ret);
4534
4535     l1 = xmlXPathNodeSetGetLength(nodes1);
4536
4537     for (i = 0; i < l1; i++) {
4538         cur = xmlXPathNodeSetItem(nodes1, i);
4539         if (xmlXPathNodeSetContains(nodes2, cur)) {
4540             if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4541                 break;
4542         }
4543     }
4544     return(ret);
4545 }
4546
4547 /**
4548  * xmlXPathDistinctSorted:
4549  * @nodes:  a node-set, sorted by document order
4550  *
4551  * Implements the EXSLT - Sets distinct() function:
4552  *    node-set set:distinct (node-set)
4553  *
4554  * Returns a subset of the nodes contained in @nodes, or @nodes if
4555  *         it is empty
4556  */
4557 xmlNodeSetPtr
4558 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4559     xmlNodeSetPtr ret;
4560     xmlHashTablePtr hash;
4561     int i, l;
4562     xmlChar * strval;
4563     xmlNodePtr cur;
4564
4565     if (xmlXPathNodeSetIsEmpty(nodes))
4566         return(nodes);
4567
4568     ret = xmlXPathNodeSetCreate(NULL);
4569     if (ret == NULL)
4570         return(ret);
4571     l = xmlXPathNodeSetGetLength(nodes);
4572     hash = xmlHashCreate (l);
4573     for (i = 0; i < l; i++) {
4574         cur = xmlXPathNodeSetItem(nodes, i);
4575         strval = xmlXPathCastNodeToString(cur);
4576         if (xmlHashLookup(hash, strval) == NULL) {
4577             xmlHashAddEntry(hash, strval, strval);
4578             if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4579                 break;
4580         } else {
4581             xmlFree(strval);
4582         }
4583     }
4584     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4585     return(ret);
4586 }
4587
4588 /**
4589  * xmlXPathDistinct:
4590  * @nodes:  a node-set
4591  *
4592  * Implements the EXSLT - Sets distinct() function:
4593  *    node-set set:distinct (node-set)
4594  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4595  * is called with the sorted node-set
4596  *
4597  * Returns a subset of the nodes contained in @nodes, or @nodes if
4598  *         it is empty
4599  */
4600 xmlNodeSetPtr
4601 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4602     if (xmlXPathNodeSetIsEmpty(nodes))
4603         return(nodes);
4604
4605     xmlXPathNodeSetSort(nodes);
4606     return(xmlXPathDistinctSorted(nodes));
4607 }
4608
4609 /**
4610  * xmlXPathHasSameNodes:
4611  * @nodes1:  a node-set
4612  * @nodes2:  a node-set
4613  *
4614  * Implements the EXSLT - Sets has-same-nodes function:
4615  *    boolean set:has-same-node(node-set, node-set)
4616  *
4617  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4618  *         otherwise
4619  */
4620 int
4621 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4622     int i, l;
4623     xmlNodePtr cur;
4624
4625     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4626         xmlXPathNodeSetIsEmpty(nodes2))
4627         return(0);
4628
4629     l = xmlXPathNodeSetGetLength(nodes1);
4630     for (i = 0; i < l; i++) {
4631         cur = xmlXPathNodeSetItem(nodes1, i);
4632         if (xmlXPathNodeSetContains(nodes2, cur))
4633             return(1);
4634     }
4635     return(0);
4636 }
4637
4638 /**
4639  * xmlXPathNodeLeadingSorted:
4640  * @nodes: a node-set, sorted by document order
4641  * @node: a node
4642  *
4643  * Implements the EXSLT - Sets leading() function:
4644  *    node-set set:leading (node-set, node-set)
4645  *
4646  * Returns the nodes in @nodes that precede @node in document order,
4647  *         @nodes if @node is NULL or an empty node-set if @nodes
4648  *         doesn't contain @node
4649  */
4650 xmlNodeSetPtr
4651 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4652     int i, l;
4653     xmlNodePtr cur;
4654     xmlNodeSetPtr ret;
4655
4656     if (node == NULL)
4657         return(nodes);
4658
4659     ret = xmlXPathNodeSetCreate(NULL);
4660     if (ret == NULL)
4661         return(ret);
4662     if (xmlXPathNodeSetIsEmpty(nodes) ||
4663         (!xmlXPathNodeSetContains(nodes, node)))
4664         return(ret);
4665
4666     l = xmlXPathNodeSetGetLength(nodes);
4667     for (i = 0; i < l; i++) {
4668         cur = xmlXPathNodeSetItem(nodes, i);
4669         if (cur == node)
4670             break;
4671         if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4672             break;
4673     }
4674     return(ret);
4675 }
4676
4677 /**
4678  * xmlXPathNodeLeading:
4679  * @nodes:  a node-set
4680  * @node:  a node
4681  *
4682  * Implements the EXSLT - Sets leading() function:
4683  *    node-set set:leading (node-set, node-set)
4684  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4685  * is called.
4686  *
4687  * Returns the nodes in @nodes that precede @node in document order,
4688  *         @nodes if @node is NULL or an empty node-set if @nodes
4689  *         doesn't contain @node
4690  */
4691 xmlNodeSetPtr
4692 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4693     xmlXPathNodeSetSort(nodes);
4694     return(xmlXPathNodeLeadingSorted(nodes, node));
4695 }
4696
4697 /**
4698  * xmlXPathLeadingSorted:
4699  * @nodes1:  a node-set, sorted by document order
4700  * @nodes2:  a node-set, sorted by document order
4701  *
4702  * Implements the EXSLT - Sets leading() function:
4703  *    node-set set:leading (node-set, node-set)
4704  *
4705  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4706  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4707  *         an empty node-set if @nodes1 doesn't contain @nodes2
4708  */
4709 xmlNodeSetPtr
4710 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4711     if (xmlXPathNodeSetIsEmpty(nodes2))
4712         return(nodes1);
4713     return(xmlXPathNodeLeadingSorted(nodes1,
4714                                      xmlXPathNodeSetItem(nodes2, 1)));
4715 }
4716
4717 /**
4718  * xmlXPathLeading:
4719  * @nodes1:  a node-set
4720  * @nodes2:  a node-set
4721  *
4722  * Implements the EXSLT - Sets leading() function:
4723  *    node-set set:leading (node-set, node-set)
4724  * @nodes1 and @nodes2 are sorted by document order, then
4725  * #exslSetsLeadingSorted is called.
4726  *
4727  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4728  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4729  *         an empty node-set if @nodes1 doesn't contain @nodes2
4730  */
4731 xmlNodeSetPtr
4732 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4733     if (xmlXPathNodeSetIsEmpty(nodes2))
4734         return(nodes1);
4735     if (xmlXPathNodeSetIsEmpty(nodes1))
4736         return(xmlXPathNodeSetCreate(NULL));
4737     xmlXPathNodeSetSort(nodes1);
4738     xmlXPathNodeSetSort(nodes2);
4739     return(xmlXPathNodeLeadingSorted(nodes1,
4740                                      xmlXPathNodeSetItem(nodes2, 1)));
4741 }
4742
4743 /**
4744  * xmlXPathNodeTrailingSorted:
4745  * @nodes: a node-set, sorted by document order
4746  * @node: a node
4747  *
4748  * Implements the EXSLT - Sets trailing() function:
4749  *    node-set set:trailing (node-set, node-set)
4750  *
4751  * Returns the nodes in @nodes that follow @node in document order,
4752  *         @nodes if @node is NULL or an empty node-set if @nodes
4753  *         doesn't contain @node
4754  */
4755 xmlNodeSetPtr
4756 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4757     int i, l;
4758     xmlNodePtr cur;
4759     xmlNodeSetPtr ret;
4760
4761     if (node == NULL)
4762         return(nodes);
4763
4764     ret = xmlXPathNodeSetCreate(NULL);
4765     if (ret == NULL)
4766         return(ret);
4767     if (xmlXPathNodeSetIsEmpty(nodes) ||
4768         (!xmlXPathNodeSetContains(nodes, node)))
4769         return(ret);
4770
4771     l = xmlXPathNodeSetGetLength(nodes);
4772     for (i = l - 1; i >= 0; i--) {
4773         cur = xmlXPathNodeSetItem(nodes, i);
4774         if (cur == node)
4775             break;
4776         if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4777             break;
4778     }
4779     xmlXPathNodeSetSort(ret);   /* bug 413451 */
4780     return(ret);
4781 }
4782
4783 /**
4784  * xmlXPathNodeTrailing:
4785  * @nodes:  a node-set
4786  * @node:  a node
4787  *
4788  * Implements the EXSLT - Sets trailing() function:
4789  *    node-set set:trailing (node-set, node-set)
4790  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4791  * is called.
4792  *
4793  * Returns the nodes in @nodes that follow @node in document order,
4794  *         @nodes if @node is NULL or an empty node-set if @nodes
4795  *         doesn't contain @node
4796  */
4797 xmlNodeSetPtr
4798 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4799     xmlXPathNodeSetSort(nodes);
4800     return(xmlXPathNodeTrailingSorted(nodes, node));
4801 }
4802
4803 /**
4804  * xmlXPathTrailingSorted:
4805  * @nodes1:  a node-set, sorted by document order
4806  * @nodes2:  a node-set, sorted by document order
4807  *
4808  * Implements the EXSLT - Sets trailing() function:
4809  *    node-set set:trailing (node-set, node-set)
4810  *
4811  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4812  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4813  *         an empty node-set if @nodes1 doesn't contain @nodes2
4814  */
4815 xmlNodeSetPtr
4816 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4817     if (xmlXPathNodeSetIsEmpty(nodes2))
4818         return(nodes1);
4819     return(xmlXPathNodeTrailingSorted(nodes1,
4820                                       xmlXPathNodeSetItem(nodes2, 0)));
4821 }
4822
4823 /**
4824  * xmlXPathTrailing:
4825  * @nodes1:  a node-set
4826  * @nodes2:  a node-set
4827  *
4828  * Implements the EXSLT - Sets trailing() function:
4829  *    node-set set:trailing (node-set, node-set)
4830  * @nodes1 and @nodes2 are sorted by document order, then
4831  * #xmlXPathTrailingSorted is called.
4832  *
4833  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4834  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4835  *         an empty node-set if @nodes1 doesn't contain @nodes2
4836  */
4837 xmlNodeSetPtr
4838 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4839     if (xmlXPathNodeSetIsEmpty(nodes2))
4840         return(nodes1);
4841     if (xmlXPathNodeSetIsEmpty(nodes1))
4842         return(xmlXPathNodeSetCreate(NULL));
4843     xmlXPathNodeSetSort(nodes1);
4844     xmlXPathNodeSetSort(nodes2);
4845     return(xmlXPathNodeTrailingSorted(nodes1,
4846                                       xmlXPathNodeSetItem(nodes2, 0)));
4847 }
4848
4849 /************************************************************************
4850  *                                                                      *
4851  *              Routines to handle extra functions                      *
4852  *                                                                      *
4853  ************************************************************************/
4854
4855 /**
4856  * xmlXPathRegisterFunc:
4857  * @ctxt:  the XPath context
4858  * @name:  the function name
4859  * @f:  the function implementation or NULL
4860  *
4861  * Register a new function. If @f is NULL it unregisters the function
4862  *
4863  * Returns 0 in case of success, -1 in case of error
4864  */
4865 int
4866 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4867                      xmlXPathFunction f) {
4868     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4869 }
4870
4871 /**
4872  * xmlXPathRegisterFuncNS:
4873  * @ctxt:  the XPath context
4874  * @name:  the function name
4875  * @ns_uri:  the function namespace URI
4876  * @f:  the function implementation or NULL
4877  *
4878  * Register a new function. If @f is NULL it unregisters the function
4879  *
4880  * Returns 0 in case of success, -1 in case of error
4881  */
4882 int
4883 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4884                        const xmlChar *ns_uri, xmlXPathFunction f) {
4885     if (ctxt == NULL)
4886         return(-1);
4887     if (name == NULL)
4888         return(-1);
4889
4890     if (ctxt->funcHash == NULL)
4891         ctxt->funcHash = xmlHashCreate(0);
4892     if (ctxt->funcHash == NULL)
4893         return(-1);
4894     if (f == NULL)
4895         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4896     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4897 }
4898
4899 /**
4900  * xmlXPathRegisterFuncLookup:
4901  * @ctxt:  the XPath context
4902  * @f:  the lookup function
4903  * @funcCtxt:  the lookup data
4904  *
4905  * Registers an external mechanism to do function lookup.
4906  */
4907 void
4908 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4909                             xmlXPathFuncLookupFunc f,
4910                             void *funcCtxt) {
4911     if (ctxt == NULL)
4912         return;
4913     ctxt->funcLookupFunc = f;
4914     ctxt->funcLookupData = funcCtxt;
4915 }
4916
4917 /**
4918  * xmlXPathFunctionLookup:
4919  * @ctxt:  the XPath context
4920  * @name:  the function name
4921  *
4922  * Search in the Function array of the context for the given
4923  * function.
4924  *
4925  * Returns the xmlXPathFunction or NULL if not found
4926  */
4927 xmlXPathFunction
4928 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4929     if (ctxt == NULL)
4930         return (NULL);
4931
4932     if (ctxt->funcLookupFunc != NULL) {
4933         xmlXPathFunction ret;
4934         xmlXPathFuncLookupFunc f;
4935
4936         f = ctxt->funcLookupFunc;
4937         ret = f(ctxt->funcLookupData, name, NULL);
4938         if (ret != NULL)
4939             return(ret);
4940     }
4941     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4942 }
4943
4944 /**
4945  * xmlXPathFunctionLookupNS:
4946  * @ctxt:  the XPath context
4947  * @name:  the function name
4948  * @ns_uri:  the function namespace URI
4949  *
4950  * Search in the Function array of the context for the given
4951  * function.
4952  *
4953  * Returns the xmlXPathFunction or NULL if not found
4954  */
4955 xmlXPathFunction
4956 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4957                          const xmlChar *ns_uri) {
4958     xmlXPathFunction ret;
4959
4960     if (ctxt == NULL)
4961         return(NULL);
4962     if (name == NULL)
4963         return(NULL);
4964
4965     if (ctxt->funcLookupFunc != NULL) {
4966         xmlXPathFuncLookupFunc f;
4967
4968         f = ctxt->funcLookupFunc;
4969         ret = f(ctxt->funcLookupData, name, ns_uri);
4970         if (ret != NULL)
4971             return(ret);
4972     }
4973
4974     if (ctxt->funcHash == NULL)
4975         return(NULL);
4976
4977     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4978     return(ret);
4979 }
4980
4981 /**
4982  * xmlXPathRegisteredFuncsCleanup:
4983  * @ctxt:  the XPath context
4984  *
4985  * Cleanup the XPath context data associated to registered functions
4986  */
4987 void
4988 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4989     if (ctxt == NULL)
4990         return;
4991
4992     xmlHashFree(ctxt->funcHash, NULL);
4993     ctxt->funcHash = NULL;
4994 }
4995
4996 /************************************************************************
4997  *                                                                      *
4998  *                      Routines to handle Variables                    *
4999  *                                                                      *
5000  ************************************************************************/
5001
5002 /**
5003  * xmlXPathRegisterVariable:
5004  * @ctxt:  the XPath context
5005  * @name:  the variable name
5006  * @value:  the variable value or NULL
5007  *
5008  * Register a new variable value. If @value is NULL it unregisters
5009  * the variable
5010  *
5011  * Returns 0 in case of success, -1 in case of error
5012  */
5013 int
5014 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5015                          xmlXPathObjectPtr value) {
5016     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5017 }
5018
5019 /**
5020  * xmlXPathRegisterVariableNS:
5021  * @ctxt:  the XPath context
5022  * @name:  the variable name
5023  * @ns_uri:  the variable namespace URI
5024  * @value:  the variable value or NULL
5025  *
5026  * Register a new variable value. If @value is NULL it unregisters
5027  * the variable
5028  *
5029  * Returns 0 in case of success, -1 in case of error
5030  */
5031 int
5032 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5033                            const xmlChar *ns_uri,
5034                            xmlXPathObjectPtr value) {
5035     if (ctxt == NULL)
5036         return(-1);
5037     if (name == NULL)
5038         return(-1);
5039
5040     if (ctxt->varHash == NULL)
5041         ctxt->varHash = xmlHashCreate(0);
5042     if (ctxt->varHash == NULL)
5043         return(-1);
5044     if (value == NULL)
5045         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5046                                    (xmlHashDeallocator)xmlXPathFreeObject));
5047     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5048                                (void *) value,
5049                                (xmlHashDeallocator)xmlXPathFreeObject));
5050 }
5051
5052 /**
5053  * xmlXPathRegisterVariableLookup:
5054  * @ctxt:  the XPath context
5055  * @f:  the lookup function
5056  * @data:  the lookup data
5057  *
5058  * register an external mechanism to do variable lookup
5059  */
5060 void
5061 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5062          xmlXPathVariableLookupFunc f, void *data) {
5063     if (ctxt == NULL)
5064         return;
5065     ctxt->varLookupFunc = f;
5066     ctxt->varLookupData = data;
5067 }
5068
5069 /**
5070  * xmlXPathVariableLookup:
5071  * @ctxt:  the XPath context
5072  * @name:  the variable name
5073  *
5074  * Search in the Variable array of the context for the given
5075  * variable value.
5076  *
5077  * Returns a copy of the value or NULL if not found
5078  */
5079 xmlXPathObjectPtr
5080 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5081     if (ctxt == NULL)
5082         return(NULL);
5083
5084     if (ctxt->varLookupFunc != NULL) {
5085         xmlXPathObjectPtr ret;
5086
5087         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5088                 (ctxt->varLookupData, name, NULL);
5089         return(ret);
5090     }
5091     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5092 }
5093
5094 /**
5095  * xmlXPathVariableLookupNS:
5096  * @ctxt:  the XPath context
5097  * @name:  the variable name
5098  * @ns_uri:  the variable namespace URI
5099  *
5100  * Search in the Variable array of the context for the given
5101  * variable value.
5102  *
5103  * Returns the a copy of the value or NULL if not found
5104  */
5105 xmlXPathObjectPtr
5106 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5107                          const xmlChar *ns_uri) {
5108     if (ctxt == NULL)
5109         return(NULL);
5110
5111     if (ctxt->varLookupFunc != NULL) {
5112         xmlXPathObjectPtr ret;
5113
5114         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5115                 (ctxt->varLookupData, name, ns_uri);
5116         if (ret != NULL) return(ret);
5117     }
5118
5119     if (ctxt->varHash == NULL)
5120         return(NULL);
5121     if (name == NULL)
5122         return(NULL);
5123
5124     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5125                 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5126 }
5127
5128 /**
5129  * xmlXPathRegisteredVariablesCleanup:
5130  * @ctxt:  the XPath context
5131  *
5132  * Cleanup the XPath context data associated to registered variables
5133  */
5134 void
5135 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5136     if (ctxt == NULL)
5137         return;
5138
5139     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5140     ctxt->varHash = NULL;
5141 }
5142
5143 /**
5144  * xmlXPathRegisterNs:
5145  * @ctxt:  the XPath context
5146  * @prefix:  the namespace prefix cannot be NULL or empty string
5147  * @ns_uri:  the namespace name
5148  *
5149  * Register a new namespace. If @ns_uri is NULL it unregisters
5150  * the namespace
5151  *
5152  * Returns 0 in case of success, -1 in case of error
5153  */
5154 int
5155 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5156                            const xmlChar *ns_uri) {
5157     if (ctxt == NULL)
5158         return(-1);
5159     if (prefix == NULL)
5160         return(-1);
5161     if (prefix[0] == 0)
5162         return(-1);
5163
5164     if (ctxt->nsHash == NULL)
5165         ctxt->nsHash = xmlHashCreate(10);
5166     if (ctxt->nsHash == NULL)
5167         return(-1);
5168     if (ns_uri == NULL)
5169         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5170                                   (xmlHashDeallocator)xmlFree));
5171     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5172                               (xmlHashDeallocator)xmlFree));
5173 }
5174
5175 /**
5176  * xmlXPathNsLookup:
5177  * @ctxt:  the XPath context
5178  * @prefix:  the namespace prefix value
5179  *
5180  * Search in the namespace declaration array of the context for the given
5181  * namespace name associated to the given prefix
5182  *
5183  * Returns the value or NULL if not found
5184  */
5185 const xmlChar *
5186 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5187     if (ctxt == NULL)
5188         return(NULL);
5189     if (prefix == NULL)
5190         return(NULL);
5191
5192 #ifdef XML_XML_NAMESPACE
5193     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5194         return(XML_XML_NAMESPACE);
5195 #endif
5196
5197     if (ctxt->namespaces != NULL) {
5198         int i;
5199
5200         for (i = 0;i < ctxt->nsNr;i++) {
5201             if ((ctxt->namespaces[i] != NULL) &&
5202                 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5203                 return(ctxt->namespaces[i]->href);
5204         }
5205     }
5206
5207     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5208 }
5209
5210 /**
5211  * xmlXPathRegisteredNsCleanup:
5212  * @ctxt:  the XPath context
5213  *
5214  * Cleanup the XPath context data associated to registered variables
5215  */
5216 void
5217 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5218     if (ctxt == NULL)
5219         return;
5220
5221     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5222     ctxt->nsHash = NULL;
5223 }
5224
5225 /************************************************************************
5226  *                                                                      *
5227  *                      Routines to handle Values                       *
5228  *                                                                      *
5229  ************************************************************************/
5230
5231 /* Allocations are terrible, one needs to optimize all this !!! */
5232
5233 /**
5234  * xmlXPathNewFloat:
5235  * @val:  the double value
5236  *
5237  * Create a new xmlXPathObjectPtr of type double and of value @val
5238  *
5239  * Returns the newly created object.
5240  */
5241 xmlXPathObjectPtr
5242 xmlXPathNewFloat(double val) {
5243     xmlXPathObjectPtr ret;
5244
5245     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5246     if (ret == NULL) {
5247         xmlXPathErrMemory(NULL, "creating float object\n");
5248         return(NULL);
5249     }
5250     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5251     ret->type = XPATH_NUMBER;
5252     ret->floatval = val;
5253 #ifdef XP_DEBUG_OBJ_USAGE
5254     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5255 #endif
5256     return(ret);
5257 }
5258
5259 /**
5260  * xmlXPathNewBoolean:
5261  * @val:  the boolean value
5262  *
5263  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5264  *
5265  * Returns the newly created object.
5266  */
5267 xmlXPathObjectPtr
5268 xmlXPathNewBoolean(int val) {
5269     xmlXPathObjectPtr ret;
5270
5271     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5272     if (ret == NULL) {
5273         xmlXPathErrMemory(NULL, "creating boolean object\n");
5274         return(NULL);
5275     }
5276     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5277     ret->type = XPATH_BOOLEAN;
5278     ret->boolval = (val != 0);
5279 #ifdef XP_DEBUG_OBJ_USAGE
5280     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5281 #endif
5282     return(ret);
5283 }
5284
5285 /**
5286  * xmlXPathNewString:
5287  * @val:  the xmlChar * value
5288  *
5289  * Create a new xmlXPathObjectPtr of type string and of value @val
5290  *
5291  * Returns the newly created object.
5292  */
5293 xmlXPathObjectPtr
5294 xmlXPathNewString(const xmlChar *val) {
5295     xmlXPathObjectPtr ret;
5296
5297     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5298     if (ret == NULL) {
5299         xmlXPathErrMemory(NULL, "creating string object\n");
5300         return(NULL);
5301     }
5302     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5303     ret->type = XPATH_STRING;
5304     if (val != NULL)
5305         ret->stringval = xmlStrdup(val);
5306     else
5307         ret->stringval = xmlStrdup((const xmlChar *)"");
5308 #ifdef XP_DEBUG_OBJ_USAGE
5309     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5310 #endif
5311     return(ret);
5312 }
5313
5314 /**
5315  * xmlXPathWrapString:
5316  * @val:  the xmlChar * value
5317  *
5318  * Wraps the @val string into an XPath object.
5319  *
5320  * Returns the newly created object.
5321  */
5322 xmlXPathObjectPtr
5323 xmlXPathWrapString (xmlChar *val) {
5324     xmlXPathObjectPtr ret;
5325
5326     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5327     if (ret == NULL) {
5328         xmlXPathErrMemory(NULL, "creating string object\n");
5329         return(NULL);
5330     }
5331     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5332     ret->type = XPATH_STRING;
5333     ret->stringval = val;
5334 #ifdef XP_DEBUG_OBJ_USAGE
5335     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5336 #endif
5337     return(ret);
5338 }
5339
5340 /**
5341  * xmlXPathNewCString:
5342  * @val:  the char * value
5343  *
5344  * Create a new xmlXPathObjectPtr of type string and of value @val
5345  *
5346  * Returns the newly created object.
5347  */
5348 xmlXPathObjectPtr
5349 xmlXPathNewCString(const char *val) {
5350     xmlXPathObjectPtr ret;
5351
5352     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5353     if (ret == NULL) {
5354         xmlXPathErrMemory(NULL, "creating string object\n");
5355         return(NULL);
5356     }
5357     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5358     ret->type = XPATH_STRING;
5359     ret->stringval = xmlStrdup(BAD_CAST val);
5360 #ifdef XP_DEBUG_OBJ_USAGE
5361     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5362 #endif
5363     return(ret);
5364 }
5365
5366 /**
5367  * xmlXPathWrapCString:
5368  * @val:  the char * value
5369  *
5370  * Wraps a string into an XPath object.
5371  *
5372  * Returns the newly created object.
5373  */
5374 xmlXPathObjectPtr
5375 xmlXPathWrapCString (char * val) {
5376     return(xmlXPathWrapString((xmlChar *)(val)));
5377 }
5378
5379 /**
5380  * xmlXPathWrapExternal:
5381  * @val:  the user data
5382  *
5383  * Wraps the @val data into an XPath object.
5384  *
5385  * Returns the newly created object.
5386  */
5387 xmlXPathObjectPtr
5388 xmlXPathWrapExternal (void *val) {
5389     xmlXPathObjectPtr ret;
5390
5391     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5392     if (ret == NULL) {
5393         xmlXPathErrMemory(NULL, "creating user object\n");
5394         return(NULL);
5395     }
5396     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5397     ret->type = XPATH_USERS;
5398     ret->user = val;
5399 #ifdef XP_DEBUG_OBJ_USAGE
5400     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5401 #endif
5402     return(ret);
5403 }
5404
5405 /**
5406  * xmlXPathObjectCopy:
5407  * @val:  the original object
5408  *
5409  * allocate a new copy of a given object
5410  *
5411  * Returns the newly created object.
5412  */
5413 xmlXPathObjectPtr
5414 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5415     xmlXPathObjectPtr ret;
5416
5417     if (val == NULL)
5418         return(NULL);
5419
5420     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5421     if (ret == NULL) {
5422         xmlXPathErrMemory(NULL, "copying object\n");
5423         return(NULL);
5424     }
5425     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5426 #ifdef XP_DEBUG_OBJ_USAGE
5427     xmlXPathDebugObjUsageRequested(NULL, val->type);
5428 #endif
5429     switch (val->type) {
5430         case XPATH_BOOLEAN:
5431         case XPATH_NUMBER:
5432         case XPATH_POINT:
5433         case XPATH_RANGE:
5434             break;
5435         case XPATH_STRING:
5436             ret->stringval = xmlStrdup(val->stringval);
5437             break;
5438         case XPATH_XSLT_TREE:
5439 #if 0
5440 /*
5441   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5442   this previous handling is no longer correct, and can cause some serious
5443   problems (ref. bug 145547)
5444 */
5445             if ((val->nodesetval != NULL) &&
5446                 (val->nodesetval->nodeTab != NULL)) {
5447                 xmlNodePtr cur, tmp;
5448                 xmlDocPtr top;
5449
5450                 ret->boolval = 1;
5451                 top =  xmlNewDoc(NULL);
5452                 top->name = (char *)
5453                     xmlStrdup(val->nodesetval->nodeTab[0]->name);
5454                 ret->user = top;
5455                 if (top != NULL) {
5456                     top->doc = top;
5457                     cur = val->nodesetval->nodeTab[0]->children;
5458                     while (cur != NULL) {
5459                         tmp = xmlDocCopyNode(cur, top, 1);
5460                         xmlAddChild((xmlNodePtr) top, tmp);
5461                         cur = cur->next;
5462                     }
5463                 }
5464
5465                 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5466             } else
5467                 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5468             /* Deallocate the copied tree value */
5469             break;
5470 #endif
5471         case XPATH_NODESET:
5472             ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5473             /* Do not deallocate the copied tree value */
5474             ret->boolval = 0;
5475             break;
5476         case XPATH_LOCATIONSET:
5477 #ifdef LIBXML_XPTR_ENABLED
5478         {
5479             xmlLocationSetPtr loc = val->user;
5480             ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5481             break;
5482         }
5483 #endif
5484         case XPATH_USERS:
5485             ret->user = val->user;
5486             break;
5487         case XPATH_UNDEFINED:
5488             xmlGenericError(xmlGenericErrorContext,
5489                     "xmlXPathObjectCopy: unsupported type %d\n",
5490                     val->type);
5491             break;
5492     }
5493     return(ret);
5494 }
5495
5496 /**
5497  * xmlXPathFreeObject:
5498  * @obj:  the object to free
5499  *
5500  * Free up an xmlXPathObjectPtr object.
5501  */
5502 void
5503 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5504     if (obj == NULL) return;
5505     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5506         if (obj->boolval) {
5507 #if 0
5508             if (obj->user != NULL) {
5509                 xmlXPathFreeNodeSet(obj->nodesetval);
5510                 xmlFreeNodeList((xmlNodePtr) obj->user);
5511             } else
5512 #endif
5513             obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5514             if (obj->nodesetval != NULL)
5515                 xmlXPathFreeValueTree(obj->nodesetval);
5516         } else {
5517             if (obj->nodesetval != NULL)
5518                 xmlXPathFreeNodeSet(obj->nodesetval);
5519         }
5520 #ifdef LIBXML_XPTR_ENABLED
5521     } else if (obj->type == XPATH_LOCATIONSET) {
5522         if (obj->user != NULL)
5523             xmlXPtrFreeLocationSet(obj->user);
5524 #endif
5525     } else if (obj->type == XPATH_STRING) {
5526         if (obj->stringval != NULL)
5527             xmlFree(obj->stringval);
5528     }
5529 #ifdef XP_DEBUG_OBJ_USAGE
5530     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5531 #endif
5532     xmlFree(obj);
5533 }
5534
5535 /**
5536  * xmlXPathReleaseObject:
5537  * @obj:  the xmlXPathObjectPtr to free or to cache
5538  *
5539  * Depending on the state of the cache this frees the given
5540  * XPath object or stores it in the cache.
5541  */
5542 static void
5543 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5544 {
5545 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5546         sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5547     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5548
5549 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5550
5551     if (obj == NULL)
5552         return;
5553     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5554          xmlXPathFreeObject(obj);
5555     } else {
5556         xmlXPathContextCachePtr cache =
5557             (xmlXPathContextCachePtr) ctxt->cache;
5558
5559         switch (obj->type) {
5560             case XPATH_NODESET:
5561             case XPATH_XSLT_TREE:
5562                 if (obj->nodesetval != NULL) {
5563                     if (obj->boolval) {
5564                         /*
5565                         * It looks like the @boolval is used for
5566                         * evaluation if this an XSLT Result Tree Fragment.
5567                         * TODO: Check if this assumption is correct.
5568                         */
5569                         obj->type = XPATH_XSLT_TREE; /* just for debugging */
5570                         xmlXPathFreeValueTree(obj->nodesetval);
5571                         obj->nodesetval = NULL;
5572                     } else if ((obj->nodesetval->nodeMax <= 40) &&
5573                         (XP_CACHE_WANTS(cache->nodesetObjs,
5574                                         cache->maxNodeset)))
5575                     {
5576                         XP_CACHE_ADD(cache->nodesetObjs, obj);
5577                         goto obj_cached;
5578                     } else {
5579                         xmlXPathFreeNodeSet(obj->nodesetval);
5580                         obj->nodesetval = NULL;
5581                     }
5582                 }
5583                 break;
5584             case XPATH_STRING:
5585                 if (obj->stringval != NULL)
5586                     xmlFree(obj->stringval);
5587
5588                 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5589                     XP_CACHE_ADD(cache->stringObjs, obj);
5590                     goto obj_cached;
5591                 }
5592                 break;
5593             case XPATH_BOOLEAN:
5594                 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5595                     XP_CACHE_ADD(cache->booleanObjs, obj);
5596                     goto obj_cached;
5597                 }
5598                 break;
5599             case XPATH_NUMBER:
5600                 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5601                     XP_CACHE_ADD(cache->numberObjs, obj);
5602                     goto obj_cached;
5603                 }
5604                 break;
5605 #ifdef LIBXML_XPTR_ENABLED
5606             case XPATH_LOCATIONSET:
5607                 if (obj->user != NULL) {
5608                     xmlXPtrFreeLocationSet(obj->user);
5609                 }
5610                 goto free_obj;
5611 #endif
5612             default:
5613                 goto free_obj;
5614         }
5615
5616         /*
5617         * Fallback to adding to the misc-objects slot.
5618         */
5619         if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5620             XP_CACHE_ADD(cache->miscObjs, obj);
5621         } else
5622             goto free_obj;
5623
5624 obj_cached:
5625
5626 #ifdef XP_DEBUG_OBJ_USAGE
5627         xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5628 #endif
5629
5630         if (obj->nodesetval != NULL) {
5631             xmlNodeSetPtr tmpset = obj->nodesetval;
5632
5633             /*
5634             * TODO: Due to those nasty ns-nodes, we need to traverse
5635             *  the list and free the ns-nodes.
5636             * URGENT TODO: Check if it's actually slowing things down.
5637             *  Maybe we shouldn't try to preserve the list.
5638             */
5639             if (tmpset->nodeNr > 1) {
5640                 int i;
5641                 xmlNodePtr node;
5642
5643                 for (i = 0; i < tmpset->nodeNr; i++) {
5644                     node = tmpset->nodeTab[i];
5645                     if ((node != NULL) &&
5646                         (node->type == XML_NAMESPACE_DECL))
5647                     {
5648                         xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5649                     }
5650                 }
5651             } else if (tmpset->nodeNr == 1) {
5652                 if ((tmpset->nodeTab[0] != NULL) &&
5653                     (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5654                     xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5655             }
5656             tmpset->nodeNr = 0;
5657             memset(obj, 0, sizeof(xmlXPathObject));
5658             obj->nodesetval = tmpset;
5659         } else
5660             memset(obj, 0, sizeof(xmlXPathObject));
5661
5662         return;
5663
5664 free_obj:
5665         /*
5666         * Cache is full; free the object.
5667         */
5668         if (obj->nodesetval != NULL)
5669             xmlXPathFreeNodeSet(obj->nodesetval);
5670 #ifdef XP_DEBUG_OBJ_USAGE
5671         xmlXPathDebugObjUsageReleased(NULL, obj->type);
5672 #endif
5673         xmlFree(obj);
5674     }
5675     return;
5676 }
5677
5678
5679 /************************************************************************
5680  *                                                                      *
5681  *                      Type Casting Routines                           *
5682  *                                                                      *
5683  ************************************************************************/
5684
5685 /**
5686  * xmlXPathCastBooleanToString:
5687  * @val:  a boolean
5688  *
5689  * Converts a boolean to its string value.
5690  *
5691  * Returns a newly allocated string.
5692  */
5693 xmlChar *
5694 xmlXPathCastBooleanToString (int val) {
5695     xmlChar *ret;
5696     if (val)
5697         ret = xmlStrdup((const xmlChar *) "true");
5698     else
5699         ret = xmlStrdup((const xmlChar *) "false");
5700     return(ret);
5701 }
5702
5703 /**
5704  * xmlXPathCastNumberToString:
5705  * @val:  a number
5706  *
5707  * Converts a number to its string value.
5708  *
5709  * Returns a newly allocated string.
5710  */
5711 xmlChar *
5712 xmlXPathCastNumberToString (double val) {
5713     xmlChar *ret;
5714     switch (xmlXPathIsInf(val)) {
5715     case 1:
5716         ret = xmlStrdup((const xmlChar *) "Infinity");
5717         break;
5718     case -1:
5719         ret = xmlStrdup((const xmlChar *) "-Infinity");
5720         break;
5721     default:
5722         if (xmlXPathIsNaN(val)) {
5723             ret = xmlStrdup((const xmlChar *) "NaN");
5724         } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5725             ret = xmlStrdup((const xmlChar *) "0");
5726         } else {
5727             /* could be improved */
5728             char buf[100];
5729             xmlXPathFormatNumber(val, buf, 99);
5730             buf[99] = 0;
5731             ret = xmlStrdup((const xmlChar *) buf);
5732         }
5733     }
5734     return(ret);
5735 }
5736
5737 /**
5738  * xmlXPathCastNodeToString:
5739  * @node:  a node
5740  *
5741  * Converts a node to its string value.
5742  *
5743  * Returns a newly allocated string.
5744  */
5745 xmlChar *
5746 xmlXPathCastNodeToString (xmlNodePtr node) {
5747 xmlChar *ret;
5748     if ((ret = xmlNodeGetContent(node)) == NULL)
5749         ret = xmlStrdup((const xmlChar *) "");
5750     return(ret);
5751 }
5752
5753 /**
5754  * xmlXPathCastNodeSetToString:
5755  * @ns:  a node-set
5756  *
5757  * Converts a node-set to its string value.
5758  *
5759  * Returns a newly allocated string.
5760  */
5761 xmlChar *
5762 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5763     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5764         return(xmlStrdup((const xmlChar *) ""));
5765
5766     if (ns->nodeNr > 1)
5767         xmlXPathNodeSetSort(ns);
5768     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5769 }
5770
5771 /**
5772  * xmlXPathCastToString:
5773  * @val:  an XPath object
5774  *
5775  * Converts an existing object to its string() equivalent
5776  *
5777  * Returns the allocated string value of the object, NULL in case of error.
5778  *         It's up to the caller to free the string memory with xmlFree().
5779  */
5780 xmlChar *
5781 xmlXPathCastToString(xmlXPathObjectPtr val) {
5782     xmlChar *ret = NULL;
5783
5784     if (val == NULL)
5785         return(xmlStrdup((const xmlChar *) ""));
5786     switch (val->type) {
5787         case XPATH_UNDEFINED:
5788 #ifdef DEBUG_EXPR
5789             xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5790 #endif
5791             ret = xmlStrdup((const xmlChar *) "");
5792             break;
5793         case XPATH_NODESET:
5794         case XPATH_XSLT_TREE:
5795             ret = xmlXPathCastNodeSetToString(val->nodesetval);
5796             break;
5797         case XPATH_STRING:
5798             return(xmlStrdup(val->stringval));
5799         case XPATH_BOOLEAN:
5800             ret = xmlXPathCastBooleanToString(val->boolval);
5801             break;
5802         case XPATH_NUMBER: {
5803             ret = xmlXPathCastNumberToString(val->floatval);
5804             break;
5805         }
5806         case XPATH_USERS:
5807         case XPATH_POINT:
5808         case XPATH_RANGE:
5809         case XPATH_LOCATIONSET:
5810             TODO
5811             ret = xmlStrdup((const xmlChar *) "");
5812             break;
5813     }
5814     return(ret);
5815 }
5816
5817 /**
5818  * xmlXPathConvertString:
5819  * @val:  an XPath object
5820  *
5821  * Converts an existing object to its string() equivalent
5822  *
5823  * Returns the new object, the old one is freed (or the operation
5824  *         is done directly on @val)
5825  */
5826 xmlXPathObjectPtr
5827 xmlXPathConvertString(xmlXPathObjectPtr val) {
5828     xmlChar *res = NULL;
5829
5830     if (val == NULL)
5831         return(xmlXPathNewCString(""));
5832
5833     switch (val->type) {
5834     case XPATH_UNDEFINED:
5835 #ifdef DEBUG_EXPR
5836         xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5837 #endif
5838         break;
5839     case XPATH_NODESET:
5840     case XPATH_XSLT_TREE:
5841         res = xmlXPathCastNodeSetToString(val->nodesetval);
5842         break;
5843     case XPATH_STRING:
5844         return(val);
5845     case XPATH_BOOLEAN:
5846         res = xmlXPathCastBooleanToString(val->boolval);
5847         break;
5848     case XPATH_NUMBER:
5849         res = xmlXPathCastNumberToString(val->floatval);
5850         break;
5851     case XPATH_USERS:
5852     case XPATH_POINT:
5853     case XPATH_RANGE:
5854     case XPATH_LOCATIONSET:
5855         TODO;
5856         break;
5857     }
5858     xmlXPathFreeObject(val);
5859     if (res == NULL)
5860         return(xmlXPathNewCString(""));
5861     return(xmlXPathWrapString(res));
5862 }
5863
5864 /**
5865  * xmlXPathCastBooleanToNumber:
5866  * @val:  a boolean
5867  *
5868  * Converts a boolean to its number value
5869  *
5870  * Returns the number value
5871  */
5872 double
5873 xmlXPathCastBooleanToNumber(int val) {
5874     if (val)
5875         return(1.0);
5876     return(0.0);
5877 }
5878
5879 /**
5880  * xmlXPathCastStringToNumber:
5881  * @val:  a string
5882  *
5883  * Converts a string to its number value
5884  *
5885  * Returns the number value
5886  */
5887 double
5888 xmlXPathCastStringToNumber(const xmlChar * val) {
5889     return(xmlXPathStringEvalNumber(val));
5890 }
5891
5892 /**
5893  * xmlXPathCastNodeToNumber:
5894  * @node:  a node
5895  *
5896  * Converts a node to its number value
5897  *
5898  * Returns the number value
5899  */
5900 double
5901 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5902     xmlChar *strval;
5903     double ret;
5904
5905     if (node == NULL)
5906         return(xmlXPathNAN);
5907     strval = xmlXPathCastNodeToString(node);
5908     if (strval == NULL)
5909         return(xmlXPathNAN);
5910     ret = xmlXPathCastStringToNumber(strval);
5911     xmlFree(strval);
5912
5913     return(ret);
5914 }
5915
5916 /**
5917  * xmlXPathCastNodeSetToNumber:
5918  * @ns:  a node-set
5919  *
5920  * Converts a node-set to its number value
5921  *
5922  * Returns the number value
5923  */
5924 double
5925 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5926     xmlChar *str;
5927     double ret;
5928
5929     if (ns == NULL)
5930         return(xmlXPathNAN);
5931     str = xmlXPathCastNodeSetToString(ns);
5932     ret = xmlXPathCastStringToNumber(str);
5933     xmlFree(str);
5934     return(ret);
5935 }
5936
5937 /**
5938  * xmlXPathCastToNumber:
5939  * @val:  an XPath object
5940  *
5941  * Converts an XPath object to its number value
5942  *
5943  * Returns the number value
5944  */
5945 double
5946 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5947     double ret = 0.0;
5948
5949     if (val == NULL)
5950         return(xmlXPathNAN);
5951     switch (val->type) {
5952     case XPATH_UNDEFINED:
5953 #ifdef DEGUB_EXPR
5954         xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5955 #endif
5956         ret = xmlXPathNAN;
5957         break;
5958     case XPATH_NODESET:
5959     case XPATH_XSLT_TREE:
5960         ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5961         break;
5962     case XPATH_STRING:
5963         ret = xmlXPathCastStringToNumber(val->stringval);
5964         break;
5965     case XPATH_NUMBER:
5966         ret = val->floatval;
5967         break;
5968     case XPATH_BOOLEAN:
5969         ret = xmlXPathCastBooleanToNumber(val->boolval);
5970         break;
5971     case XPATH_USERS:
5972     case XPATH_POINT:
5973     case XPATH_RANGE:
5974     case XPATH_LOCATIONSET:
5975         TODO;
5976         ret = xmlXPathNAN;
5977         break;
5978     }
5979     return(ret);
5980 }
5981
5982 /**
5983  * xmlXPathConvertNumber:
5984  * @val:  an XPath object
5985  *
5986  * Converts an existing object to its number() equivalent
5987  *
5988  * Returns the new object, the old one is freed (or the operation
5989  *         is done directly on @val)
5990  */
5991 xmlXPathObjectPtr
5992 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5993     xmlXPathObjectPtr ret;
5994
5995     if (val == NULL)
5996         return(xmlXPathNewFloat(0.0));
5997     if (val->type == XPATH_NUMBER)
5998         return(val);
5999     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
6000     xmlXPathFreeObject(val);
6001     return(ret);
6002 }
6003
6004 /**
6005  * xmlXPathCastNumberToBoolean:
6006  * @val:  a number
6007  *
6008  * Converts a number to its boolean value
6009  *
6010  * Returns the boolean value
6011  */
6012 int
6013 xmlXPathCastNumberToBoolean (double val) {
6014      if (xmlXPathIsNaN(val) || (val == 0.0))
6015          return(0);
6016      return(1);
6017 }
6018
6019 /**
6020  * xmlXPathCastStringToBoolean:
6021  * @val:  a string
6022  *
6023  * Converts a string to its boolean value
6024  *
6025  * Returns the boolean value
6026  */
6027 int
6028 xmlXPathCastStringToBoolean (const xmlChar *val) {
6029     if ((val == NULL) || (xmlStrlen(val) == 0))
6030         return(0);
6031     return(1);
6032 }
6033
6034 /**
6035  * xmlXPathCastNodeSetToBoolean:
6036  * @ns:  a node-set
6037  *
6038  * Converts a node-set to its boolean value
6039  *
6040  * Returns the boolean value
6041  */
6042 int
6043 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6044     if ((ns == NULL) || (ns->nodeNr == 0))
6045         return(0);
6046     return(1);
6047 }
6048
6049 /**
6050  * xmlXPathCastToBoolean:
6051  * @val:  an XPath object
6052  *
6053  * Converts an XPath object to its boolean value
6054  *
6055  * Returns the boolean value
6056  */
6057 int
6058 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6059     int ret = 0;
6060
6061     if (val == NULL)
6062         return(0);
6063     switch (val->type) {
6064     case XPATH_UNDEFINED:
6065 #ifdef DEBUG_EXPR
6066         xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6067 #endif
6068         ret = 0;
6069         break;
6070     case XPATH_NODESET:
6071     case XPATH_XSLT_TREE:
6072         ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6073         break;
6074     case XPATH_STRING:
6075         ret = xmlXPathCastStringToBoolean(val->stringval);
6076         break;
6077     case XPATH_NUMBER:
6078         ret = xmlXPathCastNumberToBoolean(val->floatval);
6079         break;
6080     case XPATH_BOOLEAN:
6081         ret = val->boolval;
6082         break;
6083     case XPATH_USERS:
6084     case XPATH_POINT:
6085     case XPATH_RANGE:
6086     case XPATH_LOCATIONSET:
6087         TODO;
6088         ret = 0;
6089         break;
6090     }
6091     return(ret);
6092 }
6093
6094
6095 /**
6096  * xmlXPathConvertBoolean:
6097  * @val:  an XPath object
6098  *
6099  * Converts an existing object to its boolean() equivalent
6100  *
6101  * Returns the new object, the old one is freed (or the operation
6102  *         is done directly on @val)
6103  */
6104 xmlXPathObjectPtr
6105 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6106     xmlXPathObjectPtr ret;
6107
6108     if (val == NULL)
6109         return(xmlXPathNewBoolean(0));
6110     if (val->type == XPATH_BOOLEAN)
6111         return(val);
6112     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6113     xmlXPathFreeObject(val);
6114     return(ret);
6115 }
6116
6117 /************************************************************************
6118  *                                                                      *
6119  *              Routines to handle XPath contexts                       *
6120  *                                                                      *
6121  ************************************************************************/
6122
6123 /**
6124  * xmlXPathNewContext:
6125  * @doc:  the XML document
6126  *
6127  * Create a new xmlXPathContext
6128  *
6129  * Returns the xmlXPathContext just allocated. The caller will need to free it.
6130  */
6131 xmlXPathContextPtr
6132 xmlXPathNewContext(xmlDocPtr doc) {
6133     xmlXPathContextPtr ret;
6134
6135     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6136     if (ret == NULL) {
6137         xmlXPathErrMemory(NULL, "creating context\n");
6138         return(NULL);
6139     }
6140     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6141     ret->doc = doc;
6142     ret->node = NULL;
6143
6144     ret->varHash = NULL;
6145
6146     ret->nb_types = 0;
6147     ret->max_types = 0;
6148     ret->types = NULL;
6149
6150     ret->funcHash = xmlHashCreate(0);
6151
6152     ret->nb_axis = 0;
6153     ret->max_axis = 0;
6154     ret->axis = NULL;
6155
6156     ret->nsHash = NULL;
6157     ret->user = NULL;
6158
6159     ret->contextSize = -1;
6160     ret->proximityPosition = -1;
6161
6162 #ifdef XP_DEFAULT_CACHE_ON
6163     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6164         xmlXPathFreeContext(ret);
6165         return(NULL);
6166     }
6167 #endif
6168
6169     xmlXPathRegisterAllFunctions(ret);
6170
6171     return(ret);
6172 }
6173
6174 /**
6175  * xmlXPathFreeContext:
6176  * @ctxt:  the context to free
6177  *
6178  * Free up an xmlXPathContext
6179  */
6180 void
6181 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6182     if (ctxt == NULL) return;
6183
6184     if (ctxt->cache != NULL)
6185         xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6186     xmlXPathRegisteredNsCleanup(ctxt);
6187     xmlXPathRegisteredFuncsCleanup(ctxt);
6188     xmlXPathRegisteredVariablesCleanup(ctxt);
6189     xmlResetError(&ctxt->lastError);
6190     xmlFree(ctxt);
6191 }
6192
6193 /************************************************************************
6194  *                                                                      *
6195  *              Routines to handle XPath parser contexts                *
6196  *                                                                      *
6197  ************************************************************************/
6198
6199 #define CHECK_CTXT(ctxt)                                                \
6200     if (ctxt == NULL) {                                         \
6201         __xmlRaiseError(NULL, NULL, NULL,                               \
6202                 NULL, NULL, XML_FROM_XPATH,                             \
6203                 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6204                 __FILE__, __LINE__,                                     \
6205                 NULL, NULL, NULL, 0, 0,                                 \
6206                 "NULL context pointer\n");                              \
6207         return(NULL);                                                   \
6208     }                                                                   \
6209
6210 #define CHECK_CTXT_NEG(ctxt)                                            \
6211     if (ctxt == NULL) {                                         \
6212         __xmlRaiseError(NULL, NULL, NULL,                               \
6213                 NULL, NULL, XML_FROM_XPATH,                             \
6214                 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6215                 __FILE__, __LINE__,                                     \
6216                 NULL, NULL, NULL, 0, 0,                                 \
6217                 "NULL context pointer\n");                              \
6218         return(-1);                                                     \
6219     }                                                                   \
6220
6221
6222 #define CHECK_CONTEXT(ctxt)                                             \
6223     if ((ctxt == NULL) || (ctxt->doc == NULL) ||                        \
6224         (ctxt->doc->children == NULL)) {                                \
6225         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);    \
6226         return(NULL);                                                   \
6227     }
6228
6229
6230 /**
6231  * xmlXPathNewParserContext:
6232  * @str:  the XPath expression
6233  * @ctxt:  the XPath context
6234  *
6235  * Create a new xmlXPathParserContext
6236  *
6237  * Returns the xmlXPathParserContext just allocated.
6238  */
6239 xmlXPathParserContextPtr
6240 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6241     xmlXPathParserContextPtr ret;
6242
6243     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6244     if (ret == NULL) {
6245         xmlXPathErrMemory(ctxt, "creating parser context\n");
6246         return(NULL);
6247     }
6248     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6249     ret->cur = ret->base = str;
6250     ret->context = ctxt;
6251
6252     ret->comp = xmlXPathNewCompExpr();
6253     if (ret->comp == NULL) {
6254         xmlFree(ret->valueTab);
6255         xmlFree(ret);
6256         return(NULL);
6257     }
6258     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6259         ret->comp->dict = ctxt->dict;
6260         xmlDictReference(ret->comp->dict);
6261     }
6262
6263     return(ret);
6264 }
6265
6266 /**
6267  * xmlXPathCompParserContext:
6268  * @comp:  the XPath compiled expression
6269  * @ctxt:  the XPath context
6270  *
6271  * Create a new xmlXPathParserContext when processing a compiled expression
6272  *
6273  * Returns the xmlXPathParserContext just allocated.
6274  */
6275 static xmlXPathParserContextPtr
6276 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6277     xmlXPathParserContextPtr ret;
6278
6279     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6280     if (ret == NULL) {
6281         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6282         return(NULL);
6283     }
6284     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6285
6286     /* Allocate the value stack */
6287     ret->valueTab = (xmlXPathObjectPtr *)
6288                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6289     if (ret->valueTab == NULL) {
6290         xmlFree(ret);
6291         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6292         return(NULL);
6293     }
6294     ret->valueNr = 0;
6295     ret->valueMax = 10;
6296     ret->value = NULL;
6297     ret->valueFrame = 0;
6298
6299     ret->context = ctxt;
6300     ret->comp = comp;
6301
6302     return(ret);
6303 }
6304
6305 /**
6306  * xmlXPathFreeParserContext:
6307  * @ctxt:  the context to free
6308  *
6309  * Free up an xmlXPathParserContext
6310  */
6311 void
6312 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6313     int i;
6314
6315     if (ctxt->valueTab != NULL) {
6316         for (i = 0; i < ctxt->valueNr; i++) {
6317             if (ctxt->context)
6318                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6319             else
6320                 xmlXPathFreeObject(ctxt->valueTab[i]);
6321         }
6322         xmlFree(ctxt->valueTab);
6323     }
6324     if (ctxt->comp != NULL) {
6325 #ifdef XPATH_STREAMING
6326         if (ctxt->comp->stream != NULL) {
6327             xmlFreePatternList(ctxt->comp->stream);
6328             ctxt->comp->stream = NULL;
6329         }
6330 #endif
6331         xmlXPathFreeCompExpr(ctxt->comp);
6332     }
6333     xmlFree(ctxt);
6334 }
6335
6336 /************************************************************************
6337  *                                                                      *
6338  *              The implicit core function library                      *
6339  *                                                                      *
6340  ************************************************************************/
6341
6342 /**
6343  * xmlXPathNodeValHash:
6344  * @node:  a node pointer
6345  *
6346  * Function computing the beginning of the string value of the node,
6347  * used to speed up comparisons
6348  *
6349  * Returns an int usable as a hash
6350  */
6351 static unsigned int
6352 xmlXPathNodeValHash(xmlNodePtr node) {
6353     int len = 2;
6354     const xmlChar * string = NULL;
6355     xmlNodePtr tmp = NULL;
6356     unsigned int ret = 0;
6357
6358     if (node == NULL)
6359         return(0);
6360
6361     if (node->type == XML_DOCUMENT_NODE) {
6362         tmp = xmlDocGetRootElement((xmlDocPtr) node);
6363         if (tmp == NULL)
6364             node = node->children;
6365         else
6366             node = tmp;
6367
6368         if (node == NULL)
6369             return(0);
6370     }
6371
6372     switch (node->type) {
6373         case XML_COMMENT_NODE:
6374         case XML_PI_NODE:
6375         case XML_CDATA_SECTION_NODE:
6376         case XML_TEXT_NODE:
6377             string = node->content;
6378             if (string == NULL)
6379                 return(0);
6380             if (string[0] == 0)
6381                 return(0);
6382             return(((unsigned int) string[0]) +
6383                    (((unsigned int) string[1]) << 8));
6384         case XML_NAMESPACE_DECL:
6385             string = ((xmlNsPtr)node)->href;
6386             if (string == NULL)
6387                 return(0);
6388             if (string[0] == 0)
6389                 return(0);
6390             return(((unsigned int) string[0]) +
6391                    (((unsigned int) string[1]) << 8));
6392         case XML_ATTRIBUTE_NODE:
6393             tmp = ((xmlAttrPtr) node)->children;
6394             break;
6395         case XML_ELEMENT_NODE:
6396             tmp = node->children;
6397             break;
6398         default:
6399             return(0);
6400     }
6401     while (tmp != NULL) {
6402         switch (tmp->type) {
6403             case XML_COMMENT_NODE:
6404             case XML_PI_NODE:
6405             case XML_CDATA_SECTION_NODE:
6406             case XML_TEXT_NODE:
6407                 string = tmp->content;
6408                 break;
6409             case XML_NAMESPACE_DECL:
6410                 string = ((xmlNsPtr)tmp)->href;
6411                 break;
6412             default:
6413                 break;
6414         }
6415         if ((string != NULL) && (string[0] != 0)) {
6416             if (len == 1) {
6417                 return(ret + (((unsigned int) string[0]) << 8));
6418             }
6419             if (string[1] == 0) {
6420                 len = 1;
6421                 ret = (unsigned int) string[0];
6422             } else {
6423                 return(((unsigned int) string[0]) +
6424                        (((unsigned int) string[1]) << 8));
6425             }
6426         }
6427         /*
6428          * Skip to next node
6429          */
6430         if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6431             if (tmp->children->type != XML_ENTITY_DECL) {
6432                 tmp = tmp->children;
6433                 continue;
6434             }
6435         }
6436         if (tmp == node)
6437             break;
6438
6439         if (tmp->next != NULL) {
6440             tmp = tmp->next;
6441             continue;
6442         }
6443
6444         do {
6445             tmp = tmp->parent;
6446             if (tmp == NULL)
6447                 break;
6448             if (tmp == node) {
6449                 tmp = NULL;
6450                 break;
6451             }
6452             if (tmp->next != NULL) {
6453                 tmp = tmp->next;
6454                 break;
6455             }
6456         } while (tmp != NULL);
6457     }
6458     return(ret);
6459 }
6460
6461 /**
6462  * xmlXPathStringHash:
6463  * @string:  a string
6464  *
6465  * Function computing the beginning of the string value of the node,
6466  * used to speed up comparisons
6467  *
6468  * Returns an int usable as a hash
6469  */
6470 static unsigned int
6471 xmlXPathStringHash(const xmlChar * string) {
6472     if (string == NULL)
6473         return((unsigned int) 0);
6474     if (string[0] == 0)
6475         return(0);
6476     return(((unsigned int) string[0]) +
6477            (((unsigned int) string[1]) << 8));
6478 }
6479
6480 /**
6481  * xmlXPathCompareNodeSetFloat:
6482  * @ctxt:  the XPath Parser context
6483  * @inf:  less than (1) or greater than (0)
6484  * @strict:  is the comparison strict
6485  * @arg:  the node set
6486  * @f:  the value
6487  *
6488  * Implement the compare operation between a nodeset and a number
6489  *     @ns < @val    (1, 1, ...
6490  *     @ns <= @val   (1, 0, ...
6491  *     @ns > @val    (0, 1, ...
6492  *     @ns >= @val   (0, 0, ...
6493  *
6494  * If one object to be compared is a node-set and the other is a number,
6495  * then the comparison will be true if and only if there is a node in the
6496  * node-set such that the result of performing the comparison on the number
6497  * to be compared and on the result of converting the string-value of that
6498  * node to a number using the number function is true.
6499  *
6500  * Returns 0 or 1 depending on the results of the test.
6501  */
6502 static int
6503 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6504                             xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6505     int i, ret = 0;
6506     xmlNodeSetPtr ns;
6507     xmlChar *str2;
6508
6509     if ((f == NULL) || (arg == NULL) ||
6510         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6511         xmlXPathReleaseObject(ctxt->context, arg);
6512         xmlXPathReleaseObject(ctxt->context, f);
6513         return(0);
6514     }
6515     ns = arg->nodesetval;
6516     if (ns != NULL) {
6517         for (i = 0;i < ns->nodeNr;i++) {
6518              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6519              if (str2 != NULL) {
6520                  valuePush(ctxt,
6521                            xmlXPathCacheNewString(ctxt->context, str2));
6522                  xmlFree(str2);
6523                  xmlXPathNumberFunction(ctxt, 1);
6524                  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6525                  ret = xmlXPathCompareValues(ctxt, inf, strict);
6526                  if (ret)
6527                      break;
6528              }
6529         }
6530     }
6531     xmlXPathReleaseObject(ctxt->context, arg);
6532     xmlXPathReleaseObject(ctxt->context, f);
6533     return(ret);
6534 }
6535
6536 /**
6537  * xmlXPathCompareNodeSetString:
6538  * @ctxt:  the XPath Parser context
6539  * @inf:  less than (1) or greater than (0)
6540  * @strict:  is the comparison strict
6541  * @arg:  the node set
6542  * @s:  the value
6543  *
6544  * Implement the compare operation between a nodeset and a string
6545  *     @ns < @val    (1, 1, ...
6546  *     @ns <= @val   (1, 0, ...
6547  *     @ns > @val    (0, 1, ...
6548  *     @ns >= @val   (0, 0, ...
6549  *
6550  * If one object to be compared is a node-set and the other is a string,
6551  * then the comparison will be true if and only if there is a node in
6552  * the node-set such that the result of performing the comparison on the
6553  * string-value of the node and the other string is true.
6554  *
6555  * Returns 0 or 1 depending on the results of the test.
6556  */
6557 static int
6558 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6559                             xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6560     int i, ret = 0;
6561     xmlNodeSetPtr ns;
6562     xmlChar *str2;
6563
6564     if ((s == NULL) || (arg == NULL) ||
6565         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6566         xmlXPathReleaseObject(ctxt->context, arg);
6567         xmlXPathReleaseObject(ctxt->context, s);
6568         return(0);
6569     }
6570     ns = arg->nodesetval;
6571     if (ns != NULL) {
6572         for (i = 0;i < ns->nodeNr;i++) {
6573              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6574              if (str2 != NULL) {
6575                  valuePush(ctxt,
6576                            xmlXPathCacheNewString(ctxt->context, str2));
6577                  xmlFree(str2);
6578                  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6579                  ret = xmlXPathCompareValues(ctxt, inf, strict);
6580                  if (ret)
6581                      break;
6582              }
6583         }
6584     }
6585     xmlXPathReleaseObject(ctxt->context, arg);
6586     xmlXPathReleaseObject(ctxt->context, s);
6587     return(ret);
6588 }
6589
6590 /**
6591  * xmlXPathCompareNodeSets:
6592  * @inf:  less than (1) or greater than (0)
6593  * @strict:  is the comparison strict
6594  * @arg1:  the first node set object
6595  * @arg2:  the second node set object
6596  *
6597  * Implement the compare operation on nodesets:
6598  *
6599  * If both objects to be compared are node-sets, then the comparison
6600  * will be true if and only if there is a node in the first node-set
6601  * and a node in the second node-set such that the result of performing
6602  * the comparison on the string-values of the two nodes is true.
6603  * ....
6604  * When neither object to be compared is a node-set and the operator
6605  * is <=, <, >= or >, then the objects are compared by converting both
6606  * objects to numbers and comparing the numbers according to IEEE 754.
6607  * ....
6608  * The number function converts its argument to a number as follows:
6609  *  - a string that consists of optional whitespace followed by an
6610  *    optional minus sign followed by a Number followed by whitespace
6611  *    is converted to the IEEE 754 number that is nearest (according
6612  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6613  *    represented by the string; any other string is converted to NaN
6614  *
6615  * Conclusion all nodes need to be converted first to their string value
6616  * and then the comparison must be done when possible
6617  */
6618 static int
6619 xmlXPathCompareNodeSets(int inf, int strict,
6620                         xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6621     int i, j, init = 0;
6622     double val1;
6623     double *values2;
6624     int ret = 0;
6625     xmlNodeSetPtr ns1;
6626     xmlNodeSetPtr ns2;
6627
6628     if ((arg1 == NULL) ||
6629         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6630         xmlXPathFreeObject(arg2);
6631         return(0);
6632     }
6633     if ((arg2 == NULL) ||
6634         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6635         xmlXPathFreeObject(arg1);
6636         xmlXPathFreeObject(arg2);
6637         return(0);
6638     }
6639
6640     ns1 = arg1->nodesetval;
6641     ns2 = arg2->nodesetval;
6642
6643     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6644         xmlXPathFreeObject(arg1);
6645         xmlXPathFreeObject(arg2);
6646         return(0);
6647     }
6648     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6649         xmlXPathFreeObject(arg1);
6650         xmlXPathFreeObject(arg2);
6651         return(0);
6652     }
6653
6654     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6655     if (values2 == NULL) {
6656         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6657         xmlXPathFreeObject(arg1);
6658         xmlXPathFreeObject(arg2);
6659         return(0);
6660     }
6661     for (i = 0;i < ns1->nodeNr;i++) {
6662         val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6663         if (xmlXPathIsNaN(val1))
6664             continue;
6665         for (j = 0;j < ns2->nodeNr;j++) {
6666             if (init == 0) {
6667                 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6668             }
6669             if (xmlXPathIsNaN(values2[j]))
6670                 continue;
6671             if (inf && strict)
6672                 ret = (val1 < values2[j]);
6673             else if (inf && !strict)
6674                 ret = (val1 <= values2[j]);
6675             else if (!inf && strict)
6676                 ret = (val1 > values2[j]);
6677             else if (!inf && !strict)
6678                 ret = (val1 >= values2[j]);
6679             if (ret)
6680                 break;
6681         }
6682         if (ret)
6683             break;
6684         init = 1;
6685     }
6686     xmlFree(values2);
6687     xmlXPathFreeObject(arg1);
6688     xmlXPathFreeObject(arg2);
6689     return(ret);
6690 }
6691
6692 /**
6693  * xmlXPathCompareNodeSetValue:
6694  * @ctxt:  the XPath Parser context
6695  * @inf:  less than (1) or greater than (0)
6696  * @strict:  is the comparison strict
6697  * @arg:  the node set
6698  * @val:  the value
6699  *
6700  * Implement the compare operation between a nodeset and a value
6701  *     @ns < @val    (1, 1, ...
6702  *     @ns <= @val   (1, 0, ...
6703  *     @ns > @val    (0, 1, ...
6704  *     @ns >= @val   (0, 0, ...
6705  *
6706  * If one object to be compared is a node-set and the other is a boolean,
6707  * then the comparison will be true if and only if the result of performing
6708  * the comparison on the boolean and on the result of converting
6709  * the node-set to a boolean using the boolean function is true.
6710  *
6711  * Returns 0 or 1 depending on the results of the test.
6712  */
6713 static int
6714 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6715                             xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6716     if ((val == NULL) || (arg == NULL) ||
6717         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6718         return(0);
6719
6720     switch(val->type) {
6721         case XPATH_NUMBER:
6722             return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6723         case XPATH_NODESET:
6724         case XPATH_XSLT_TREE:
6725             return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6726         case XPATH_STRING:
6727             return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6728         case XPATH_BOOLEAN:
6729             valuePush(ctxt, arg);
6730             xmlXPathBooleanFunction(ctxt, 1);
6731             valuePush(ctxt, val);
6732             return(xmlXPathCompareValues(ctxt, inf, strict));
6733         default:
6734             xmlGenericError(xmlGenericErrorContext,
6735                     "xmlXPathCompareNodeSetValue: Can't compare node set "
6736                     "and object of type %d\n",
6737                     val->type);
6738             xmlXPathReleaseObject(ctxt->context, arg);
6739             xmlXPathReleaseObject(ctxt->context, val);
6740             XP_ERROR0(XPATH_INVALID_TYPE);
6741     }
6742     return(0);
6743 }
6744
6745 /**
6746  * xmlXPathEqualNodeSetString:
6747  * @arg:  the nodeset object argument
6748  * @str:  the string to compare to.
6749  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6750  *
6751  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6752  * If one object to be compared is a node-set and the other is a string,
6753  * then the comparison will be true if and only if there is a node in
6754  * the node-set such that the result of performing the comparison on the
6755  * string-value of the node and the other string is true.
6756  *
6757  * Returns 0 or 1 depending on the results of the test.
6758  */
6759 static int
6760 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6761 {
6762     int i;
6763     xmlNodeSetPtr ns;
6764     xmlChar *str2;
6765     unsigned int hash;
6766
6767     if ((str == NULL) || (arg == NULL) ||
6768         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6769         return (0);
6770     ns = arg->nodesetval;
6771     /*
6772      * A NULL nodeset compared with a string is always false
6773      * (since there is no node equal, and no node not equal)
6774      */
6775     if ((ns == NULL) || (ns->nodeNr <= 0) )
6776         return (0);
6777     hash = xmlXPathStringHash(str);
6778     for (i = 0; i < ns->nodeNr; i++) {
6779         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6780             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6781             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6782                 xmlFree(str2);
6783                 if (neq)
6784                     continue;
6785                 return (1);
6786             } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6787                 if (neq)
6788                     continue;
6789                 return (1);
6790             } else if (neq) {
6791                 if (str2 != NULL)
6792                     xmlFree(str2);
6793                 return (1);
6794             }
6795             if (str2 != NULL)
6796                 xmlFree(str2);
6797         } else if (neq)
6798             return (1);
6799     }
6800     return (0);
6801 }
6802
6803 /**
6804  * xmlXPathEqualNodeSetFloat:
6805  * @arg:  the nodeset object argument
6806  * @f:  the float to compare to
6807  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6808  *
6809  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6810  * If one object to be compared is a node-set and the other is a number,
6811  * then the comparison will be true if and only if there is a node in
6812  * the node-set such that the result of performing the comparison on the
6813  * number to be compared and on the result of converting the string-value
6814  * of that node to a number using the number function is true.
6815  *
6816  * Returns 0 or 1 depending on the results of the test.
6817  */
6818 static int
6819 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6820     xmlXPathObjectPtr arg, double f, int neq) {
6821   int i, ret=0;
6822   xmlNodeSetPtr ns;
6823   xmlChar *str2;
6824   xmlXPathObjectPtr val;
6825   double v;
6826
6827     if ((arg == NULL) ||
6828         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6829         return(0);
6830
6831     ns = arg->nodesetval;
6832     if (ns != NULL) {
6833         for (i=0;i<ns->nodeNr;i++) {
6834             str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6835             if (str2 != NULL) {
6836                 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6837                 xmlFree(str2);
6838                 xmlXPathNumberFunction(ctxt, 1);
6839                 val = valuePop(ctxt);
6840                 v = val->floatval;
6841                 xmlXPathReleaseObject(ctxt->context, val);
6842                 if (!xmlXPathIsNaN(v)) {
6843                     if ((!neq) && (v==f)) {
6844                         ret = 1;
6845                         break;
6846                     } else if ((neq) && (v!=f)) {
6847                         ret = 1;
6848                         break;
6849                     }
6850                 } else {        /* NaN is unequal to any value */
6851                     if (neq)
6852                         ret = 1;
6853                 }
6854             }
6855         }
6856     }
6857
6858     return(ret);
6859 }
6860
6861
6862 /**
6863  * xmlXPathEqualNodeSets:
6864  * @arg1:  first nodeset object argument
6865  * @arg2:  second nodeset object argument
6866  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6867  *
6868  * Implement the equal / not equal operation on XPath nodesets:
6869  * @arg1 == @arg2  or  @arg1 != @arg2
6870  * If both objects to be compared are node-sets, then the comparison
6871  * will be true if and only if there is a node in the first node-set and
6872  * a node in the second node-set such that the result of performing the
6873  * comparison on the string-values of the two nodes is true.
6874  *
6875  * (needless to say, this is a costly operation)
6876  *
6877  * Returns 0 or 1 depending on the results of the test.
6878  */
6879 static int
6880 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6881     int i, j;
6882     unsigned int *hashs1;
6883     unsigned int *hashs2;
6884     xmlChar **values1;
6885     xmlChar **values2;
6886     int ret = 0;
6887     xmlNodeSetPtr ns1;
6888     xmlNodeSetPtr ns2;
6889
6890     if ((arg1 == NULL) ||
6891         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6892         return(0);
6893     if ((arg2 == NULL) ||
6894         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6895         return(0);
6896
6897     ns1 = arg1->nodesetval;
6898     ns2 = arg2->nodesetval;
6899
6900     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6901         return(0);
6902     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6903         return(0);
6904
6905     /*
6906      * for equal, check if there is a node pertaining to both sets
6907      */
6908     if (neq == 0)
6909         for (i = 0;i < ns1->nodeNr;i++)
6910             for (j = 0;j < ns2->nodeNr;j++)
6911                 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6912                     return(1);
6913
6914     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6915     if (values1 == NULL) {
6916         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6917         return(0);
6918     }
6919     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6920     if (hashs1 == NULL) {
6921         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6922         xmlFree(values1);
6923         return(0);
6924     }
6925     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6926     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6927     if (values2 == NULL) {
6928         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6929         xmlFree(hashs1);
6930         xmlFree(values1);
6931         return(0);
6932     }
6933     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6934     if (hashs2 == NULL) {
6935         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6936         xmlFree(hashs1);
6937         xmlFree(values1);
6938         xmlFree(values2);
6939         return(0);
6940     }
6941     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6942     for (i = 0;i < ns1->nodeNr;i++) {
6943         hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6944         for (j = 0;j < ns2->nodeNr;j++) {
6945             if (i == 0)
6946                 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6947             if (hashs1[i] != hashs2[j]) {
6948                 if (neq) {
6949                     ret = 1;
6950                     break;
6951                 }
6952             }
6953             else {
6954                 if (values1[i] == NULL)
6955                     values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6956                 if (values2[j] == NULL)
6957                     values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6958                 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6959                 if (ret)
6960                     break;
6961             }
6962         }
6963         if (ret)
6964             break;
6965     }
6966     for (i = 0;i < ns1->nodeNr;i++)
6967         if (values1[i] != NULL)
6968             xmlFree(values1[i]);
6969     for (j = 0;j < ns2->nodeNr;j++)
6970         if (values2[j] != NULL)
6971             xmlFree(values2[j]);
6972     xmlFree(values1);
6973     xmlFree(values2);
6974     xmlFree(hashs1);
6975     xmlFree(hashs2);
6976     return(ret);
6977 }
6978
6979 static int
6980 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6981   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6982     int ret = 0;
6983     /*
6984      *At this point we are assured neither arg1 nor arg2
6985      *is a nodeset, so we can just pick the appropriate routine.
6986      */
6987     switch (arg1->type) {
6988         case XPATH_UNDEFINED:
6989 #ifdef DEBUG_EXPR
6990             xmlGenericError(xmlGenericErrorContext,
6991                     "Equal: undefined\n");
6992 #endif
6993             break;
6994         case XPATH_BOOLEAN:
6995             switch (arg2->type) {
6996                 case XPATH_UNDEFINED:
6997 #ifdef DEBUG_EXPR
6998                     xmlGenericError(xmlGenericErrorContext,
6999                             "Equal: undefined\n");
7000 #endif
7001                     break;
7002                 case XPATH_BOOLEAN:
7003 #ifdef DEBUG_EXPR
7004                     xmlGenericError(xmlGenericErrorContext,
7005                             "Equal: %d boolean %d \n",
7006                             arg1->boolval, arg2->boolval);
7007 #endif
7008                     ret = (arg1->boolval == arg2->boolval);
7009                     break;
7010                 case XPATH_NUMBER:
7011                     ret = (arg1->boolval ==
7012                            xmlXPathCastNumberToBoolean(arg2->floatval));
7013                     break;
7014                 case XPATH_STRING:
7015                     if ((arg2->stringval == NULL) ||
7016                         (arg2->stringval[0] == 0)) ret = 0;
7017                     else
7018                         ret = 1;
7019                     ret = (arg1->boolval == ret);
7020                     break;
7021                 case XPATH_USERS:
7022                 case XPATH_POINT:
7023                 case XPATH_RANGE:
7024                 case XPATH_LOCATIONSET:
7025                     TODO
7026                     break;
7027                 case XPATH_NODESET:
7028                 case XPATH_XSLT_TREE:
7029                     break;
7030             }
7031             break;
7032         case XPATH_NUMBER:
7033             switch (arg2->type) {
7034                 case XPATH_UNDEFINED:
7035 #ifdef DEBUG_EXPR
7036                     xmlGenericError(xmlGenericErrorContext,
7037                             "Equal: undefined\n");
7038 #endif
7039                     break;
7040                 case XPATH_BOOLEAN:
7041                     ret = (arg2->boolval==
7042                            xmlXPathCastNumberToBoolean(arg1->floatval));
7043                     break;
7044                 case XPATH_STRING:
7045                     valuePush(ctxt, arg2);
7046                     xmlXPathNumberFunction(ctxt, 1);
7047                     arg2 = valuePop(ctxt);
7048                     /* no break on purpose */
7049                 case XPATH_NUMBER:
7050                     /* Hand check NaN and Infinity equalities */
7051                     if (xmlXPathIsNaN(arg1->floatval) ||
7052                             xmlXPathIsNaN(arg2->floatval)) {
7053                         ret = 0;
7054                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7055                         if (xmlXPathIsInf(arg2->floatval) == 1)
7056                             ret = 1;
7057                         else
7058                             ret = 0;
7059                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7060                         if (xmlXPathIsInf(arg2->floatval) == -1)
7061                             ret = 1;
7062                         else
7063                             ret = 0;
7064                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7065                         if (xmlXPathIsInf(arg1->floatval) == 1)
7066                             ret = 1;
7067                         else
7068                             ret = 0;
7069                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7070                         if (xmlXPathIsInf(arg1->floatval) == -1)
7071                             ret = 1;
7072                         else
7073                             ret = 0;
7074                     } else {
7075                         ret = (arg1->floatval == arg2->floatval);
7076                     }
7077                     break;
7078                 case XPATH_USERS:
7079                 case XPATH_POINT:
7080                 case XPATH_RANGE:
7081                 case XPATH_LOCATIONSET:
7082                     TODO
7083                     break;
7084                 case XPATH_NODESET:
7085                 case XPATH_XSLT_TREE:
7086                     break;
7087             }
7088             break;
7089         case XPATH_STRING:
7090             switch (arg2->type) {
7091                 case XPATH_UNDEFINED:
7092 #ifdef DEBUG_EXPR
7093                     xmlGenericError(xmlGenericErrorContext,
7094                             "Equal: undefined\n");
7095 #endif
7096                     break;
7097                 case XPATH_BOOLEAN:
7098                     if ((arg1->stringval == NULL) ||
7099                         (arg1->stringval[0] == 0)) ret = 0;
7100                     else
7101                         ret = 1;
7102                     ret = (arg2->boolval == ret);
7103                     break;
7104                 case XPATH_STRING:
7105                     ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7106                     break;
7107                 case XPATH_NUMBER:
7108                     valuePush(ctxt, arg1);
7109                     xmlXPathNumberFunction(ctxt, 1);
7110                     arg1 = valuePop(ctxt);
7111                     /* Hand check NaN and Infinity equalities */
7112                     if (xmlXPathIsNaN(arg1->floatval) ||
7113                             xmlXPathIsNaN(arg2->floatval)) {
7114                         ret = 0;
7115                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7116                         if (xmlXPathIsInf(arg2->floatval) == 1)
7117                             ret = 1;
7118                         else
7119                             ret = 0;
7120                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7121                         if (xmlXPathIsInf(arg2->floatval) == -1)
7122                             ret = 1;
7123                         else
7124                             ret = 0;
7125                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7126                         if (xmlXPathIsInf(arg1->floatval) == 1)
7127                             ret = 1;
7128                         else
7129                             ret = 0;
7130                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7131                         if (xmlXPathIsInf(arg1->floatval) == -1)
7132                             ret = 1;
7133                         else
7134                             ret = 0;
7135                     } else {
7136                         ret = (arg1->floatval == arg2->floatval);
7137                     }
7138                     break;
7139                 case XPATH_USERS:
7140                 case XPATH_POINT:
7141                 case XPATH_RANGE:
7142                 case XPATH_LOCATIONSET:
7143                     TODO
7144                     break;
7145                 case XPATH_NODESET:
7146                 case XPATH_XSLT_TREE:
7147                     break;
7148             }
7149             break;
7150         case XPATH_USERS:
7151         case XPATH_POINT:
7152         case XPATH_RANGE:
7153         case XPATH_LOCATIONSET:
7154             TODO
7155             break;
7156         case XPATH_NODESET:
7157         case XPATH_XSLT_TREE:
7158             break;
7159     }
7160     xmlXPathReleaseObject(ctxt->context, arg1);
7161     xmlXPathReleaseObject(ctxt->context, arg2);
7162     return(ret);
7163 }
7164
7165 /**
7166  * xmlXPathEqualValues:
7167  * @ctxt:  the XPath Parser context
7168  *
7169  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7170  *
7171  * Returns 0 or 1 depending on the results of the test.
7172  */
7173 int
7174 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7175     xmlXPathObjectPtr arg1, arg2, argtmp;
7176     int ret = 0;
7177
7178     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7179     arg2 = valuePop(ctxt);
7180     arg1 = valuePop(ctxt);
7181     if ((arg1 == NULL) || (arg2 == NULL)) {
7182         if (arg1 != NULL)
7183             xmlXPathReleaseObject(ctxt->context, arg1);
7184         else
7185             xmlXPathReleaseObject(ctxt->context, arg2);
7186         XP_ERROR0(XPATH_INVALID_OPERAND);
7187     }
7188
7189     if (arg1 == arg2) {
7190 #ifdef DEBUG_EXPR
7191         xmlGenericError(xmlGenericErrorContext,
7192                 "Equal: by pointer\n");
7193 #endif
7194         xmlXPathFreeObject(arg1);
7195         return(1);
7196     }
7197
7198     /*
7199      *If either argument is a nodeset, it's a 'special case'
7200      */
7201     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7202       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7203         /*
7204          *Hack it to assure arg1 is the nodeset
7205          */
7206         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7207                 argtmp = arg2;
7208                 arg2 = arg1;
7209                 arg1 = argtmp;
7210         }
7211         switch (arg2->type) {
7212             case XPATH_UNDEFINED:
7213 #ifdef DEBUG_EXPR
7214                 xmlGenericError(xmlGenericErrorContext,
7215                         "Equal: undefined\n");
7216 #endif
7217                 break;
7218             case XPATH_NODESET:
7219             case XPATH_XSLT_TREE:
7220                 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7221                 break;
7222             case XPATH_BOOLEAN:
7223                 if ((arg1->nodesetval == NULL) ||
7224                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
7225                 else
7226                     ret = 1;
7227                 ret = (ret == arg2->boolval);
7228                 break;
7229             case XPATH_NUMBER:
7230                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7231                 break;
7232             case XPATH_STRING:
7233                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7234                 break;
7235             case XPATH_USERS:
7236             case XPATH_POINT:
7237             case XPATH_RANGE:
7238             case XPATH_LOCATIONSET:
7239                 TODO
7240                 break;
7241         }
7242         xmlXPathReleaseObject(ctxt->context, arg1);
7243         xmlXPathReleaseObject(ctxt->context, arg2);
7244         return(ret);
7245     }
7246
7247     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7248 }
7249
7250 /**
7251  * xmlXPathNotEqualValues:
7252  * @ctxt:  the XPath Parser context
7253  *
7254  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7255  *
7256  * Returns 0 or 1 depending on the results of the test.
7257  */
7258 int
7259 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7260     xmlXPathObjectPtr arg1, arg2, argtmp;
7261     int ret = 0;
7262
7263     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7264     arg2 = valuePop(ctxt);
7265     arg1 = valuePop(ctxt);
7266     if ((arg1 == NULL) || (arg2 == NULL)) {
7267         if (arg1 != NULL)
7268             xmlXPathReleaseObject(ctxt->context, arg1);
7269         else
7270             xmlXPathReleaseObject(ctxt->context, arg2);
7271         XP_ERROR0(XPATH_INVALID_OPERAND);
7272     }
7273
7274     if (arg1 == arg2) {
7275 #ifdef DEBUG_EXPR
7276         xmlGenericError(xmlGenericErrorContext,
7277                 "NotEqual: by pointer\n");
7278 #endif
7279         xmlXPathReleaseObject(ctxt->context, arg1);
7280         return(0);
7281     }
7282
7283     /*
7284      *If either argument is a nodeset, it's a 'special case'
7285      */
7286     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7287       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7288         /*
7289          *Hack it to assure arg1 is the nodeset
7290          */
7291         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7292                 argtmp = arg2;
7293                 arg2 = arg1;
7294                 arg1 = argtmp;
7295         }
7296         switch (arg2->type) {
7297             case XPATH_UNDEFINED:
7298 #ifdef DEBUG_EXPR
7299                 xmlGenericError(xmlGenericErrorContext,
7300                         "NotEqual: undefined\n");
7301 #endif
7302                 break;
7303             case XPATH_NODESET:
7304             case XPATH_XSLT_TREE:
7305                 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7306                 break;
7307             case XPATH_BOOLEAN:
7308                 if ((arg1->nodesetval == NULL) ||
7309                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
7310                 else
7311                     ret = 1;
7312                 ret = (ret != arg2->boolval);
7313                 break;
7314             case XPATH_NUMBER:
7315                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7316                 break;
7317             case XPATH_STRING:
7318                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7319                 break;
7320             case XPATH_USERS:
7321             case XPATH_POINT:
7322             case XPATH_RANGE:
7323             case XPATH_LOCATIONSET:
7324                 TODO
7325                 break;
7326         }
7327         xmlXPathReleaseObject(ctxt->context, arg1);
7328         xmlXPathReleaseObject(ctxt->context, arg2);
7329         return(ret);
7330     }
7331
7332     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7333 }
7334
7335 /**
7336  * xmlXPathCompareValues:
7337  * @ctxt:  the XPath Parser context
7338  * @inf:  less than (1) or greater than (0)
7339  * @strict:  is the comparison strict
7340  *
7341  * Implement the compare operation on XPath objects:
7342  *     @arg1 < @arg2    (1, 1, ...
7343  *     @arg1 <= @arg2   (1, 0, ...
7344  *     @arg1 > @arg2    (0, 1, ...
7345  *     @arg1 >= @arg2   (0, 0, ...
7346  *
7347  * When neither object to be compared is a node-set and the operator is
7348  * <=, <, >=, >, then the objects are compared by converted both objects
7349  * to numbers and comparing the numbers according to IEEE 754. The <
7350  * comparison will be true if and only if the first number is less than the
7351  * second number. The <= comparison will be true if and only if the first
7352  * number is less than or equal to the second number. The > comparison
7353  * will be true if and only if the first number is greater than the second
7354  * number. The >= comparison will be true if and only if the first number
7355  * is greater than or equal to the second number.
7356  *
7357  * Returns 1 if the comparison succeeded, 0 if it failed
7358  */
7359 int
7360 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7361     int ret = 0, arg1i = 0, arg2i = 0;
7362     xmlXPathObjectPtr arg1, arg2;
7363
7364     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7365     arg2 = valuePop(ctxt);
7366     arg1 = valuePop(ctxt);
7367     if ((arg1 == NULL) || (arg2 == NULL)) {
7368         if (arg1 != NULL)
7369             xmlXPathReleaseObject(ctxt->context, arg1);
7370         else
7371             xmlXPathReleaseObject(ctxt->context, arg2);
7372         XP_ERROR0(XPATH_INVALID_OPERAND);
7373     }
7374
7375     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7376       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7377         /*
7378          * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7379          * are not freed from within this routine; they will be freed from the
7380          * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7381          */
7382         if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7383           ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7384             ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7385         } else {
7386             if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7387                 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7388                                                   arg1, arg2);
7389             } else {
7390                 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7391                                                   arg2, arg1);
7392             }
7393         }
7394         return(ret);
7395     }
7396
7397     if (arg1->type != XPATH_NUMBER) {
7398         valuePush(ctxt, arg1);
7399         xmlXPathNumberFunction(ctxt, 1);
7400         arg1 = valuePop(ctxt);
7401     }
7402     if (arg1->type != XPATH_NUMBER) {
7403         xmlXPathFreeObject(arg1);
7404         xmlXPathFreeObject(arg2);
7405         XP_ERROR0(XPATH_INVALID_OPERAND);
7406     }
7407     if (arg2->type != XPATH_NUMBER) {
7408         valuePush(ctxt, arg2);
7409         xmlXPathNumberFunction(ctxt, 1);
7410         arg2 = valuePop(ctxt);
7411     }
7412     if (arg2->type != XPATH_NUMBER) {
7413         xmlXPathReleaseObject(ctxt->context, arg1);
7414         xmlXPathReleaseObject(ctxt->context, arg2);
7415         XP_ERROR0(XPATH_INVALID_OPERAND);
7416     }
7417     /*
7418      * Add tests for infinity and nan
7419      * => feedback on 3.4 for Inf and NaN
7420      */
7421     /* Hand check NaN and Infinity comparisons */
7422     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7423         ret=0;
7424     } else {
7425         arg1i=xmlXPathIsInf(arg1->floatval);
7426         arg2i=xmlXPathIsInf(arg2->floatval);
7427         if (inf && strict) {
7428             if ((arg1i == -1 && arg2i != -1) ||
7429                 (arg2i == 1 && arg1i != 1)) {
7430                 ret = 1;
7431             } else if (arg1i == 0 && arg2i == 0) {
7432                 ret = (arg1->floatval < arg2->floatval);
7433             } else {
7434                 ret = 0;
7435             }
7436         }
7437         else if (inf && !strict) {
7438             if (arg1i == -1 || arg2i == 1) {
7439                 ret = 1;
7440             } else if (arg1i == 0 && arg2i == 0) {
7441                 ret = (arg1->floatval <= arg2->floatval);
7442             } else {
7443                 ret = 0;
7444             }
7445         }
7446         else if (!inf && strict) {
7447             if ((arg1i == 1 && arg2i != 1) ||
7448                 (arg2i == -1 && arg1i != -1)) {
7449                 ret = 1;
7450             } else if (arg1i == 0 && arg2i == 0) {
7451                 ret = (arg1->floatval > arg2->floatval);
7452             } else {
7453                 ret = 0;
7454             }
7455         }
7456         else if (!inf && !strict) {
7457             if (arg1i == 1 || arg2i == -1) {
7458                 ret = 1;
7459             } else if (arg1i == 0 && arg2i == 0) {
7460                 ret = (arg1->floatval >= arg2->floatval);
7461             } else {
7462                 ret = 0;
7463             }
7464         }
7465     }
7466     xmlXPathReleaseObject(ctxt->context, arg1);
7467     xmlXPathReleaseObject(ctxt->context, arg2);
7468     return(ret);
7469 }
7470
7471 /**
7472  * xmlXPathValueFlipSign:
7473  * @ctxt:  the XPath Parser context
7474  *
7475  * Implement the unary - operation on an XPath object
7476  * The numeric operators convert their operands to numbers as if
7477  * by calling the number function.
7478  */
7479 void
7480 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7481     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7482     CAST_TO_NUMBER;
7483     CHECK_TYPE(XPATH_NUMBER);
7484     if (xmlXPathIsNaN(ctxt->value->floatval))
7485         ctxt->value->floatval=xmlXPathNAN;
7486     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7487         ctxt->value->floatval=xmlXPathNINF;
7488     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7489         ctxt->value->floatval=xmlXPathPINF;
7490     else if (ctxt->value->floatval == 0) {
7491         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7492             ctxt->value->floatval = xmlXPathNZERO;
7493         else
7494             ctxt->value->floatval = 0;
7495     }
7496     else
7497         ctxt->value->floatval = - ctxt->value->floatval;
7498 }
7499
7500 /**
7501  * xmlXPathAddValues:
7502  * @ctxt:  the XPath Parser context
7503  *
7504  * Implement the add operation on XPath objects:
7505  * The numeric operators convert their operands to numbers as if
7506  * by calling the number function.
7507  */
7508 void
7509 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7510     xmlXPathObjectPtr arg;
7511     double val;
7512
7513     arg = valuePop(ctxt);
7514     if (arg == NULL)
7515         XP_ERROR(XPATH_INVALID_OPERAND);
7516     val = xmlXPathCastToNumber(arg);
7517     xmlXPathReleaseObject(ctxt->context, arg);
7518     CAST_TO_NUMBER;
7519     CHECK_TYPE(XPATH_NUMBER);
7520     ctxt->value->floatval += val;
7521 }
7522
7523 /**
7524  * xmlXPathSubValues:
7525  * @ctxt:  the XPath Parser context
7526  *
7527  * Implement the subtraction operation on XPath objects:
7528  * The numeric operators convert their operands to numbers as if
7529  * by calling the number function.
7530  */
7531 void
7532 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7533     xmlXPathObjectPtr arg;
7534     double val;
7535
7536     arg = valuePop(ctxt);
7537     if (arg == NULL)
7538         XP_ERROR(XPATH_INVALID_OPERAND);
7539     val = xmlXPathCastToNumber(arg);
7540     xmlXPathReleaseObject(ctxt->context, arg);
7541     CAST_TO_NUMBER;
7542     CHECK_TYPE(XPATH_NUMBER);
7543     ctxt->value->floatval -= val;
7544 }
7545
7546 /**
7547  * xmlXPathMultValues:
7548  * @ctxt:  the XPath Parser context
7549  *
7550  * Implement the multiply operation on XPath objects:
7551  * The numeric operators convert their operands to numbers as if
7552  * by calling the number function.
7553  */
7554 void
7555 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7556     xmlXPathObjectPtr arg;
7557     double val;
7558
7559     arg = valuePop(ctxt);
7560     if (arg == NULL)
7561         XP_ERROR(XPATH_INVALID_OPERAND);
7562     val = xmlXPathCastToNumber(arg);
7563     xmlXPathReleaseObject(ctxt->context, arg);
7564     CAST_TO_NUMBER;
7565     CHECK_TYPE(XPATH_NUMBER);
7566     ctxt->value->floatval *= val;
7567 }
7568
7569 /**
7570  * xmlXPathDivValues:
7571  * @ctxt:  the XPath Parser context
7572  *
7573  * Implement the div operation on XPath objects @arg1 / @arg2:
7574  * The numeric operators convert their operands to numbers as if
7575  * by calling the number function.
7576  */
7577 void
7578 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7579     xmlXPathObjectPtr arg;
7580     double val;
7581
7582     arg = valuePop(ctxt);
7583     if (arg == NULL)
7584         XP_ERROR(XPATH_INVALID_OPERAND);
7585     val = xmlXPathCastToNumber(arg);
7586     xmlXPathReleaseObject(ctxt->context, arg);
7587     CAST_TO_NUMBER;
7588     CHECK_TYPE(XPATH_NUMBER);
7589     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7590         ctxt->value->floatval = xmlXPathNAN;
7591     else if (val == 0 && xmlXPathGetSign(val) != 0) {
7592         if (ctxt->value->floatval == 0)
7593             ctxt->value->floatval = xmlXPathNAN;
7594         else if (ctxt->value->floatval > 0)
7595             ctxt->value->floatval = xmlXPathNINF;
7596         else if (ctxt->value->floatval < 0)
7597             ctxt->value->floatval = xmlXPathPINF;
7598     }
7599     else if (val == 0) {
7600         if (ctxt->value->floatval == 0)
7601             ctxt->value->floatval = xmlXPathNAN;
7602         else if (ctxt->value->floatval > 0)
7603             ctxt->value->floatval = xmlXPathPINF;
7604         else if (ctxt->value->floatval < 0)
7605             ctxt->value->floatval = xmlXPathNINF;
7606     } else
7607         ctxt->value->floatval /= val;
7608 }
7609
7610 /**
7611  * xmlXPathModValues:
7612  * @ctxt:  the XPath Parser context
7613  *
7614  * Implement the mod operation on XPath objects: @arg1 / @arg2
7615  * The numeric operators convert their operands to numbers as if
7616  * by calling the number function.
7617  */
7618 void
7619 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7620     xmlXPathObjectPtr arg;
7621     double arg1, arg2;
7622
7623     arg = valuePop(ctxt);
7624     if (arg == NULL)
7625         XP_ERROR(XPATH_INVALID_OPERAND);
7626     arg2 = xmlXPathCastToNumber(arg);
7627     xmlXPathReleaseObject(ctxt->context, arg);
7628     CAST_TO_NUMBER;
7629     CHECK_TYPE(XPATH_NUMBER);
7630     arg1 = ctxt->value->floatval;
7631     if (arg2 == 0)
7632         ctxt->value->floatval = xmlXPathNAN;
7633     else {
7634         ctxt->value->floatval = fmod(arg1, arg2);
7635     }
7636 }
7637
7638 /************************************************************************
7639  *                                                                      *
7640  *              The traversal functions                                 *
7641  *                                                                      *
7642  ************************************************************************/
7643
7644 /*
7645  * A traversal function enumerates nodes along an axis.
7646  * Initially it must be called with NULL, and it indicates
7647  * termination on the axis by returning NULL.
7648  */
7649 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7650                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7651
7652 /*
7653  * xmlXPathTraversalFunctionExt:
7654  * A traversal function enumerates nodes along an axis.
7655  * Initially it must be called with NULL, and it indicates
7656  * termination on the axis by returning NULL.
7657  * The context node of the traversal is specified via @contextNode.
7658  */
7659 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7660                     (xmlNodePtr cur, xmlNodePtr contextNode);
7661
7662 /*
7663  * xmlXPathNodeSetMergeFunction:
7664  * Used for merging node sets in xmlXPathCollectAndTest().
7665  */
7666 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7667                     (xmlNodeSetPtr, xmlNodeSetPtr, int);
7668
7669
7670 /**
7671  * xmlXPathNextSelf:
7672  * @ctxt:  the XPath Parser context
7673  * @cur:  the current node in the traversal
7674  *
7675  * Traversal function for the "self" direction
7676  * The self axis contains just the context node itself
7677  *
7678  * Returns the next element following that axis
7679  */
7680 xmlNodePtr
7681 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7682     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7683     if (cur == NULL)
7684         return(ctxt->context->node);
7685     return(NULL);
7686 }
7687
7688 /**
7689  * xmlXPathNextChild:
7690  * @ctxt:  the XPath Parser context
7691  * @cur:  the current node in the traversal
7692  *
7693  * Traversal function for the "child" direction
7694  * The child axis contains the children of the context node in document order.
7695  *
7696  * Returns the next element following that axis
7697  */
7698 xmlNodePtr
7699 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7700     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7701     if (cur == NULL) {
7702         if (ctxt->context->node == NULL) return(NULL);
7703         switch (ctxt->context->node->type) {
7704             case XML_ELEMENT_NODE:
7705             case XML_TEXT_NODE:
7706             case XML_CDATA_SECTION_NODE:
7707             case XML_ENTITY_REF_NODE:
7708             case XML_ENTITY_NODE:
7709             case XML_PI_NODE:
7710             case XML_COMMENT_NODE:
7711             case XML_NOTATION_NODE:
7712             case XML_DTD_NODE:
7713                 return(ctxt->context->node->children);
7714             case XML_DOCUMENT_NODE:
7715             case XML_DOCUMENT_TYPE_NODE:
7716             case XML_DOCUMENT_FRAG_NODE:
7717             case XML_HTML_DOCUMENT_NODE:
7718 #ifdef LIBXML_DOCB_ENABLED
7719             case XML_DOCB_DOCUMENT_NODE:
7720 #endif
7721                 return(((xmlDocPtr) ctxt->context->node)->children);
7722             case XML_ELEMENT_DECL:
7723             case XML_ATTRIBUTE_DECL:
7724             case XML_ENTITY_DECL:
7725             case XML_ATTRIBUTE_NODE:
7726             case XML_NAMESPACE_DECL:
7727             case XML_XINCLUDE_START:
7728             case XML_XINCLUDE_END:
7729                 return(NULL);
7730         }
7731         return(NULL);
7732     }
7733     if ((cur->type == XML_DOCUMENT_NODE) ||
7734         (cur->type == XML_HTML_DOCUMENT_NODE))
7735         return(NULL);
7736     return(cur->next);
7737 }
7738
7739 /**
7740  * xmlXPathNextChildElement:
7741  * @ctxt:  the XPath Parser context
7742  * @cur:  the current node in the traversal
7743  *
7744  * Traversal function for the "child" direction and nodes of type element.
7745  * The child axis contains the children of the context node in document order.
7746  *
7747  * Returns the next element following that axis
7748  */
7749 static xmlNodePtr
7750 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7751     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7752     if (cur == NULL) {
7753         cur = ctxt->context->node;
7754         if (cur == NULL) return(NULL);
7755         /*
7756         * Get the first element child.
7757         */
7758         switch (cur->type) {
7759             case XML_ELEMENT_NODE:
7760             case XML_DOCUMENT_FRAG_NODE:
7761             case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7762             case XML_ENTITY_NODE:
7763                 cur = cur->children;
7764                 if (cur != NULL) {
7765                     if (cur->type == XML_ELEMENT_NODE)
7766                         return(cur);
7767                     do {
7768                         cur = cur->next;
7769                     } while ((cur != NULL) &&
7770                         (cur->type != XML_ELEMENT_NODE));
7771                     return(cur);
7772                 }
7773                 return(NULL);
7774             case XML_DOCUMENT_NODE:
7775             case XML_HTML_DOCUMENT_NODE:
7776 #ifdef LIBXML_DOCB_ENABLED
7777             case XML_DOCB_DOCUMENT_NODE:
7778 #endif
7779                 return(xmlDocGetRootElement((xmlDocPtr) cur));
7780             default:
7781                 return(NULL);
7782         }
7783         return(NULL);
7784     }
7785     /*
7786     * Get the next sibling element node.
7787     */
7788     switch (cur->type) {
7789         case XML_ELEMENT_NODE:
7790         case XML_TEXT_NODE:
7791         case XML_ENTITY_REF_NODE:
7792         case XML_ENTITY_NODE:
7793         case XML_CDATA_SECTION_NODE:
7794         case XML_PI_NODE:
7795         case XML_COMMENT_NODE:
7796         case XML_XINCLUDE_END:
7797             break;
7798         /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7799         default:
7800             return(NULL);
7801     }
7802     if (cur->next != NULL) {
7803         if (cur->next->type == XML_ELEMENT_NODE)
7804             return(cur->next);
7805         cur = cur->next;
7806         do {
7807             cur = cur->next;
7808         } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7809         return(cur);
7810     }
7811     return(NULL);
7812 }
7813
7814 #if 0
7815 /**
7816  * xmlXPathNextDescendantOrSelfElemParent:
7817  * @ctxt:  the XPath Parser context
7818  * @cur:  the current node in the traversal
7819  *
7820  * Traversal function for the "descendant-or-self" axis.
7821  * Additionally it returns only nodes which can be parents of
7822  * element nodes.
7823  *
7824  *
7825  * Returns the next element following that axis
7826  */
7827 static xmlNodePtr
7828 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7829                                        xmlNodePtr contextNode)
7830 {
7831     if (cur == NULL) {
7832         if (contextNode == NULL)
7833             return(NULL);
7834         switch (contextNode->type) {
7835             case XML_ELEMENT_NODE:
7836             case XML_XINCLUDE_START:
7837             case XML_DOCUMENT_FRAG_NODE:
7838             case XML_DOCUMENT_NODE:
7839 #ifdef LIBXML_DOCB_ENABLED
7840             case XML_DOCB_DOCUMENT_NODE:
7841 #endif
7842             case XML_HTML_DOCUMENT_NODE:
7843                 return(contextNode);
7844             default:
7845                 return(NULL);
7846         }
7847         return(NULL);
7848     } else {
7849         xmlNodePtr start = cur;
7850
7851         while (cur != NULL) {
7852             switch (cur->type) {
7853                 case XML_ELEMENT_NODE:
7854                 /* TODO: OK to have XInclude here? */
7855                 case XML_XINCLUDE_START:
7856                 case XML_DOCUMENT_FRAG_NODE:
7857                     if (cur != start)
7858                         return(cur);
7859                     if (cur->children != NULL) {
7860                         cur = cur->children;
7861                         continue;
7862                     }
7863                     break;
7864                 /* Not sure if we need those here. */
7865                 case XML_DOCUMENT_NODE:
7866 #ifdef LIBXML_DOCB_ENABLED
7867                 case XML_DOCB_DOCUMENT_NODE:
7868 #endif
7869                 case XML_HTML_DOCUMENT_NODE:
7870                     if (cur != start)
7871                         return(cur);
7872                     return(xmlDocGetRootElement((xmlDocPtr) cur));
7873                 default:
7874                     break;
7875             }
7876
7877 next_sibling:
7878             if ((cur == NULL) || (cur == contextNode))
7879                 return(NULL);
7880             if (cur->next != NULL) {
7881                 cur = cur->next;
7882             } else {
7883                 cur = cur->parent;
7884                 goto next_sibling;
7885             }
7886         }
7887     }
7888     return(NULL);
7889 }
7890 #endif
7891
7892 /**
7893  * xmlXPathNextDescendant:
7894  * @ctxt:  the XPath Parser context
7895  * @cur:  the current node in the traversal
7896  *
7897  * Traversal function for the "descendant" direction
7898  * the descendant axis contains the descendants of the context node in document
7899  * order; a descendant is a child or a child of a child and so on.
7900  *
7901  * Returns the next element following that axis
7902  */
7903 xmlNodePtr
7904 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7905     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7906     if (cur == NULL) {
7907         if (ctxt->context->node == NULL)
7908             return(NULL);
7909         if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7910             (ctxt->context->node->type == XML_NAMESPACE_DECL))
7911             return(NULL);
7912
7913         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7914             return(ctxt->context->doc->children);
7915         return(ctxt->context->node->children);
7916     }
7917
7918     if (cur->type == XML_NAMESPACE_DECL)
7919         return(NULL);
7920     if (cur->children != NULL) {
7921         /*
7922          * Do not descend on entities declarations
7923          */
7924         if (cur->children->type != XML_ENTITY_DECL) {
7925             cur = cur->children;
7926             /*
7927              * Skip DTDs
7928              */
7929             if (cur->type != XML_DTD_NODE)
7930                 return(cur);
7931         }
7932     }
7933
7934     if (cur == ctxt->context->node) return(NULL);
7935
7936     while (cur->next != NULL) {
7937         cur = cur->next;
7938         if ((cur->type != XML_ENTITY_DECL) &&
7939             (cur->type != XML_DTD_NODE))
7940             return(cur);
7941     }
7942
7943     do {
7944         cur = cur->parent;
7945         if (cur == NULL) break;
7946         if (cur == ctxt->context->node) return(NULL);
7947         if (cur->next != NULL) {
7948             cur = cur->next;
7949             return(cur);
7950         }
7951     } while (cur != NULL);
7952     return(cur);
7953 }
7954
7955 /**
7956  * xmlXPathNextDescendantOrSelf:
7957  * @ctxt:  the XPath Parser context
7958  * @cur:  the current node in the traversal
7959  *
7960  * Traversal function for the "descendant-or-self" direction
7961  * the descendant-or-self axis contains the context node and the descendants
7962  * of the context node in document order; thus the context node is the first
7963  * node on the axis, and the first child of the context node is the second node
7964  * on the axis
7965  *
7966  * Returns the next element following that axis
7967  */
7968 xmlNodePtr
7969 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7970     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7971     if (cur == NULL)
7972         return(ctxt->context->node);
7973
7974     if (ctxt->context->node == NULL)
7975         return(NULL);
7976     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7977         (ctxt->context->node->type == XML_NAMESPACE_DECL))
7978         return(NULL);
7979
7980     return(xmlXPathNextDescendant(ctxt, cur));
7981 }
7982
7983 /**
7984  * xmlXPathNextParent:
7985  * @ctxt:  the XPath Parser context
7986  * @cur:  the current node in the traversal
7987  *
7988  * Traversal function for the "parent" direction
7989  * The parent axis contains the parent of the context node, if there is one.
7990  *
7991  * Returns the next element following that axis
7992  */
7993 xmlNodePtr
7994 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7995     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7996     /*
7997      * the parent of an attribute or namespace node is the element
7998      * to which the attribute or namespace node is attached
7999      * Namespace handling !!!
8000      */
8001     if (cur == NULL) {
8002         if (ctxt->context->node == NULL) return(NULL);
8003         switch (ctxt->context->node->type) {
8004             case XML_ELEMENT_NODE:
8005             case XML_TEXT_NODE:
8006             case XML_CDATA_SECTION_NODE:
8007             case XML_ENTITY_REF_NODE:
8008             case XML_ENTITY_NODE:
8009             case XML_PI_NODE:
8010             case XML_COMMENT_NODE:
8011             case XML_NOTATION_NODE:
8012             case XML_DTD_NODE:
8013             case XML_ELEMENT_DECL:
8014             case XML_ATTRIBUTE_DECL:
8015             case XML_XINCLUDE_START:
8016             case XML_XINCLUDE_END:
8017             case XML_ENTITY_DECL:
8018                 if (ctxt->context->node->parent == NULL)
8019                     return((xmlNodePtr) ctxt->context->doc);
8020                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8021                     ((ctxt->context->node->parent->name[0] == ' ') ||
8022                      (xmlStrEqual(ctxt->context->node->parent->name,
8023                                  BAD_CAST "fake node libxslt"))))
8024                     return(NULL);
8025                 return(ctxt->context->node->parent);
8026             case XML_ATTRIBUTE_NODE: {
8027                 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8028
8029                 return(att->parent);
8030             }
8031             case XML_DOCUMENT_NODE:
8032             case XML_DOCUMENT_TYPE_NODE:
8033             case XML_DOCUMENT_FRAG_NODE:
8034             case XML_HTML_DOCUMENT_NODE:
8035 #ifdef LIBXML_DOCB_ENABLED
8036             case XML_DOCB_DOCUMENT_NODE:
8037 #endif
8038                 return(NULL);
8039             case XML_NAMESPACE_DECL: {
8040                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8041
8042                 if ((ns->next != NULL) &&
8043                     (ns->next->type != XML_NAMESPACE_DECL))
8044                     return((xmlNodePtr) ns->next);
8045                 return(NULL);
8046             }
8047         }
8048     }
8049     return(NULL);
8050 }
8051
8052 /**
8053  * xmlXPathNextAncestor:
8054  * @ctxt:  the XPath Parser context
8055  * @cur:  the current node in the traversal
8056  *
8057  * Traversal function for the "ancestor" direction
8058  * the ancestor axis contains the ancestors of the context node; the ancestors
8059  * of the context node consist of the parent of context node and the parent's
8060  * parent and so on; the nodes are ordered in reverse document order; thus the
8061  * parent is the first node on the axis, and the parent's parent is the second
8062  * node on the axis
8063  *
8064  * Returns the next element following that axis
8065  */
8066 xmlNodePtr
8067 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8068     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8069     /*
8070      * the parent of an attribute or namespace node is the element
8071      * to which the attribute or namespace node is attached
8072      * !!!!!!!!!!!!!
8073      */
8074     if (cur == NULL) {
8075         if (ctxt->context->node == NULL) return(NULL);
8076         switch (ctxt->context->node->type) {
8077             case XML_ELEMENT_NODE:
8078             case XML_TEXT_NODE:
8079             case XML_CDATA_SECTION_NODE:
8080             case XML_ENTITY_REF_NODE:
8081             case XML_ENTITY_NODE:
8082             case XML_PI_NODE:
8083             case XML_COMMENT_NODE:
8084             case XML_DTD_NODE:
8085             case XML_ELEMENT_DECL:
8086             case XML_ATTRIBUTE_DECL:
8087             case XML_ENTITY_DECL:
8088             case XML_NOTATION_NODE:
8089             case XML_XINCLUDE_START:
8090             case XML_XINCLUDE_END:
8091                 if (ctxt->context->node->parent == NULL)
8092                     return((xmlNodePtr) ctxt->context->doc);
8093                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8094                     ((ctxt->context->node->parent->name[0] == ' ') ||
8095                      (xmlStrEqual(ctxt->context->node->parent->name,
8096                                  BAD_CAST "fake node libxslt"))))
8097                     return(NULL);
8098                 return(ctxt->context->node->parent);
8099             case XML_ATTRIBUTE_NODE: {
8100                 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8101
8102                 return(tmp->parent);
8103             }
8104             case XML_DOCUMENT_NODE:
8105             case XML_DOCUMENT_TYPE_NODE:
8106             case XML_DOCUMENT_FRAG_NODE:
8107             case XML_HTML_DOCUMENT_NODE:
8108 #ifdef LIBXML_DOCB_ENABLED
8109             case XML_DOCB_DOCUMENT_NODE:
8110 #endif
8111                 return(NULL);
8112             case XML_NAMESPACE_DECL: {
8113                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8114
8115                 if ((ns->next != NULL) &&
8116                     (ns->next->type != XML_NAMESPACE_DECL))
8117                     return((xmlNodePtr) ns->next);
8118                 /* Bad, how did that namespace end up here ? */
8119                 return(NULL);
8120             }
8121         }
8122         return(NULL);
8123     }
8124     if (cur == ctxt->context->doc->children)
8125         return((xmlNodePtr) ctxt->context->doc);
8126     if (cur == (xmlNodePtr) ctxt->context->doc)
8127         return(NULL);
8128     switch (cur->type) {
8129         case XML_ELEMENT_NODE:
8130         case XML_TEXT_NODE:
8131         case XML_CDATA_SECTION_NODE:
8132         case XML_ENTITY_REF_NODE:
8133         case XML_ENTITY_NODE:
8134         case XML_PI_NODE:
8135         case XML_COMMENT_NODE:
8136         case XML_NOTATION_NODE:
8137         case XML_DTD_NODE:
8138         case XML_ELEMENT_DECL:
8139         case XML_ATTRIBUTE_DECL:
8140         case XML_ENTITY_DECL:
8141         case XML_XINCLUDE_START:
8142         case XML_XINCLUDE_END:
8143             if (cur->parent == NULL)
8144                 return(NULL);
8145             if ((cur->parent->type == XML_ELEMENT_NODE) &&
8146                 ((cur->parent->name[0] == ' ') ||
8147                  (xmlStrEqual(cur->parent->name,
8148                               BAD_CAST "fake node libxslt"))))
8149                 return(NULL);
8150             return(cur->parent);
8151         case XML_ATTRIBUTE_NODE: {
8152             xmlAttrPtr att = (xmlAttrPtr) cur;
8153
8154             return(att->parent);
8155         }
8156         case XML_NAMESPACE_DECL: {
8157             xmlNsPtr ns = (xmlNsPtr) cur;
8158
8159             if ((ns->next != NULL) &&
8160                 (ns->next->type != XML_NAMESPACE_DECL))
8161                 return((xmlNodePtr) ns->next);
8162             /* Bad, how did that namespace end up here ? */
8163             return(NULL);
8164         }
8165         case XML_DOCUMENT_NODE:
8166         case XML_DOCUMENT_TYPE_NODE:
8167         case XML_DOCUMENT_FRAG_NODE:
8168         case XML_HTML_DOCUMENT_NODE:
8169 #ifdef LIBXML_DOCB_ENABLED
8170         case XML_DOCB_DOCUMENT_NODE:
8171 #endif
8172             return(NULL);
8173     }
8174     return(NULL);
8175 }
8176
8177 /**
8178  * xmlXPathNextAncestorOrSelf:
8179  * @ctxt:  the XPath Parser context
8180  * @cur:  the current node in the traversal
8181  *
8182  * Traversal function for the "ancestor-or-self" direction
8183  * he ancestor-or-self axis contains the context node and ancestors of
8184  * the context node in reverse document order; thus the context node is
8185  * the first node on the axis, and the context node's parent the second;
8186  * parent here is defined the same as with the parent axis.
8187  *
8188  * Returns the next element following that axis
8189  */
8190 xmlNodePtr
8191 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8192     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8193     if (cur == NULL)
8194         return(ctxt->context->node);
8195     return(xmlXPathNextAncestor(ctxt, cur));
8196 }
8197
8198 /**
8199  * xmlXPathNextFollowingSibling:
8200  * @ctxt:  the XPath Parser context
8201  * @cur:  the current node in the traversal
8202  *
8203  * Traversal function for the "following-sibling" direction
8204  * The following-sibling axis contains the following siblings of the context
8205  * node in document order.
8206  *
8207  * Returns the next element following that axis
8208  */
8209 xmlNodePtr
8210 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8211     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8212     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8213         (ctxt->context->node->type == XML_NAMESPACE_DECL))
8214         return(NULL);
8215     if (cur == (xmlNodePtr) ctxt->context->doc)
8216         return(NULL);
8217     if (cur == NULL)
8218         return(ctxt->context->node->next);
8219     return(cur->next);
8220 }
8221
8222 /**
8223  * xmlXPathNextPrecedingSibling:
8224  * @ctxt:  the XPath Parser context
8225  * @cur:  the current node in the traversal
8226  *
8227  * Traversal function for the "preceding-sibling" direction
8228  * The preceding-sibling axis contains the preceding siblings of the context
8229  * node in reverse document order; the first preceding sibling is first on the
8230  * axis; the sibling preceding that node is the second on the axis and so on.
8231  *
8232  * Returns the next element following that axis
8233  */
8234 xmlNodePtr
8235 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8236     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8237     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8238         (ctxt->context->node->type == XML_NAMESPACE_DECL))
8239         return(NULL);
8240     if (cur == (xmlNodePtr) ctxt->context->doc)
8241         return(NULL);
8242     if (cur == NULL)
8243         return(ctxt->context->node->prev);
8244     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8245         cur = cur->prev;
8246         if (cur == NULL)
8247             return(ctxt->context->node->prev);
8248     }
8249     return(cur->prev);
8250 }
8251
8252 /**
8253  * xmlXPathNextFollowing:
8254  * @ctxt:  the XPath Parser context
8255  * @cur:  the current node in the traversal
8256  *
8257  * Traversal function for the "following" direction
8258  * The following axis contains all nodes in the same document as the context
8259  * node that are after the context node in document order, excluding any
8260  * descendants and excluding attribute nodes and namespace nodes; the nodes
8261  * are ordered in document order
8262  *
8263  * Returns the next element following that axis
8264  */
8265 xmlNodePtr
8266 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8267     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8268     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8269         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8270         return(cur->children);
8271
8272     if (cur == NULL) {
8273         cur = ctxt->context->node;
8274         if (cur->type == XML_ATTRIBUTE_NODE) {
8275             cur = cur->parent;
8276         } else if (cur->type == XML_NAMESPACE_DECL) {
8277             xmlNsPtr ns = (xmlNsPtr) cur;
8278
8279             if ((ns->next == NULL) ||
8280                 (ns->next->type == XML_NAMESPACE_DECL))
8281                 return (NULL);
8282             cur = (xmlNodePtr) ns->next;
8283         }
8284     }
8285     if (cur == NULL) return(NULL) ; /* ERROR */
8286     if (cur->next != NULL) return(cur->next) ;
8287     do {
8288         cur = cur->parent;
8289         if (cur == NULL) break;
8290         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8291         if (cur->next != NULL) return(cur->next);
8292     } while (cur != NULL);
8293     return(cur);
8294 }
8295
8296 /*
8297  * xmlXPathIsAncestor:
8298  * @ancestor:  the ancestor node
8299  * @node:  the current node
8300  *
8301  * Check that @ancestor is a @node's ancestor
8302  *
8303  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8304  */
8305 static int
8306 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8307     if ((ancestor == NULL) || (node == NULL)) return(0);
8308     if (node->type == XML_NAMESPACE_DECL)
8309         return(0);
8310     if (ancestor->type == XML_NAMESPACE_DECL)
8311         return(0);
8312     /* nodes need to be in the same document */
8313     if (ancestor->doc != node->doc) return(0);
8314     /* avoid searching if ancestor or node is the root node */
8315     if (ancestor == (xmlNodePtr) node->doc) return(1);
8316     if (node == (xmlNodePtr) ancestor->doc) return(0);
8317     while (node->parent != NULL) {
8318         if (node->parent == ancestor)
8319             return(1);
8320         node = node->parent;
8321     }
8322     return(0);
8323 }
8324
8325 /**
8326  * xmlXPathNextPreceding:
8327  * @ctxt:  the XPath Parser context
8328  * @cur:  the current node in the traversal
8329  *
8330  * Traversal function for the "preceding" direction
8331  * the preceding axis contains all nodes in the same document as the context
8332  * node that are before the context node in document order, excluding any
8333  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8334  * ordered in reverse document order
8335  *
8336  * Returns the next element following that axis
8337  */
8338 xmlNodePtr
8339 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8340 {
8341     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8342     if (cur == NULL) {
8343         cur = ctxt->context->node;
8344         if (cur->type == XML_ATTRIBUTE_NODE) {
8345             cur = cur->parent;
8346         } else if (cur->type == XML_NAMESPACE_DECL) {
8347             xmlNsPtr ns = (xmlNsPtr) cur;
8348
8349             if ((ns->next == NULL) ||
8350                 (ns->next->type == XML_NAMESPACE_DECL))
8351                 return (NULL);
8352             cur = (xmlNodePtr) ns->next;
8353         }
8354     }
8355     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8356         return (NULL);
8357     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8358         cur = cur->prev;
8359     do {
8360         if (cur->prev != NULL) {
8361             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8362             return (cur);
8363         }
8364
8365         cur = cur->parent;
8366         if (cur == NULL)
8367             return (NULL);
8368         if (cur == ctxt->context->doc->children)
8369             return (NULL);
8370     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8371     return (cur);
8372 }
8373
8374 /**
8375  * xmlXPathNextPrecedingInternal:
8376  * @ctxt:  the XPath Parser context
8377  * @cur:  the current node in the traversal
8378  *
8379  * Traversal function for the "preceding" direction
8380  * the preceding axis contains all nodes in the same document as the context
8381  * node that are before the context node in document order, excluding any
8382  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8383  * ordered in reverse document order
8384  * This is a faster implementation but internal only since it requires a
8385  * state kept in the parser context: ctxt->ancestor.
8386  *
8387  * Returns the next element following that axis
8388  */
8389 static xmlNodePtr
8390 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8391                               xmlNodePtr cur)
8392 {
8393     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8394     if (cur == NULL) {
8395         cur = ctxt->context->node;
8396         if (cur == NULL)
8397             return (NULL);
8398         if (cur->type == XML_ATTRIBUTE_NODE) {
8399             cur = cur->parent;
8400         } else if (cur->type == XML_NAMESPACE_DECL) {
8401             xmlNsPtr ns = (xmlNsPtr) cur;
8402
8403             if ((ns->next == NULL) ||
8404                 (ns->next->type == XML_NAMESPACE_DECL))
8405                 return (NULL);
8406             cur = (xmlNodePtr) ns->next;
8407         }
8408         ctxt->ancestor = cur->parent;
8409     }
8410     if (cur->type == XML_NAMESPACE_DECL)
8411         return(NULL);
8412     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8413         cur = cur->prev;
8414     while (cur->prev == NULL) {
8415         cur = cur->parent;
8416         if (cur == NULL)
8417             return (NULL);
8418         if (cur == ctxt->context->doc->children)
8419             return (NULL);
8420         if (cur != ctxt->ancestor)
8421             return (cur);
8422         ctxt->ancestor = cur->parent;
8423     }
8424     cur = cur->prev;
8425     while (cur->last != NULL)
8426         cur = cur->last;
8427     return (cur);
8428 }
8429
8430 /**
8431  * xmlXPathNextNamespace:
8432  * @ctxt:  the XPath Parser context
8433  * @cur:  the current attribute in the traversal
8434  *
8435  * Traversal function for the "namespace" direction
8436  * the namespace axis contains the namespace nodes of the context node;
8437  * the order of nodes on this axis is implementation-defined; the axis will
8438  * be empty unless the context node is an element
8439  *
8440  * We keep the XML namespace node at the end of the list.
8441  *
8442  * Returns the next element following that axis
8443  */
8444 xmlNodePtr
8445 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8446     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8447     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8448     if (cur == NULL) {
8449         if (ctxt->context->tmpNsList != NULL)
8450             xmlFree(ctxt->context->tmpNsList);
8451         ctxt->context->tmpNsList =
8452             xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8453         ctxt->context->tmpNsNr = 0;
8454         if (ctxt->context->tmpNsList != NULL) {
8455             while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8456                 ctxt->context->tmpNsNr++;
8457             }
8458         }
8459         return((xmlNodePtr) xmlXPathXMLNamespace);
8460     }
8461     if (ctxt->context->tmpNsNr > 0) {
8462         return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8463     } else {
8464         if (ctxt->context->tmpNsList != NULL)
8465             xmlFree(ctxt->context->tmpNsList);
8466         ctxt->context->tmpNsList = NULL;
8467         return(NULL);
8468     }
8469 }
8470
8471 /**
8472  * xmlXPathNextAttribute:
8473  * @ctxt:  the XPath Parser context
8474  * @cur:  the current attribute in the traversal
8475  *
8476  * Traversal function for the "attribute" direction
8477  * TODO: support DTD inherited default attributes
8478  *
8479  * Returns the next element following that axis
8480  */
8481 xmlNodePtr
8482 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8483     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8484     if (ctxt->context->node == NULL)
8485         return(NULL);
8486     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8487         return(NULL);
8488     if (cur == NULL) {
8489         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8490             return(NULL);
8491         return((xmlNodePtr)ctxt->context->node->properties);
8492     }
8493     return((xmlNodePtr)cur->next);
8494 }
8495
8496 /************************************************************************
8497  *                                                                      *
8498  *              NodeTest Functions                                      *
8499  *                                                                      *
8500  ************************************************************************/
8501
8502 #define IS_FUNCTION                     200
8503
8504
8505 /************************************************************************
8506  *                                                                      *
8507  *              Implicit tree core function library                     *
8508  *                                                                      *
8509  ************************************************************************/
8510
8511 /**
8512  * xmlXPathRoot:
8513  * @ctxt:  the XPath Parser context
8514  *
8515  * Initialize the context to the root of the document
8516  */
8517 void
8518 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8519     if ((ctxt == NULL) || (ctxt->context == NULL))
8520         return;
8521     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8522     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8523         ctxt->context->node));
8524 }
8525
8526 /************************************************************************
8527  *                                                                      *
8528  *              The explicit core function library                      *
8529  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8530  *                                                                      *
8531  ************************************************************************/
8532
8533
8534 /**
8535  * xmlXPathLastFunction:
8536  * @ctxt:  the XPath Parser context
8537  * @nargs:  the number of arguments
8538  *
8539  * Implement the last() XPath function
8540  *    number last()
8541  * The last function returns the number of nodes in the context node list.
8542  */
8543 void
8544 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8545     CHECK_ARITY(0);
8546     if (ctxt->context->contextSize >= 0) {
8547         valuePush(ctxt,
8548             xmlXPathCacheNewFloat(ctxt->context,
8549                 (double) ctxt->context->contextSize));
8550 #ifdef DEBUG_EXPR
8551         xmlGenericError(xmlGenericErrorContext,
8552                 "last() : %d\n", ctxt->context->contextSize);
8553 #endif
8554     } else {
8555         XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8556     }
8557 }
8558
8559 /**
8560  * xmlXPathPositionFunction:
8561  * @ctxt:  the XPath Parser context
8562  * @nargs:  the number of arguments
8563  *
8564  * Implement the position() XPath function
8565  *    number position()
8566  * The position function returns the position of the context node in the
8567  * context node list. The first position is 1, and so the last position
8568  * will be equal to last().
8569  */
8570 void
8571 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8572     CHECK_ARITY(0);
8573     if (ctxt->context->proximityPosition >= 0) {
8574         valuePush(ctxt,
8575               xmlXPathCacheNewFloat(ctxt->context,
8576                 (double) ctxt->context->proximityPosition));
8577 #ifdef DEBUG_EXPR
8578         xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8579                 ctxt->context->proximityPosition);
8580 #endif
8581     } else {
8582         XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8583     }
8584 }
8585
8586 /**
8587  * xmlXPathCountFunction:
8588  * @ctxt:  the XPath Parser context
8589  * @nargs:  the number of arguments
8590  *
8591  * Implement the count() XPath function
8592  *    number count(node-set)
8593  */
8594 void
8595 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8596     xmlXPathObjectPtr cur;
8597
8598     CHECK_ARITY(1);
8599     if ((ctxt->value == NULL) ||
8600         ((ctxt->value->type != XPATH_NODESET) &&
8601          (ctxt->value->type != XPATH_XSLT_TREE)))
8602         XP_ERROR(XPATH_INVALID_TYPE);
8603     cur = valuePop(ctxt);
8604
8605     if ((cur == NULL) || (cur->nodesetval == NULL))
8606         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8607     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8608         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8609             (double) cur->nodesetval->nodeNr));
8610     } else {
8611         if ((cur->nodesetval->nodeNr != 1) ||
8612             (cur->nodesetval->nodeTab == NULL)) {
8613             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8614         } else {
8615             xmlNodePtr tmp;
8616             int i = 0;
8617
8618             tmp = cur->nodesetval->nodeTab[0];
8619             if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8620                 tmp = tmp->children;
8621                 while (tmp != NULL) {
8622                     tmp = tmp->next;
8623                     i++;
8624                 }
8625             }
8626             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8627         }
8628     }
8629     xmlXPathReleaseObject(ctxt->context, cur);
8630 }
8631
8632 /**
8633  * xmlXPathGetElementsByIds:
8634  * @doc:  the document
8635  * @ids:  a whitespace separated list of IDs
8636  *
8637  * Selects elements by their unique ID.
8638  *
8639  * Returns a node-set of selected elements.
8640  */
8641 static xmlNodeSetPtr
8642 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8643     xmlNodeSetPtr ret;
8644     const xmlChar *cur = ids;
8645     xmlChar *ID;
8646     xmlAttrPtr attr;
8647     xmlNodePtr elem = NULL;
8648
8649     if (ids == NULL) return(NULL);
8650
8651     ret = xmlXPathNodeSetCreate(NULL);
8652     if (ret == NULL)
8653         return(ret);
8654
8655     while (IS_BLANK_CH(*cur)) cur++;
8656     while (*cur != 0) {
8657         while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8658             cur++;
8659
8660         ID = xmlStrndup(ids, cur - ids);
8661         if (ID != NULL) {
8662             /*
8663              * We used to check the fact that the value passed
8664              * was an NCName, but this generated much troubles for
8665              * me and Aleksey Sanin, people blatantly violated that
8666              * constaint, like Visa3D spec.
8667              * if (xmlValidateNCName(ID, 1) == 0)
8668              */
8669             attr = xmlGetID(doc, ID);
8670             if (attr != NULL) {
8671                 if (attr->type == XML_ATTRIBUTE_NODE)
8672                     elem = attr->parent;
8673                 else if (attr->type == XML_ELEMENT_NODE)
8674                     elem = (xmlNodePtr) attr;
8675                 else
8676                     elem = NULL;
8677                 if (elem != NULL)
8678                     xmlXPathNodeSetAdd(ret, elem);
8679             }
8680             xmlFree(ID);
8681         }
8682
8683         while (IS_BLANK_CH(*cur)) cur++;
8684         ids = cur;
8685     }
8686     return(ret);
8687 }
8688
8689 /**
8690  * xmlXPathIdFunction:
8691  * @ctxt:  the XPath Parser context
8692  * @nargs:  the number of arguments
8693  *
8694  * Implement the id() XPath function
8695  *    node-set id(object)
8696  * The id function selects elements by their unique ID
8697  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8698  * then the result is the union of the result of applying id to the
8699  * string value of each of the nodes in the argument node-set. When the
8700  * argument to id is of any other type, the argument is converted to a
8701  * string as if by a call to the string function; the string is split
8702  * into a whitespace-separated list of tokens (whitespace is any sequence
8703  * of characters matching the production S); the result is a node-set
8704  * containing the elements in the same document as the context node that
8705  * have a unique ID equal to any of the tokens in the list.
8706  */
8707 void
8708 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8709     xmlChar *tokens;
8710     xmlNodeSetPtr ret;
8711     xmlXPathObjectPtr obj;
8712
8713     CHECK_ARITY(1);
8714     obj = valuePop(ctxt);
8715     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8716     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8717         xmlNodeSetPtr ns;
8718         int i;
8719
8720         ret = xmlXPathNodeSetCreate(NULL);
8721         /*
8722          * FIXME -- in an out-of-memory condition this will behave badly.
8723          * The solution is not clear -- we already popped an item from
8724          * ctxt, so the object is in a corrupt state.
8725          */
8726
8727         if (obj->nodesetval != NULL) {
8728             for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8729                 tokens =
8730                     xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8731                 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8732                 ret = xmlXPathNodeSetMerge(ret, ns);
8733                 xmlXPathFreeNodeSet(ns);
8734                 if (tokens != NULL)
8735                     xmlFree(tokens);
8736             }
8737         }
8738         xmlXPathReleaseObject(ctxt->context, obj);
8739         valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8740         return;
8741     }
8742     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8743     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8744     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8745     xmlXPathReleaseObject(ctxt->context, obj);
8746     return;
8747 }
8748
8749 /**
8750  * xmlXPathLocalNameFunction:
8751  * @ctxt:  the XPath Parser context
8752  * @nargs:  the number of arguments
8753  *
8754  * Implement the local-name() XPath function
8755  *    string local-name(node-set?)
8756  * The local-name function returns a string containing the local part
8757  * of the name of the node in the argument node-set that is first in
8758  * document order. If the node-set is empty or the first node has no
8759  * name, an empty string is returned. If the argument is omitted it
8760  * defaults to the context node.
8761  */
8762 void
8763 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8764     xmlXPathObjectPtr cur;
8765
8766     if (ctxt == NULL) return;
8767
8768     if (nargs == 0) {
8769         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8770             ctxt->context->node));
8771         nargs = 1;
8772     }
8773
8774     CHECK_ARITY(1);
8775     if ((ctxt->value == NULL) ||
8776         ((ctxt->value->type != XPATH_NODESET) &&
8777          (ctxt->value->type != XPATH_XSLT_TREE)))
8778         XP_ERROR(XPATH_INVALID_TYPE);
8779     cur = valuePop(ctxt);
8780
8781     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8782         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8783     } else {
8784         int i = 0; /* Should be first in document order !!!!! */
8785         switch (cur->nodesetval->nodeTab[i]->type) {
8786         case XML_ELEMENT_NODE:
8787         case XML_ATTRIBUTE_NODE:
8788         case XML_PI_NODE:
8789             if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8790                 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8791             else
8792                 valuePush(ctxt,
8793                       xmlXPathCacheNewString(ctxt->context,
8794                         cur->nodesetval->nodeTab[i]->name));
8795             break;
8796         case XML_NAMESPACE_DECL:
8797             valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8798                         ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8799             break;
8800         default:
8801             valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8802         }
8803     }
8804     xmlXPathReleaseObject(ctxt->context, cur);
8805 }
8806
8807 /**
8808  * xmlXPathNamespaceURIFunction:
8809  * @ctxt:  the XPath Parser context
8810  * @nargs:  the number of arguments
8811  *
8812  * Implement the namespace-uri() XPath function
8813  *    string namespace-uri(node-set?)
8814  * The namespace-uri function returns a string containing the
8815  * namespace URI of the expanded name of the node in the argument
8816  * node-set that is first in document order. If the node-set is empty,
8817  * the first node has no name, or the expanded name has no namespace
8818  * URI, an empty string is returned. If the argument is omitted it
8819  * defaults to the context node.
8820  */
8821 void
8822 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8823     xmlXPathObjectPtr cur;
8824
8825     if (ctxt == NULL) return;
8826
8827     if (nargs == 0) {
8828         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8829             ctxt->context->node));
8830         nargs = 1;
8831     }
8832     CHECK_ARITY(1);
8833     if ((ctxt->value == NULL) ||
8834         ((ctxt->value->type != XPATH_NODESET) &&
8835          (ctxt->value->type != XPATH_XSLT_TREE)))
8836         XP_ERROR(XPATH_INVALID_TYPE);
8837     cur = valuePop(ctxt);
8838
8839     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8840         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8841     } else {
8842         int i = 0; /* Should be first in document order !!!!! */
8843         switch (cur->nodesetval->nodeTab[i]->type) {
8844         case XML_ELEMENT_NODE:
8845         case XML_ATTRIBUTE_NODE:
8846             if (cur->nodesetval->nodeTab[i]->ns == NULL)
8847                 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8848             else
8849                 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8850                           cur->nodesetval->nodeTab[i]->ns->href));
8851             break;
8852         default:
8853             valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8854         }
8855     }
8856     xmlXPathReleaseObject(ctxt->context, cur);
8857 }
8858
8859 /**
8860  * xmlXPathNameFunction:
8861  * @ctxt:  the XPath Parser context
8862  * @nargs:  the number of arguments
8863  *
8864  * Implement the name() XPath function
8865  *    string name(node-set?)
8866  * The name function returns a string containing a QName representing
8867  * the name of the node in the argument node-set that is first in document
8868  * order. The QName must represent the name with respect to the namespace
8869  * declarations in effect on the node whose name is being represented.
8870  * Typically, this will be the form in which the name occurred in the XML
8871  * source. This need not be the case if there are namespace declarations
8872  * in effect on the node that associate multiple prefixes with the same
8873  * namespace. However, an implementation may include information about
8874  * the original prefix in its representation of nodes; in this case, an
8875  * implementation can ensure that the returned string is always the same
8876  * as the QName used in the XML source. If the argument it omitted it
8877  * defaults to the context node.
8878  * Libxml keep the original prefix so the "real qualified name" used is
8879  * returned.
8880  */
8881 static void
8882 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8883 {
8884     xmlXPathObjectPtr cur;
8885
8886     if (nargs == 0) {
8887         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8888             ctxt->context->node));
8889         nargs = 1;
8890     }
8891
8892     CHECK_ARITY(1);
8893     if ((ctxt->value == NULL) ||
8894         ((ctxt->value->type != XPATH_NODESET) &&
8895          (ctxt->value->type != XPATH_XSLT_TREE)))
8896         XP_ERROR(XPATH_INVALID_TYPE);
8897     cur = valuePop(ctxt);
8898
8899     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8900         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8901     } else {
8902         int i = 0;              /* Should be first in document order !!!!! */
8903
8904         switch (cur->nodesetval->nodeTab[i]->type) {
8905             case XML_ELEMENT_NODE:
8906             case XML_ATTRIBUTE_NODE:
8907                 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8908                     valuePush(ctxt,
8909                         xmlXPathCacheNewCString(ctxt->context, ""));
8910                 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8911                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8912                     valuePush(ctxt,
8913                         xmlXPathCacheNewString(ctxt->context,
8914                             cur->nodesetval->nodeTab[i]->name));
8915                 } else {
8916                     xmlChar *fullname;
8917
8918                     fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8919                                      cur->nodesetval->nodeTab[i]->ns->prefix,
8920                                      NULL, 0);
8921                     if (fullname == cur->nodesetval->nodeTab[i]->name)
8922                         fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8923                     if (fullname == NULL) {
8924                         XP_ERROR(XPATH_MEMORY_ERROR);
8925                     }
8926                     valuePush(ctxt, xmlXPathCacheWrapString(
8927                         ctxt->context, fullname));
8928                 }
8929                 break;
8930             default:
8931                 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8932                     cur->nodesetval->nodeTab[i]));
8933                 xmlXPathLocalNameFunction(ctxt, 1);
8934         }
8935     }
8936     xmlXPathReleaseObject(ctxt->context, cur);
8937 }
8938
8939
8940 /**
8941  * xmlXPathStringFunction:
8942  * @ctxt:  the XPath Parser context
8943  * @nargs:  the number of arguments
8944  *
8945  * Implement the string() XPath function
8946  *    string string(object?)
8947  * The string function converts an object to a string as follows:
8948  *    - A node-set is converted to a string by returning the value of
8949  *      the node in the node-set that is first in document order.
8950  *      If the node-set is empty, an empty string is returned.
8951  *    - A number is converted to a string as follows
8952  *      + NaN is converted to the string NaN
8953  *      + positive zero is converted to the string 0
8954  *      + negative zero is converted to the string 0
8955  *      + positive infinity is converted to the string Infinity
8956  *      + negative infinity is converted to the string -Infinity
8957  *      + if the number is an integer, the number is represented in
8958  *        decimal form as a Number with no decimal point and no leading
8959  *        zeros, preceded by a minus sign (-) if the number is negative
8960  *      + otherwise, the number is represented in decimal form as a
8961  *        Number including a decimal point with at least one digit
8962  *        before the decimal point and at least one digit after the
8963  *        decimal point, preceded by a minus sign (-) if the number
8964  *        is negative; there must be no leading zeros before the decimal
8965  *        point apart possibly from the one required digit immediately
8966  *        before the decimal point; beyond the one required digit
8967  *        after the decimal point there must be as many, but only as
8968  *        many, more digits as are needed to uniquely distinguish the
8969  *        number from all other IEEE 754 numeric values.
8970  *    - The boolean false value is converted to the string false.
8971  *      The boolean true value is converted to the string true.
8972  *
8973  * If the argument is omitted, it defaults to a node-set with the
8974  * context node as its only member.
8975  */
8976 void
8977 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8978     xmlXPathObjectPtr cur;
8979
8980     if (ctxt == NULL) return;
8981     if (nargs == 0) {
8982     valuePush(ctxt,
8983         xmlXPathCacheWrapString(ctxt->context,
8984             xmlXPathCastNodeToString(ctxt->context->node)));
8985         return;
8986     }
8987
8988     CHECK_ARITY(1);
8989     cur = valuePop(ctxt);
8990     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8991     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8992 }
8993
8994 /**
8995  * xmlXPathStringLengthFunction:
8996  * @ctxt:  the XPath Parser context
8997  * @nargs:  the number of arguments
8998  *
8999  * Implement the string-length() XPath function
9000  *    number string-length(string?)
9001  * The string-length returns the number of characters in the string
9002  * (see [3.6 Strings]). If the argument is omitted, it defaults to
9003  * the context node converted to a string, in other words the value
9004  * of the context node.
9005  */
9006 void
9007 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9008     xmlXPathObjectPtr cur;
9009
9010     if (nargs == 0) {
9011         if ((ctxt == NULL) || (ctxt->context == NULL))
9012             return;
9013         if (ctxt->context->node == NULL) {
9014             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
9015         } else {
9016             xmlChar *content;
9017
9018             content = xmlXPathCastNodeToString(ctxt->context->node);
9019             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9020                 xmlUTF8Strlen(content)));
9021             xmlFree(content);
9022         }
9023         return;
9024     }
9025     CHECK_ARITY(1);
9026     CAST_TO_STRING;
9027     CHECK_TYPE(XPATH_STRING);
9028     cur = valuePop(ctxt);
9029     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9030         xmlUTF8Strlen(cur->stringval)));
9031     xmlXPathReleaseObject(ctxt->context, cur);
9032 }
9033
9034 /**
9035  * xmlXPathConcatFunction:
9036  * @ctxt:  the XPath Parser context
9037  * @nargs:  the number of arguments
9038  *
9039  * Implement the concat() XPath function
9040  *    string concat(string, string, string*)
9041  * The concat function returns the concatenation of its arguments.
9042  */
9043 void
9044 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9045     xmlXPathObjectPtr cur, newobj;
9046     xmlChar *tmp;
9047
9048     if (ctxt == NULL) return;
9049     if (nargs < 2) {
9050         CHECK_ARITY(2);
9051     }
9052
9053     CAST_TO_STRING;
9054     cur = valuePop(ctxt);
9055     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9056         xmlXPathReleaseObject(ctxt->context, cur);
9057         return;
9058     }
9059     nargs--;
9060
9061     while (nargs > 0) {
9062         CAST_TO_STRING;
9063         newobj = valuePop(ctxt);
9064         if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9065             xmlXPathReleaseObject(ctxt->context, newobj);
9066             xmlXPathReleaseObject(ctxt->context, cur);
9067             XP_ERROR(XPATH_INVALID_TYPE);
9068         }
9069         tmp = xmlStrcat(newobj->stringval, cur->stringval);
9070         newobj->stringval = cur->stringval;
9071         cur->stringval = tmp;
9072         xmlXPathReleaseObject(ctxt->context, newobj);
9073         nargs--;
9074     }
9075     valuePush(ctxt, cur);
9076 }
9077
9078 /**
9079  * xmlXPathContainsFunction:
9080  * @ctxt:  the XPath Parser context
9081  * @nargs:  the number of arguments
9082  *
9083  * Implement the contains() XPath function
9084  *    boolean contains(string, string)
9085  * The contains function returns true if the first argument string
9086  * contains the second argument string, and otherwise returns false.
9087  */
9088 void
9089 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9090     xmlXPathObjectPtr hay, needle;
9091
9092     CHECK_ARITY(2);
9093     CAST_TO_STRING;
9094     CHECK_TYPE(XPATH_STRING);
9095     needle = valuePop(ctxt);
9096     CAST_TO_STRING;
9097     hay = valuePop(ctxt);
9098
9099     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9100         xmlXPathReleaseObject(ctxt->context, hay);
9101         xmlXPathReleaseObject(ctxt->context, needle);
9102         XP_ERROR(XPATH_INVALID_TYPE);
9103     }
9104     if (xmlStrstr(hay->stringval, needle->stringval))
9105         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9106     else
9107         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9108     xmlXPathReleaseObject(ctxt->context, hay);
9109     xmlXPathReleaseObject(ctxt->context, needle);
9110 }
9111
9112 /**
9113  * xmlXPathStartsWithFunction:
9114  * @ctxt:  the XPath Parser context
9115  * @nargs:  the number of arguments
9116  *
9117  * Implement the starts-with() XPath function
9118  *    boolean starts-with(string, string)
9119  * The starts-with function returns true if the first argument string
9120  * starts with the second argument string, and otherwise returns false.
9121  */
9122 void
9123 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9124     xmlXPathObjectPtr hay, needle;
9125     int n;
9126
9127     CHECK_ARITY(2);
9128     CAST_TO_STRING;
9129     CHECK_TYPE(XPATH_STRING);
9130     needle = valuePop(ctxt);
9131     CAST_TO_STRING;
9132     hay = valuePop(ctxt);
9133
9134     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9135         xmlXPathReleaseObject(ctxt->context, hay);
9136         xmlXPathReleaseObject(ctxt->context, needle);
9137         XP_ERROR(XPATH_INVALID_TYPE);
9138     }
9139     n = xmlStrlen(needle->stringval);
9140     if (xmlStrncmp(hay->stringval, needle->stringval, n))
9141         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9142     else
9143         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9144     xmlXPathReleaseObject(ctxt->context, hay);
9145     xmlXPathReleaseObject(ctxt->context, needle);
9146 }
9147
9148 /**
9149  * xmlXPathSubstringFunction:
9150  * @ctxt:  the XPath Parser context
9151  * @nargs:  the number of arguments
9152  *
9153  * Implement the substring() XPath function
9154  *    string substring(string, number, number?)
9155  * The substring function returns the substring of the first argument
9156  * starting at the position specified in the second argument with
9157  * length specified in the third argument. For example,
9158  * substring("12345",2,3) returns "234". If the third argument is not
9159  * specified, it returns the substring starting at the position specified
9160  * in the second argument and continuing to the end of the string. For
9161  * example, substring("12345",2) returns "2345".  More precisely, each
9162  * character in the string (see [3.6 Strings]) is considered to have a
9163  * numeric position: the position of the first character is 1, the position
9164  * of the second character is 2 and so on. The returned substring contains
9165  * those characters for which the position of the character is greater than
9166  * or equal to the second argument and, if the third argument is specified,
9167  * less than the sum of the second and third arguments; the comparisons
9168  * and addition used for the above follow the standard IEEE 754 rules. Thus:
9169  *  - substring("12345", 1.5, 2.6) returns "234"
9170  *  - substring("12345", 0, 3) returns "12"
9171  *  - substring("12345", 0 div 0, 3) returns ""
9172  *  - substring("12345", 1, 0 div 0) returns ""
9173  *  - substring("12345", -42, 1 div 0) returns "12345"
9174  *  - substring("12345", -1 div 0, 1 div 0) returns ""
9175  */
9176 void
9177 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9178     xmlXPathObjectPtr str, start, len;
9179     double le=0, in;
9180     int i, l, m;
9181     xmlChar *ret;
9182
9183     if (nargs < 2) {
9184         CHECK_ARITY(2);
9185     }
9186     if (nargs > 3) {
9187         CHECK_ARITY(3);
9188     }
9189     /*
9190      * take care of possible last (position) argument
9191     */
9192     if (nargs == 3) {
9193         CAST_TO_NUMBER;
9194         CHECK_TYPE(XPATH_NUMBER);
9195         len = valuePop(ctxt);
9196         le = len->floatval;
9197         xmlXPathReleaseObject(ctxt->context, len);
9198     }
9199
9200     CAST_TO_NUMBER;
9201     CHECK_TYPE(XPATH_NUMBER);
9202     start = valuePop(ctxt);
9203     in = start->floatval;
9204     xmlXPathReleaseObject(ctxt->context, start);
9205     CAST_TO_STRING;
9206     CHECK_TYPE(XPATH_STRING);
9207     str = valuePop(ctxt);
9208     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9209
9210     /*
9211      * If last pos not present, calculate last position
9212     */
9213     if (nargs != 3) {
9214         le = (double)m;
9215         if (in < 1.0)
9216             in = 1.0;
9217     }
9218
9219     /* Need to check for the special cases where either
9220      * the index is NaN, the length is NaN, or both
9221      * arguments are infinity (relying on Inf + -Inf = NaN)
9222      */
9223     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9224         /*
9225          * To meet the requirements of the spec, the arguments
9226          * must be converted to integer format before
9227          * initial index calculations are done
9228          *
9229          * First we go to integer form, rounding up
9230          * and checking for special cases
9231          */
9232         i = (int) in;
9233         if (((double)i)+0.5 <= in) i++;
9234
9235         if (xmlXPathIsInf(le) == 1) {
9236             l = m;
9237             if (i < 1)
9238                 i = 1;
9239         }
9240         else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9241             l = 0;
9242         else {
9243             l = (int) le;
9244             if (((double)l)+0.5 <= le) l++;
9245         }
9246
9247         /* Now we normalize inidices */
9248         i -= 1;
9249         l += i;
9250         if (i < 0)
9251             i = 0;
9252         if (l > m)
9253             l = m;
9254
9255         /* number of chars to copy */
9256         l -= i;
9257
9258         ret = xmlUTF8Strsub(str->stringval, i, l);
9259     }
9260     else {
9261         ret = NULL;
9262     }
9263     if (ret == NULL)
9264         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9265     else {
9266         valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9267         xmlFree(ret);
9268     }
9269     xmlXPathReleaseObject(ctxt->context, str);
9270 }
9271
9272 /**
9273  * xmlXPathSubstringBeforeFunction:
9274  * @ctxt:  the XPath Parser context
9275  * @nargs:  the number of arguments
9276  *
9277  * Implement the substring-before() XPath function
9278  *    string substring-before(string, string)
9279  * The substring-before function returns the substring of the first
9280  * argument string that precedes the first occurrence of the second
9281  * argument string in the first argument string, or the empty string
9282  * if the first argument string does not contain the second argument
9283  * string. For example, substring-before("1999/04/01","/") returns 1999.
9284  */
9285 void
9286 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9287   xmlXPathObjectPtr str;
9288   xmlXPathObjectPtr find;
9289   xmlBufPtr target;
9290   const xmlChar *point;
9291   int offset;
9292
9293   CHECK_ARITY(2);
9294   CAST_TO_STRING;
9295   find = valuePop(ctxt);
9296   CAST_TO_STRING;
9297   str = valuePop(ctxt);
9298
9299   target = xmlBufCreate();
9300   if (target) {
9301     point = xmlStrstr(str->stringval, find->stringval);
9302     if (point) {
9303       offset = (int)(point - str->stringval);
9304       xmlBufAdd(target, str->stringval, offset);
9305     }
9306     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9307         xmlBufContent(target)));
9308     xmlBufFree(target);
9309   }
9310   xmlXPathReleaseObject(ctxt->context, str);
9311   xmlXPathReleaseObject(ctxt->context, find);
9312 }
9313
9314 /**
9315  * xmlXPathSubstringAfterFunction:
9316  * @ctxt:  the XPath Parser context
9317  * @nargs:  the number of arguments
9318  *
9319  * Implement the substring-after() XPath function
9320  *    string substring-after(string, string)
9321  * The substring-after function returns the substring of the first
9322  * argument string that follows the first occurrence of the second
9323  * argument string in the first argument string, or the empty stringi
9324  * if the first argument string does not contain the second argument
9325  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9326  * and substring-after("1999/04/01","19") returns 99/04/01.
9327  */
9328 void
9329 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9330   xmlXPathObjectPtr str;
9331   xmlXPathObjectPtr find;
9332   xmlBufPtr target;
9333   const xmlChar *point;
9334   int offset;
9335
9336   CHECK_ARITY(2);
9337   CAST_TO_STRING;
9338   find = valuePop(ctxt);
9339   CAST_TO_STRING;
9340   str = valuePop(ctxt);
9341
9342   target = xmlBufCreate();
9343   if (target) {
9344     point = xmlStrstr(str->stringval, find->stringval);
9345     if (point) {
9346       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9347       xmlBufAdd(target, &str->stringval[offset],
9348                    xmlStrlen(str->stringval) - offset);
9349     }
9350     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9351         xmlBufContent(target)));
9352     xmlBufFree(target);
9353   }
9354   xmlXPathReleaseObject(ctxt->context, str);
9355   xmlXPathReleaseObject(ctxt->context, find);
9356 }
9357
9358 /**
9359  * xmlXPathNormalizeFunction:
9360  * @ctxt:  the XPath Parser context
9361  * @nargs:  the number of arguments
9362  *
9363  * Implement the normalize-space() XPath function
9364  *    string normalize-space(string?)
9365  * The normalize-space function returns the argument string with white
9366  * space normalized by stripping leading and trailing whitespace
9367  * and replacing sequences of whitespace characters by a single
9368  * space. Whitespace characters are the same allowed by the S production
9369  * in XML. If the argument is omitted, it defaults to the context
9370  * node converted to a string, in other words the value of the context node.
9371  */
9372 void
9373 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9374   xmlXPathObjectPtr obj = NULL;
9375   xmlChar *source = NULL;
9376   xmlBufPtr target;
9377   xmlChar blank;
9378
9379   if (ctxt == NULL) return;
9380   if (nargs == 0) {
9381     /* Use current context node */
9382       valuePush(ctxt,
9383           xmlXPathCacheWrapString(ctxt->context,
9384             xmlXPathCastNodeToString(ctxt->context->node)));
9385     nargs = 1;
9386   }
9387
9388   CHECK_ARITY(1);
9389   CAST_TO_STRING;
9390   CHECK_TYPE(XPATH_STRING);
9391   obj = valuePop(ctxt);
9392   source = obj->stringval;
9393
9394   target = xmlBufCreate();
9395   if (target && source) {
9396
9397     /* Skip leading whitespaces */
9398     while (IS_BLANK_CH(*source))
9399       source++;
9400
9401     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9402     blank = 0;
9403     while (*source) {
9404       if (IS_BLANK_CH(*source)) {
9405         blank = 0x20;
9406       } else {
9407         if (blank) {
9408           xmlBufAdd(target, &blank, 1);
9409           blank = 0;
9410         }
9411         xmlBufAdd(target, source, 1);
9412       }
9413       source++;
9414     }
9415     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9416         xmlBufContent(target)));
9417     xmlBufFree(target);
9418   }
9419   xmlXPathReleaseObject(ctxt->context, obj);
9420 }
9421
9422 /**
9423  * xmlXPathTranslateFunction:
9424  * @ctxt:  the XPath Parser context
9425  * @nargs:  the number of arguments
9426  *
9427  * Implement the translate() XPath function
9428  *    string translate(string, string, string)
9429  * The translate function returns the first argument string with
9430  * occurrences of characters in the second argument string replaced
9431  * by the character at the corresponding position in the third argument
9432  * string. For example, translate("bar","abc","ABC") returns the string
9433  * BAr. If there is a character in the second argument string with no
9434  * character at a corresponding position in the third argument string
9435  * (because the second argument string is longer than the third argument
9436  * string), then occurrences of that character in the first argument
9437  * string are removed. For example, translate("--aaa--","abc-","ABC")
9438  * returns "AAA". If a character occurs more than once in second
9439  * argument string, then the first occurrence determines the replacement
9440  * character. If the third argument string is longer than the second
9441  * argument string, then excess characters are ignored.
9442  */
9443 void
9444 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9445     xmlXPathObjectPtr str;
9446     xmlXPathObjectPtr from;
9447     xmlXPathObjectPtr to;
9448     xmlBufPtr target;
9449     int offset, max;
9450     xmlChar ch;
9451     const xmlChar *point;
9452     xmlChar *cptr;
9453
9454     CHECK_ARITY(3);
9455
9456     CAST_TO_STRING;
9457     to = valuePop(ctxt);
9458     CAST_TO_STRING;
9459     from = valuePop(ctxt);
9460     CAST_TO_STRING;
9461     str = valuePop(ctxt);
9462
9463     target = xmlBufCreate();
9464     if (target) {
9465         max = xmlUTF8Strlen(to->stringval);
9466         for (cptr = str->stringval; (ch=*cptr); ) {
9467             offset = xmlUTF8Strloc(from->stringval, cptr);
9468             if (offset >= 0) {
9469                 if (offset < max) {
9470                     point = xmlUTF8Strpos(to->stringval, offset);
9471                     if (point)
9472                         xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9473                 }
9474             } else
9475                 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9476
9477             /* Step to next character in input */
9478             cptr++;
9479             if ( ch & 0x80 ) {
9480                 /* if not simple ascii, verify proper format */
9481                 if ( (ch & 0xc0) != 0xc0 ) {
9482                     xmlGenericError(xmlGenericErrorContext,
9483                         "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9484                     /* not asserting an XPath error is probably better */
9485                     break;
9486                 }
9487                 /* then skip over remaining bytes for this char */
9488                 while ( (ch <<= 1) & 0x80 )
9489                     if ( (*cptr++ & 0xc0) != 0x80 ) {
9490                         xmlGenericError(xmlGenericErrorContext,
9491                             "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9492                         /* not asserting an XPath error is probably better */
9493                         break;
9494                     }
9495                 if (ch & 0x80) /* must have had error encountered */
9496                     break;
9497             }
9498         }
9499     }
9500     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9501         xmlBufContent(target)));
9502     xmlBufFree(target);
9503     xmlXPathReleaseObject(ctxt->context, str);
9504     xmlXPathReleaseObject(ctxt->context, from);
9505     xmlXPathReleaseObject(ctxt->context, to);
9506 }
9507
9508 /**
9509  * xmlXPathBooleanFunction:
9510  * @ctxt:  the XPath Parser context
9511  * @nargs:  the number of arguments
9512  *
9513  * Implement the boolean() XPath function
9514  *    boolean boolean(object)
9515  * The boolean function converts its argument to a boolean as follows:
9516  *    - a number is true if and only if it is neither positive or
9517  *      negative zero nor NaN
9518  *    - a node-set is true if and only if it is non-empty
9519  *    - a string is true if and only if its length is non-zero
9520  */
9521 void
9522 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9523     xmlXPathObjectPtr cur;
9524
9525     CHECK_ARITY(1);
9526     cur = valuePop(ctxt);
9527     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9528     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9529     valuePush(ctxt, cur);
9530 }
9531
9532 /**
9533  * xmlXPathNotFunction:
9534  * @ctxt:  the XPath Parser context
9535  * @nargs:  the number of arguments
9536  *
9537  * Implement the not() XPath function
9538  *    boolean not(boolean)
9539  * The not function returns true if its argument is false,
9540  * and false otherwise.
9541  */
9542 void
9543 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9544     CHECK_ARITY(1);
9545     CAST_TO_BOOLEAN;
9546     CHECK_TYPE(XPATH_BOOLEAN);
9547     ctxt->value->boolval = ! ctxt->value->boolval;
9548 }
9549
9550 /**
9551  * xmlXPathTrueFunction:
9552  * @ctxt:  the XPath Parser context
9553  * @nargs:  the number of arguments
9554  *
9555  * Implement the true() XPath function
9556  *    boolean true()
9557  */
9558 void
9559 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9560     CHECK_ARITY(0);
9561     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9562 }
9563
9564 /**
9565  * xmlXPathFalseFunction:
9566  * @ctxt:  the XPath Parser context
9567  * @nargs:  the number of arguments
9568  *
9569  * Implement the false() XPath function
9570  *    boolean false()
9571  */
9572 void
9573 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9574     CHECK_ARITY(0);
9575     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9576 }
9577
9578 /**
9579  * xmlXPathLangFunction:
9580  * @ctxt:  the XPath Parser context
9581  * @nargs:  the number of arguments
9582  *
9583  * Implement the lang() XPath function
9584  *    boolean lang(string)
9585  * The lang function returns true or false depending on whether the
9586  * language of the context node as specified by xml:lang attributes
9587  * is the same as or is a sublanguage of the language specified by
9588  * the argument string. The language of the context node is determined
9589  * by the value of the xml:lang attribute on the context node, or, if
9590  * the context node has no xml:lang attribute, by the value of the
9591  * xml:lang attribute on the nearest ancestor of the context node that
9592  * has an xml:lang attribute. If there is no such attribute, then lang
9593  * returns false. If there is such an attribute, then lang returns
9594  * true if the attribute value is equal to the argument ignoring case,
9595  * or if there is some suffix starting with - such that the attribute
9596  * value is equal to the argument ignoring that suffix of the attribute
9597  * value and ignoring case.
9598  */
9599 void
9600 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9601     xmlXPathObjectPtr val = NULL;
9602     const xmlChar *theLang = NULL;
9603     const xmlChar *lang;
9604     int ret = 0;
9605     int i;
9606
9607     CHECK_ARITY(1);
9608     CAST_TO_STRING;
9609     CHECK_TYPE(XPATH_STRING);
9610     val = valuePop(ctxt);
9611     lang = val->stringval;
9612     theLang = xmlNodeGetLang(ctxt->context->node);
9613     if ((theLang != NULL) && (lang != NULL)) {
9614         for (i = 0;lang[i] != 0;i++)
9615             if (toupper(lang[i]) != toupper(theLang[i]))
9616                 goto not_equal;
9617         if ((theLang[i] == 0) || (theLang[i] == '-'))
9618             ret = 1;
9619     }
9620 not_equal:
9621     if (theLang != NULL)
9622         xmlFree((void *)theLang);
9623
9624     xmlXPathReleaseObject(ctxt->context, val);
9625     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9626 }
9627
9628 /**
9629  * xmlXPathNumberFunction:
9630  * @ctxt:  the XPath Parser context
9631  * @nargs:  the number of arguments
9632  *
9633  * Implement the number() XPath function
9634  *    number number(object?)
9635  */
9636 void
9637 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9638     xmlXPathObjectPtr cur;
9639     double res;
9640
9641     if (ctxt == NULL) return;
9642     if (nargs == 0) {
9643         if (ctxt->context->node == NULL) {
9644             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9645         } else {
9646             xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9647
9648             res = xmlXPathStringEvalNumber(content);
9649             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9650             xmlFree(content);
9651         }
9652         return;
9653     }
9654
9655     CHECK_ARITY(1);
9656     cur = valuePop(ctxt);
9657     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9658 }
9659
9660 /**
9661  * xmlXPathSumFunction:
9662  * @ctxt:  the XPath Parser context
9663  * @nargs:  the number of arguments
9664  *
9665  * Implement the sum() XPath function
9666  *    number sum(node-set)
9667  * The sum function returns the sum of the values of the nodes in
9668  * the argument node-set.
9669  */
9670 void
9671 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9672     xmlXPathObjectPtr cur;
9673     int i;
9674     double res = 0.0;
9675
9676     CHECK_ARITY(1);
9677     if ((ctxt->value == NULL) ||
9678         ((ctxt->value->type != XPATH_NODESET) &&
9679          (ctxt->value->type != XPATH_XSLT_TREE)))
9680         XP_ERROR(XPATH_INVALID_TYPE);
9681     cur = valuePop(ctxt);
9682
9683     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9684         for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9685             res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9686         }
9687     }
9688     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9689     xmlXPathReleaseObject(ctxt->context, cur);
9690 }
9691
9692 /**
9693  * xmlXPathFloorFunction:
9694  * @ctxt:  the XPath Parser context
9695  * @nargs:  the number of arguments
9696  *
9697  * Implement the floor() XPath function
9698  *    number floor(number)
9699  * The floor function returns the largest (closest to positive infinity)
9700  * number that is not greater than the argument and that is an integer.
9701  */
9702 void
9703 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9704     CHECK_ARITY(1);
9705     CAST_TO_NUMBER;
9706     CHECK_TYPE(XPATH_NUMBER);
9707
9708     ctxt->value->floatval = floor(ctxt->value->floatval);
9709 }
9710
9711 /**
9712  * xmlXPathCeilingFunction:
9713  * @ctxt:  the XPath Parser context
9714  * @nargs:  the number of arguments
9715  *
9716  * Implement the ceiling() XPath function
9717  *    number ceiling(number)
9718  * The ceiling function returns the smallest (closest to negative infinity)
9719  * number that is not less than the argument and that is an integer.
9720  */
9721 void
9722 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9723     CHECK_ARITY(1);
9724     CAST_TO_NUMBER;
9725     CHECK_TYPE(XPATH_NUMBER);
9726
9727     ctxt->value->floatval = ceil(ctxt->value->floatval);
9728 }
9729
9730 /**
9731  * xmlXPathRoundFunction:
9732  * @ctxt:  the XPath Parser context
9733  * @nargs:  the number of arguments
9734  *
9735  * Implement the round() XPath function
9736  *    number round(number)
9737  * The round function returns the number that is closest to the
9738  * argument and that is an integer. If there are two such numbers,
9739  * then the one that is closest to positive infinity is returned.
9740  */
9741 void
9742 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9743     double f;
9744
9745     CHECK_ARITY(1);
9746     CAST_TO_NUMBER;
9747     CHECK_TYPE(XPATH_NUMBER);
9748
9749     f = ctxt->value->floatval;
9750
9751     /* Test for zero to keep negative zero unchanged. */
9752     if ((xmlXPathIsNaN(f)) || (f == 0.0))
9753         return;
9754
9755     if ((f >= -0.5) && (f < 0.0)) {
9756         /* Negative zero. */
9757         ctxt->value->floatval = xmlXPathNZERO;
9758     }
9759     else {
9760         double rounded = floor(f);
9761         if (f - rounded >= 0.5)
9762             rounded += 1.0;
9763         ctxt->value->floatval = rounded;
9764     }
9765 }
9766
9767 /************************************************************************
9768  *                                                                      *
9769  *                      The Parser                                      *
9770  *                                                                      *
9771  ************************************************************************/
9772
9773 /*
9774  * a few forward declarations since we use a recursive call based
9775  * implementation.
9776  */
9777 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9778 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9779 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9780 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9781 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9782                                           int qualified);
9783
9784 /**
9785  * xmlXPathCurrentChar:
9786  * @ctxt:  the XPath parser context
9787  * @cur:  pointer to the beginning of the char
9788  * @len:  pointer to the length of the char read
9789  *
9790  * The current char value, if using UTF-8 this may actually span multiple
9791  * bytes in the input buffer.
9792  *
9793  * Returns the current char value and its length
9794  */
9795
9796 static int
9797 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9798     unsigned char c;
9799     unsigned int val;
9800     const xmlChar *cur;
9801
9802     if (ctxt == NULL)
9803         return(0);
9804     cur = ctxt->cur;
9805
9806     /*
9807      * We are supposed to handle UTF8, check it's valid
9808      * From rfc2044: encoding of the Unicode values on UTF-8:
9809      *
9810      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9811      * 0000 0000-0000 007F   0xxxxxxx
9812      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9813      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9814      *
9815      * Check for the 0x110000 limit too
9816      */
9817     c = *cur;
9818     if (c & 0x80) {
9819         if ((cur[1] & 0xc0) != 0x80)
9820             goto encoding_error;
9821         if ((c & 0xe0) == 0xe0) {
9822
9823             if ((cur[2] & 0xc0) != 0x80)
9824                 goto encoding_error;
9825             if ((c & 0xf0) == 0xf0) {
9826                 if (((c & 0xf8) != 0xf0) ||
9827                     ((cur[3] & 0xc0) != 0x80))
9828                     goto encoding_error;
9829                 /* 4-byte code */
9830                 *len = 4;
9831                 val = (cur[0] & 0x7) << 18;
9832                 val |= (cur[1] & 0x3f) << 12;
9833                 val |= (cur[2] & 0x3f) << 6;
9834                 val |= cur[3] & 0x3f;
9835             } else {
9836               /* 3-byte code */
9837                 *len = 3;
9838                 val = (cur[0] & 0xf) << 12;
9839                 val |= (cur[1] & 0x3f) << 6;
9840                 val |= cur[2] & 0x3f;
9841             }
9842         } else {
9843           /* 2-byte code */
9844             *len = 2;
9845             val = (cur[0] & 0x1f) << 6;
9846             val |= cur[1] & 0x3f;
9847         }
9848         if (!IS_CHAR(val)) {
9849             XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9850         }
9851         return(val);
9852     } else {
9853         /* 1-byte code */
9854         *len = 1;
9855         return((int) *cur);
9856     }
9857 encoding_error:
9858     /*
9859      * If we detect an UTF8 error that probably means that the
9860      * input encoding didn't get properly advertised in the
9861      * declaration header. Report the error and switch the encoding
9862      * to ISO-Latin-1 (if you don't like this policy, just declare the
9863      * encoding !)
9864      */
9865     *len = 0;
9866     XP_ERROR0(XPATH_ENCODING_ERROR);
9867 }
9868
9869 /**
9870  * xmlXPathParseNCName:
9871  * @ctxt:  the XPath Parser context
9872  *
9873  * parse an XML namespace non qualified name.
9874  *
9875  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9876  *
9877  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9878  *                       CombiningChar | Extender
9879  *
9880  * Returns the namespace name or NULL
9881  */
9882
9883 xmlChar *
9884 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9885     const xmlChar *in;
9886     xmlChar *ret;
9887     int count = 0;
9888
9889     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9890     /*
9891      * Accelerator for simple ASCII names
9892      */
9893     in = ctxt->cur;
9894     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9895         ((*in >= 0x41) && (*in <= 0x5A)) ||
9896         (*in == '_')) {
9897         in++;
9898         while (((*in >= 0x61) && (*in <= 0x7A)) ||
9899                ((*in >= 0x41) && (*in <= 0x5A)) ||
9900                ((*in >= 0x30) && (*in <= 0x39)) ||
9901                (*in == '_') || (*in == '.') ||
9902                (*in == '-'))
9903             in++;
9904         if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9905             (*in == '[') || (*in == ']') || (*in == ':') ||
9906             (*in == '@') || (*in == '*')) {
9907             count = in - ctxt->cur;
9908             if (count == 0)
9909                 return(NULL);
9910             ret = xmlStrndup(ctxt->cur, count);
9911             ctxt->cur = in;
9912             return(ret);
9913         }
9914     }
9915     return(xmlXPathParseNameComplex(ctxt, 0));
9916 }
9917
9918
9919 /**
9920  * xmlXPathParseQName:
9921  * @ctxt:  the XPath Parser context
9922  * @prefix:  a xmlChar **
9923  *
9924  * parse an XML qualified name
9925  *
9926  * [NS 5] QName ::= (Prefix ':')? LocalPart
9927  *
9928  * [NS 6] Prefix ::= NCName
9929  *
9930  * [NS 7] LocalPart ::= NCName
9931  *
9932  * Returns the function returns the local part, and prefix is updated
9933  *   to get the Prefix if any.
9934  */
9935
9936 static xmlChar *
9937 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9938     xmlChar *ret = NULL;
9939
9940     *prefix = NULL;
9941     ret = xmlXPathParseNCName(ctxt);
9942     if (ret && CUR == ':') {
9943         *prefix = ret;
9944         NEXT;
9945         ret = xmlXPathParseNCName(ctxt);
9946     }
9947     return(ret);
9948 }
9949
9950 /**
9951  * xmlXPathParseName:
9952  * @ctxt:  the XPath Parser context
9953  *
9954  * parse an XML name
9955  *
9956  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9957  *                  CombiningChar | Extender
9958  *
9959  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9960  *
9961  * Returns the namespace name or NULL
9962  */
9963
9964 xmlChar *
9965 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9966     const xmlChar *in;
9967     xmlChar *ret;
9968     size_t count = 0;
9969
9970     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9971     /*
9972      * Accelerator for simple ASCII names
9973      */
9974     in = ctxt->cur;
9975     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9976         ((*in >= 0x41) && (*in <= 0x5A)) ||
9977         (*in == '_') || (*in == ':')) {
9978         in++;
9979         while (((*in >= 0x61) && (*in <= 0x7A)) ||
9980                ((*in >= 0x41) && (*in <= 0x5A)) ||
9981                ((*in >= 0x30) && (*in <= 0x39)) ||
9982                (*in == '_') || (*in == '-') ||
9983                (*in == ':') || (*in == '.'))
9984             in++;
9985         if ((*in > 0) && (*in < 0x80)) {
9986             count = in - ctxt->cur;
9987             if (count > XML_MAX_NAME_LENGTH) {
9988                 ctxt->cur = in;
9989                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9990             }
9991             ret = xmlStrndup(ctxt->cur, count);
9992             ctxt->cur = in;
9993             return(ret);
9994         }
9995     }
9996     return(xmlXPathParseNameComplex(ctxt, 1));
9997 }
9998
9999 static xmlChar *
10000 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
10001     xmlChar buf[XML_MAX_NAMELEN + 5];
10002     int len = 0, l;
10003     int c;
10004
10005     /*
10006      * Handler for more complex cases
10007      */
10008     c = CUR_CHAR(l);
10009     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10010         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
10011         (c == '*') || /* accelerators */
10012         (!IS_LETTER(c) && (c != '_') &&
10013          ((!qualified) || (c != ':')))) {
10014         return(NULL);
10015     }
10016
10017     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10018            ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10019             (c == '.') || (c == '-') ||
10020             (c == '_') || ((qualified) && (c == ':')) ||
10021             (IS_COMBINING(c)) ||
10022             (IS_EXTENDER(c)))) {
10023         COPY_BUF(l,buf,len,c);
10024         NEXTL(l);
10025         c = CUR_CHAR(l);
10026         if (len >= XML_MAX_NAMELEN) {
10027             /*
10028              * Okay someone managed to make a huge name, so he's ready to pay
10029              * for the processing speed.
10030              */
10031             xmlChar *buffer;
10032             int max = len * 2;
10033
10034             if (len > XML_MAX_NAME_LENGTH) {
10035                 XP_ERRORNULL(XPATH_EXPR_ERROR);
10036             }
10037             buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10038             if (buffer == NULL) {
10039                 XP_ERRORNULL(XPATH_MEMORY_ERROR);
10040             }
10041             memcpy(buffer, buf, len);
10042             while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10043                    (c == '.') || (c == '-') ||
10044                    (c == '_') || ((qualified) && (c == ':')) ||
10045                    (IS_COMBINING(c)) ||
10046                    (IS_EXTENDER(c))) {
10047                 if (len + 10 > max) {
10048                     if (max > XML_MAX_NAME_LENGTH) {
10049                         XP_ERRORNULL(XPATH_EXPR_ERROR);
10050                     }
10051                     max *= 2;
10052                     buffer = (xmlChar *) xmlRealloc(buffer,
10053                                                     max * sizeof(xmlChar));
10054                     if (buffer == NULL) {
10055                         XP_ERRORNULL(XPATH_MEMORY_ERROR);
10056                     }
10057                 }
10058                 COPY_BUF(l,buffer,len,c);
10059                 NEXTL(l);
10060                 c = CUR_CHAR(l);
10061             }
10062             buffer[len] = 0;
10063             return(buffer);
10064         }
10065     }
10066     if (len == 0)
10067         return(NULL);
10068     return(xmlStrndup(buf, len));
10069 }
10070
10071 #define MAX_FRAC 20
10072
10073 /**
10074  * xmlXPathStringEvalNumber:
10075  * @str:  A string to scan
10076  *
10077  *  [30a]  Float  ::= Number ('e' Digits?)?
10078  *
10079  *  [30]   Number ::=   Digits ('.' Digits?)?
10080  *                    | '.' Digits
10081  *  [31]   Digits ::=   [0-9]+
10082  *
10083  * Compile a Number in the string
10084  * In complement of the Number expression, this function also handles
10085  * negative values : '-' Number.
10086  *
10087  * Returns the double value.
10088  */
10089 double
10090 xmlXPathStringEvalNumber(const xmlChar *str) {
10091     const xmlChar *cur = str;
10092     double ret;
10093     int ok = 0;
10094     int isneg = 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     if (cur == NULL) return(0);
10102     while (IS_BLANK_CH(*cur)) cur++;
10103     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10104         return(xmlXPathNAN);
10105     }
10106     if (*cur == '-') {
10107         isneg = 1;
10108         cur++;
10109     }
10110
10111 #ifdef __GNUC__
10112     /*
10113      * tmp/temp is a workaround against a gcc compiler bug
10114      * http://veillard.com/gcc.bug
10115      */
10116     ret = 0;
10117     while ((*cur >= '0') && (*cur <= '9')) {
10118         ret = ret * 10;
10119         tmp = (*cur - '0');
10120         ok = 1;
10121         cur++;
10122         temp = (double) tmp;
10123         ret = ret + temp;
10124     }
10125 #else
10126     ret = 0;
10127     while ((*cur >= '0') && (*cur <= '9')) {
10128         ret = ret * 10 + (*cur - '0');
10129         ok = 1;
10130         cur++;
10131     }
10132 #endif
10133
10134     if (*cur == '.') {
10135         int v, frac = 0, max;
10136         double fraction = 0;
10137
10138         cur++;
10139         if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10140             return(xmlXPathNAN);
10141         }
10142         while (*cur == '0') {
10143             frac = frac + 1;
10144             cur++;
10145         }
10146         max = frac + MAX_FRAC;
10147         while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10148             v = (*cur - '0');
10149             fraction = fraction * 10 + v;
10150             frac = frac + 1;
10151             cur++;
10152         }
10153         fraction /= pow(10.0, frac);
10154         ret = ret + fraction;
10155         while ((*cur >= '0') && (*cur <= '9'))
10156             cur++;
10157     }
10158     if ((*cur == 'e') || (*cur == 'E')) {
10159       cur++;
10160       if (*cur == '-') {
10161         is_exponent_negative = 1;
10162         cur++;
10163       } else if (*cur == '+') {
10164         cur++;
10165       }
10166       while ((*cur >= '0') && (*cur <= '9')) {
10167         if (exponent < 1000000)
10168           exponent = exponent * 10 + (*cur - '0');
10169         cur++;
10170       }
10171     }
10172     while (IS_BLANK_CH(*cur)) cur++;
10173     if (*cur != 0) return(xmlXPathNAN);
10174     if (isneg) ret = -ret;
10175     if (is_exponent_negative) exponent = -exponent;
10176     ret *= pow(10.0, (double)exponent);
10177     return(ret);
10178 }
10179
10180 /**
10181  * xmlXPathCompNumber:
10182  * @ctxt:  the XPath Parser context
10183  *
10184  *  [30]   Number ::=   Digits ('.' Digits?)?
10185  *                    | '.' Digits
10186  *  [31]   Digits ::=   [0-9]+
10187  *
10188  * Compile a Number, then push it on the stack
10189  *
10190  */
10191 static void
10192 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10193 {
10194     double ret = 0.0;
10195     int ok = 0;
10196     int exponent = 0;
10197     int is_exponent_negative = 0;
10198 #ifdef __GNUC__
10199     unsigned long tmp = 0;
10200     double temp;
10201 #endif
10202
10203     CHECK_ERROR;
10204     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10205         XP_ERROR(XPATH_NUMBER_ERROR);
10206     }
10207 #ifdef __GNUC__
10208     /*
10209      * tmp/temp is a workaround against a gcc compiler bug
10210      * http://veillard.com/gcc.bug
10211      */
10212     ret = 0;
10213     while ((CUR >= '0') && (CUR <= '9')) {
10214         ret = ret * 10;
10215         tmp = (CUR - '0');
10216         ok = 1;
10217         NEXT;
10218         temp = (double) tmp;
10219         ret = ret + temp;
10220     }
10221 #else
10222     ret = 0;
10223     while ((CUR >= '0') && (CUR <= '9')) {
10224         ret = ret * 10 + (CUR - '0');
10225         ok = 1;
10226         NEXT;
10227     }
10228 #endif
10229     if (CUR == '.') {
10230         int v, frac = 0, max;
10231         double fraction = 0;
10232
10233         NEXT;
10234         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10235             XP_ERROR(XPATH_NUMBER_ERROR);
10236         }
10237         while (CUR == '0') {
10238             frac = frac + 1;
10239             NEXT;
10240         }
10241         max = frac + MAX_FRAC;
10242         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10243             v = (CUR - '0');
10244             fraction = fraction * 10 + v;
10245             frac = frac + 1;
10246             NEXT;
10247         }
10248         fraction /= pow(10.0, frac);
10249         ret = ret + fraction;
10250         while ((CUR >= '0') && (CUR <= '9'))
10251             NEXT;
10252     }
10253     if ((CUR == 'e') || (CUR == 'E')) {
10254         NEXT;
10255         if (CUR == '-') {
10256             is_exponent_negative = 1;
10257             NEXT;
10258         } else if (CUR == '+') {
10259             NEXT;
10260         }
10261         while ((CUR >= '0') && (CUR <= '9')) {
10262             if (exponent < 1000000)
10263                 exponent = exponent * 10 + (CUR - '0');
10264             NEXT;
10265         }
10266         if (is_exponent_negative)
10267             exponent = -exponent;
10268         ret *= pow(10.0, (double) exponent);
10269     }
10270     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10271                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10272 }
10273
10274 /**
10275  * xmlXPathParseLiteral:
10276  * @ctxt:  the XPath Parser context
10277  *
10278  * Parse a Literal
10279  *
10280  *  [29]   Literal ::=   '"' [^"]* '"'
10281  *                    | "'" [^']* "'"
10282  *
10283  * Returns the value found or NULL in case of error
10284  */
10285 static xmlChar *
10286 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10287     const xmlChar *q;
10288     xmlChar *ret = NULL;
10289
10290     if (CUR == '"') {
10291         NEXT;
10292         q = CUR_PTR;
10293         while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10294             NEXT;
10295         if (!IS_CHAR_CH(CUR)) {
10296             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10297         } else {
10298             ret = xmlStrndup(q, CUR_PTR - q);
10299             NEXT;
10300         }
10301     } else if (CUR == '\'') {
10302         NEXT;
10303         q = CUR_PTR;
10304         while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10305             NEXT;
10306         if (!IS_CHAR_CH(CUR)) {
10307             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10308         } else {
10309             ret = xmlStrndup(q, CUR_PTR - q);
10310             NEXT;
10311         }
10312     } else {
10313         XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10314     }
10315     return(ret);
10316 }
10317
10318 /**
10319  * xmlXPathCompLiteral:
10320  * @ctxt:  the XPath Parser context
10321  *
10322  * Parse a Literal and push it on the stack.
10323  *
10324  *  [29]   Literal ::=   '"' [^"]* '"'
10325  *                    | "'" [^']* "'"
10326  *
10327  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10328  */
10329 static void
10330 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10331     const xmlChar *q;
10332     xmlChar *ret = NULL;
10333
10334     if (CUR == '"') {
10335         NEXT;
10336         q = CUR_PTR;
10337         while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10338             NEXT;
10339         if (!IS_CHAR_CH(CUR)) {
10340             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10341         } else {
10342             ret = xmlStrndup(q, CUR_PTR - q);
10343             NEXT;
10344         }
10345     } else if (CUR == '\'') {
10346         NEXT;
10347         q = CUR_PTR;
10348         while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10349             NEXT;
10350         if (!IS_CHAR_CH(CUR)) {
10351             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10352         } else {
10353             ret = xmlStrndup(q, CUR_PTR - q);
10354             NEXT;
10355         }
10356     } else {
10357         XP_ERROR(XPATH_START_LITERAL_ERROR);
10358     }
10359     if (ret == NULL) return;
10360     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10361                    xmlXPathCacheNewString(ctxt->context, ret), NULL);
10362     xmlFree(ret);
10363 }
10364
10365 /**
10366  * xmlXPathCompVariableReference:
10367  * @ctxt:  the XPath Parser context
10368  *
10369  * Parse a VariableReference, evaluate it and push it on the stack.
10370  *
10371  * The variable bindings consist of a mapping from variable names
10372  * to variable values. The value of a variable is an object, which can be
10373  * of any of the types that are possible for the value of an expression,
10374  * and may also be of additional types not specified here.
10375  *
10376  * Early evaluation is possible since:
10377  * The variable bindings [...] used to evaluate a subexpression are
10378  * always the same as those used to evaluate the containing expression.
10379  *
10380  *  [36]   VariableReference ::=   '$' QName
10381  */
10382 static void
10383 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10384     xmlChar *name;
10385     xmlChar *prefix;
10386
10387     SKIP_BLANKS;
10388     if (CUR != '$') {
10389         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10390     }
10391     NEXT;
10392     name = xmlXPathParseQName(ctxt, &prefix);
10393     if (name == NULL) {
10394         xmlFree(prefix);
10395         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10396     }
10397     ctxt->comp->last = -1;
10398     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10399                    name, prefix);
10400     SKIP_BLANKS;
10401     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10402         XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10403     }
10404 }
10405
10406 /**
10407  * xmlXPathIsNodeType:
10408  * @name:  a name string
10409  *
10410  * Is the name given a NodeType one.
10411  *
10412  *  [38]   NodeType ::=   'comment'
10413  *                    | 'text'
10414  *                    | 'processing-instruction'
10415  *                    | 'node'
10416  *
10417  * Returns 1 if true 0 otherwise
10418  */
10419 int
10420 xmlXPathIsNodeType(const xmlChar *name) {
10421     if (name == NULL)
10422         return(0);
10423
10424     if (xmlStrEqual(name, BAD_CAST "node"))
10425         return(1);
10426     if (xmlStrEqual(name, BAD_CAST "text"))
10427         return(1);
10428     if (xmlStrEqual(name, BAD_CAST "comment"))
10429         return(1);
10430     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10431         return(1);
10432     return(0);
10433 }
10434
10435 /**
10436  * xmlXPathCompFunctionCall:
10437  * @ctxt:  the XPath Parser context
10438  *
10439  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10440  *  [17]   Argument ::=   Expr
10441  *
10442  * Compile a function call, the evaluation of all arguments are
10443  * pushed on the stack
10444  */
10445 static void
10446 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10447     xmlChar *name;
10448     xmlChar *prefix;
10449     int nbargs = 0;
10450     int sort = 1;
10451
10452     name = xmlXPathParseQName(ctxt, &prefix);
10453     if (name == NULL) {
10454         xmlFree(prefix);
10455         XP_ERROR(XPATH_EXPR_ERROR);
10456     }
10457     SKIP_BLANKS;
10458 #ifdef DEBUG_EXPR
10459     if (prefix == NULL)
10460         xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10461                         name);
10462     else
10463         xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10464                         prefix, name);
10465 #endif
10466
10467     if (CUR != '(') {
10468         xmlFree(name);
10469         xmlFree(prefix);
10470         XP_ERROR(XPATH_EXPR_ERROR);
10471     }
10472     NEXT;
10473     SKIP_BLANKS;
10474
10475     /*
10476     * Optimization for count(): we don't need the node-set to be sorted.
10477     */
10478     if ((prefix == NULL) && (name[0] == 'c') &&
10479         xmlStrEqual(name, BAD_CAST "count"))
10480     {
10481         sort = 0;
10482     }
10483     ctxt->comp->last = -1;
10484     if (CUR != ')') {
10485         while (CUR != 0) {
10486             int op1 = ctxt->comp->last;
10487             ctxt->comp->last = -1;
10488             xmlXPathCompileExpr(ctxt, sort);
10489             if (ctxt->error != XPATH_EXPRESSION_OK) {
10490                 xmlFree(name);
10491                 xmlFree(prefix);
10492                 return;
10493             }
10494             PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10495             nbargs++;
10496             if (CUR == ')') break;
10497             if (CUR != ',') {
10498                 xmlFree(name);
10499                 xmlFree(prefix);
10500                 XP_ERROR(XPATH_EXPR_ERROR);
10501             }
10502             NEXT;
10503             SKIP_BLANKS;
10504         }
10505     }
10506     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10507                    name, prefix);
10508     NEXT;
10509     SKIP_BLANKS;
10510 }
10511
10512 /**
10513  * xmlXPathCompPrimaryExpr:
10514  * @ctxt:  the XPath Parser context
10515  *
10516  *  [15]   PrimaryExpr ::=   VariableReference
10517  *                | '(' Expr ')'
10518  *                | Literal
10519  *                | Number
10520  *                | FunctionCall
10521  *
10522  * Compile a primary expression.
10523  */
10524 static void
10525 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10526     SKIP_BLANKS;
10527     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10528     else if (CUR == '(') {
10529         NEXT;
10530         SKIP_BLANKS;
10531         xmlXPathCompileExpr(ctxt, 1);
10532         CHECK_ERROR;
10533         if (CUR != ')') {
10534             XP_ERROR(XPATH_EXPR_ERROR);
10535         }
10536         NEXT;
10537         SKIP_BLANKS;
10538     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10539         xmlXPathCompNumber(ctxt);
10540     } else if ((CUR == '\'') || (CUR == '"')) {
10541         xmlXPathCompLiteral(ctxt);
10542     } else {
10543         xmlXPathCompFunctionCall(ctxt);
10544     }
10545     SKIP_BLANKS;
10546 }
10547
10548 /**
10549  * xmlXPathCompFilterExpr:
10550  * @ctxt:  the XPath Parser context
10551  *
10552  *  [20]   FilterExpr ::=   PrimaryExpr
10553  *               | FilterExpr Predicate
10554  *
10555  * Compile a filter expression.
10556  * Square brackets are used to filter expressions in the same way that
10557  * they are used in location paths. It is an error if the expression to
10558  * be filtered does not evaluate to a node-set. The context node list
10559  * used for evaluating the expression in square brackets is the node-set
10560  * to be filtered listed in document order.
10561  */
10562
10563 static void
10564 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10565     xmlXPathCompPrimaryExpr(ctxt);
10566     CHECK_ERROR;
10567     SKIP_BLANKS;
10568
10569     while (CUR == '[') {
10570         xmlXPathCompPredicate(ctxt, 1);
10571         SKIP_BLANKS;
10572     }
10573
10574
10575 }
10576
10577 /**
10578  * xmlXPathScanName:
10579  * @ctxt:  the XPath Parser context
10580  *
10581  * Trickery: parse an XML name but without consuming the input flow
10582  * Needed to avoid insanity in the parser state.
10583  *
10584  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10585  *                  CombiningChar | Extender
10586  *
10587  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10588  *
10589  * [6] Names ::= Name (S Name)*
10590  *
10591  * Returns the Name parsed or NULL
10592  */
10593
10594 static xmlChar *
10595 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10596     int len = 0, l;
10597     int c;
10598     const xmlChar *cur;
10599     xmlChar *ret;
10600
10601     cur = ctxt->cur;
10602
10603     c = CUR_CHAR(l);
10604     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10605         (!IS_LETTER(c) && (c != '_') &&
10606          (c != ':'))) {
10607         return(NULL);
10608     }
10609
10610     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10611            ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10612             (c == '.') || (c == '-') ||
10613             (c == '_') || (c == ':') ||
10614             (IS_COMBINING(c)) ||
10615             (IS_EXTENDER(c)))) {
10616         len += l;
10617         NEXTL(l);
10618         c = CUR_CHAR(l);
10619     }
10620     ret = xmlStrndup(cur, ctxt->cur - cur);
10621     ctxt->cur = cur;
10622     return(ret);
10623 }
10624
10625 /**
10626  * xmlXPathCompPathExpr:
10627  * @ctxt:  the XPath Parser context
10628  *
10629  *  [19]   PathExpr ::=   LocationPath
10630  *               | FilterExpr
10631  *               | FilterExpr '/' RelativeLocationPath
10632  *               | FilterExpr '//' RelativeLocationPath
10633  *
10634  * Compile a path expression.
10635  * The / operator and // operators combine an arbitrary expression
10636  * and a relative location path. It is an error if the expression
10637  * does not evaluate to a node-set.
10638  * The / operator does composition in the same way as when / is
10639  * used in a location path. As in location paths, // is short for
10640  * /descendant-or-self::node()/.
10641  */
10642
10643 static void
10644 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10645     int lc = 1;           /* Should we branch to LocationPath ?         */
10646     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10647
10648     SKIP_BLANKS;
10649     if ((CUR == '$') || (CUR == '(') ||
10650         (IS_ASCII_DIGIT(CUR)) ||
10651         (CUR == '\'') || (CUR == '"') ||
10652         (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10653         lc = 0;
10654     } else if (CUR == '*') {
10655         /* relative or absolute location path */
10656         lc = 1;
10657     } else if (CUR == '/') {
10658         /* relative or absolute location path */
10659         lc = 1;
10660     } else if (CUR == '@') {
10661         /* relative abbreviated attribute location path */
10662         lc = 1;
10663     } else if (CUR == '.') {
10664         /* relative abbreviated attribute location path */
10665         lc = 1;
10666     } else {
10667         /*
10668          * Problem is finding if we have a name here whether it's:
10669          *   - a nodetype
10670          *   - a function call in which case it's followed by '('
10671          *   - an axis in which case it's followed by ':'
10672          *   - a element name
10673          * We do an a priori analysis here rather than having to
10674          * maintain parsed token content through the recursive function
10675          * calls. This looks uglier but makes the code easier to
10676          * read/write/debug.
10677          */
10678         SKIP_BLANKS;
10679         name = xmlXPathScanName(ctxt);
10680         if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10681 #ifdef DEBUG_STEP
10682             xmlGenericError(xmlGenericErrorContext,
10683                     "PathExpr: Axis\n");
10684 #endif
10685             lc = 1;
10686             xmlFree(name);
10687         } else if (name != NULL) {
10688             int len =xmlStrlen(name);
10689
10690
10691             while (NXT(len) != 0) {
10692                 if (NXT(len) == '/') {
10693                     /* element name */
10694 #ifdef DEBUG_STEP
10695                     xmlGenericError(xmlGenericErrorContext,
10696                             "PathExpr: AbbrRelLocation\n");
10697 #endif
10698                     lc = 1;
10699                     break;
10700                 } else if (IS_BLANK_CH(NXT(len))) {
10701                     /* ignore blanks */
10702                     ;
10703                 } else if (NXT(len) == ':') {
10704 #ifdef DEBUG_STEP
10705                     xmlGenericError(xmlGenericErrorContext,
10706                             "PathExpr: AbbrRelLocation\n");
10707 #endif
10708                     lc = 1;
10709                     break;
10710                 } else if ((NXT(len) == '(')) {
10711                     /* Node Type or Function */
10712                     if (xmlXPathIsNodeType(name)) {
10713 #ifdef DEBUG_STEP
10714                         xmlGenericError(xmlGenericErrorContext,
10715                                 "PathExpr: Type search\n");
10716 #endif
10717                         lc = 1;
10718 #ifdef LIBXML_XPTR_ENABLED
10719                     } else if (ctxt->xptr &&
10720                                xmlStrEqual(name, BAD_CAST "range-to")) {
10721                         lc = 1;
10722 #endif
10723                     } else {
10724 #ifdef DEBUG_STEP
10725                         xmlGenericError(xmlGenericErrorContext,
10726                                 "PathExpr: function call\n");
10727 #endif
10728                         lc = 0;
10729                     }
10730                     break;
10731                 } else if ((NXT(len) == '[')) {
10732                     /* element name */
10733 #ifdef DEBUG_STEP
10734                     xmlGenericError(xmlGenericErrorContext,
10735                             "PathExpr: AbbrRelLocation\n");
10736 #endif
10737                     lc = 1;
10738                     break;
10739                 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10740                            (NXT(len) == '=')) {
10741                     lc = 1;
10742                     break;
10743                 } else {
10744                     lc = 1;
10745                     break;
10746                 }
10747                 len++;
10748             }
10749             if (NXT(len) == 0) {
10750 #ifdef DEBUG_STEP
10751                 xmlGenericError(xmlGenericErrorContext,
10752                         "PathExpr: AbbrRelLocation\n");
10753 #endif
10754                 /* element name */
10755                 lc = 1;
10756             }
10757             xmlFree(name);
10758         } else {
10759             /* make sure all cases are covered explicitly */
10760             XP_ERROR(XPATH_EXPR_ERROR);
10761         }
10762     }
10763
10764     if (lc) {
10765         if (CUR == '/') {
10766             PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10767         } else {
10768             PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10769         }
10770         xmlXPathCompLocationPath(ctxt);
10771     } else {
10772         xmlXPathCompFilterExpr(ctxt);
10773         CHECK_ERROR;
10774         if ((CUR == '/') && (NXT(1) == '/')) {
10775             SKIP(2);
10776             SKIP_BLANKS;
10777
10778             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10779                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10780             PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10781
10782             xmlXPathCompRelativeLocationPath(ctxt);
10783         } else if (CUR == '/') {
10784             xmlXPathCompRelativeLocationPath(ctxt);
10785         }
10786     }
10787     SKIP_BLANKS;
10788 }
10789
10790 /**
10791  * xmlXPathCompUnionExpr:
10792  * @ctxt:  the XPath Parser context
10793  *
10794  *  [18]   UnionExpr ::=   PathExpr
10795  *               | UnionExpr '|' PathExpr
10796  *
10797  * Compile an union expression.
10798  */
10799
10800 static void
10801 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10802     xmlXPathCompPathExpr(ctxt);
10803     CHECK_ERROR;
10804     SKIP_BLANKS;
10805     while (CUR == '|') {
10806         int op1 = ctxt->comp->last;
10807         PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10808
10809         NEXT;
10810         SKIP_BLANKS;
10811         xmlXPathCompPathExpr(ctxt);
10812
10813         PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10814
10815         SKIP_BLANKS;
10816     }
10817 }
10818
10819 /**
10820  * xmlXPathCompUnaryExpr:
10821  * @ctxt:  the XPath Parser context
10822  *
10823  *  [27]   UnaryExpr ::=   UnionExpr
10824  *                   | '-' UnaryExpr
10825  *
10826  * Compile an unary expression.
10827  */
10828
10829 static void
10830 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10831     int minus = 0;
10832     int found = 0;
10833
10834     SKIP_BLANKS;
10835     while (CUR == '-') {
10836         minus = 1 - minus;
10837         found = 1;
10838         NEXT;
10839         SKIP_BLANKS;
10840     }
10841
10842     xmlXPathCompUnionExpr(ctxt);
10843     CHECK_ERROR;
10844     if (found) {
10845         if (minus)
10846             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10847         else
10848             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10849     }
10850 }
10851
10852 /**
10853  * xmlXPathCompMultiplicativeExpr:
10854  * @ctxt:  the XPath Parser context
10855  *
10856  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10857  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10858  *                   | MultiplicativeExpr 'div' UnaryExpr
10859  *                   | MultiplicativeExpr 'mod' UnaryExpr
10860  *  [34]   MultiplyOperator ::=   '*'
10861  *
10862  * Compile an Additive expression.
10863  */
10864
10865 static void
10866 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10867     xmlXPathCompUnaryExpr(ctxt);
10868     CHECK_ERROR;
10869     SKIP_BLANKS;
10870     while ((CUR == '*') ||
10871            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10872            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10873         int op = -1;
10874         int op1 = ctxt->comp->last;
10875
10876         if (CUR == '*') {
10877             op = 0;
10878             NEXT;
10879         } else if (CUR == 'd') {
10880             op = 1;
10881             SKIP(3);
10882         } else if (CUR == 'm') {
10883             op = 2;
10884             SKIP(3);
10885         }
10886         SKIP_BLANKS;
10887         xmlXPathCompUnaryExpr(ctxt);
10888         CHECK_ERROR;
10889         PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10890         SKIP_BLANKS;
10891     }
10892 }
10893
10894 /**
10895  * xmlXPathCompAdditiveExpr:
10896  * @ctxt:  the XPath Parser context
10897  *
10898  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10899  *                   | AdditiveExpr '+' MultiplicativeExpr
10900  *                   | AdditiveExpr '-' MultiplicativeExpr
10901  *
10902  * Compile an Additive expression.
10903  */
10904
10905 static void
10906 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10907
10908     xmlXPathCompMultiplicativeExpr(ctxt);
10909     CHECK_ERROR;
10910     SKIP_BLANKS;
10911     while ((CUR == '+') || (CUR == '-')) {
10912         int plus;
10913         int op1 = ctxt->comp->last;
10914
10915         if (CUR == '+') plus = 1;
10916         else plus = 0;
10917         NEXT;
10918         SKIP_BLANKS;
10919         xmlXPathCompMultiplicativeExpr(ctxt);
10920         CHECK_ERROR;
10921         PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10922         SKIP_BLANKS;
10923     }
10924 }
10925
10926 /**
10927  * xmlXPathCompRelationalExpr:
10928  * @ctxt:  the XPath Parser context
10929  *
10930  *  [24]   RelationalExpr ::=   AdditiveExpr
10931  *                 | RelationalExpr '<' AdditiveExpr
10932  *                 | RelationalExpr '>' AdditiveExpr
10933  *                 | RelationalExpr '<=' AdditiveExpr
10934  *                 | RelationalExpr '>=' AdditiveExpr
10935  *
10936  *  A <= B > C is allowed ? Answer from James, yes with
10937  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10938  *  which is basically what got implemented.
10939  *
10940  * Compile a Relational expression, then push the result
10941  * on the stack
10942  */
10943
10944 static void
10945 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10946     xmlXPathCompAdditiveExpr(ctxt);
10947     CHECK_ERROR;
10948     SKIP_BLANKS;
10949     while ((CUR == '<') ||
10950            (CUR == '>') ||
10951            ((CUR == '<') && (NXT(1) == '=')) ||
10952            ((CUR == '>') && (NXT(1) == '='))) {
10953         int inf, strict;
10954         int op1 = ctxt->comp->last;
10955
10956         if (CUR == '<') inf = 1;
10957         else inf = 0;
10958         if (NXT(1) == '=') strict = 0;
10959         else strict = 1;
10960         NEXT;
10961         if (!strict) NEXT;
10962         SKIP_BLANKS;
10963         xmlXPathCompAdditiveExpr(ctxt);
10964         CHECK_ERROR;
10965         PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10966         SKIP_BLANKS;
10967     }
10968 }
10969
10970 /**
10971  * xmlXPathCompEqualityExpr:
10972  * @ctxt:  the XPath Parser context
10973  *
10974  *  [23]   EqualityExpr ::=   RelationalExpr
10975  *                 | EqualityExpr '=' RelationalExpr
10976  *                 | EqualityExpr '!=' RelationalExpr
10977  *
10978  *  A != B != C is allowed ? Answer from James, yes with
10979  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10980  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10981  *  which is basically what got implemented.
10982  *
10983  * Compile an Equality expression.
10984  *
10985  */
10986 static void
10987 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10988     xmlXPathCompRelationalExpr(ctxt);
10989     CHECK_ERROR;
10990     SKIP_BLANKS;
10991     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10992         int eq;
10993         int op1 = ctxt->comp->last;
10994
10995         if (CUR == '=') eq = 1;
10996         else eq = 0;
10997         NEXT;
10998         if (!eq) NEXT;
10999         SKIP_BLANKS;
11000         xmlXPathCompRelationalExpr(ctxt);
11001         CHECK_ERROR;
11002         PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
11003         SKIP_BLANKS;
11004     }
11005 }
11006
11007 /**
11008  * xmlXPathCompAndExpr:
11009  * @ctxt:  the XPath Parser context
11010  *
11011  *  [22]   AndExpr ::=   EqualityExpr
11012  *                 | AndExpr 'and' EqualityExpr
11013  *
11014  * Compile an AND expression.
11015  *
11016  */
11017 static void
11018 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
11019     xmlXPathCompEqualityExpr(ctxt);
11020     CHECK_ERROR;
11021     SKIP_BLANKS;
11022     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
11023         int op1 = ctxt->comp->last;
11024         SKIP(3);
11025         SKIP_BLANKS;
11026         xmlXPathCompEqualityExpr(ctxt);
11027         CHECK_ERROR;
11028         PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11029         SKIP_BLANKS;
11030     }
11031 }
11032
11033 /**
11034  * xmlXPathCompileExpr:
11035  * @ctxt:  the XPath Parser context
11036  *
11037  *  [14]   Expr ::=   OrExpr
11038  *  [21]   OrExpr ::=   AndExpr
11039  *                 | OrExpr 'or' AndExpr
11040  *
11041  * Parse and compile an expression
11042  */
11043 static void
11044 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11045     xmlXPathCompAndExpr(ctxt);
11046     CHECK_ERROR;
11047     SKIP_BLANKS;
11048     while ((CUR == 'o') && (NXT(1) == 'r')) {
11049         int op1 = ctxt->comp->last;
11050         SKIP(2);
11051         SKIP_BLANKS;
11052         xmlXPathCompAndExpr(ctxt);
11053         CHECK_ERROR;
11054         PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11055         SKIP_BLANKS;
11056     }
11057     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11058         /* more ops could be optimized too */
11059         /*
11060         * This is the main place to eliminate sorting for
11061         * operations which don't require a sorted node-set.
11062         * E.g. count().
11063         */
11064         PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11065     }
11066 }
11067
11068 /**
11069  * xmlXPathCompPredicate:
11070  * @ctxt:  the XPath Parser context
11071  * @filter:  act as a filter
11072  *
11073  *  [8]   Predicate ::=   '[' PredicateExpr ']'
11074  *  [9]   PredicateExpr ::=   Expr
11075  *
11076  * Compile a predicate expression
11077  */
11078 static void
11079 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11080     int op1 = ctxt->comp->last;
11081
11082     SKIP_BLANKS;
11083     if (CUR != '[') {
11084         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11085     }
11086     NEXT;
11087     SKIP_BLANKS;
11088
11089     ctxt->comp->last = -1;
11090     /*
11091     * This call to xmlXPathCompileExpr() will deactivate sorting
11092     * of the predicate result.
11093     * TODO: Sorting is still activated for filters, since I'm not
11094     *  sure if needed. Normally sorting should not be needed, since
11095     *  a filter can only diminish the number of items in a sequence,
11096     *  but won't change its order; so if the initial sequence is sorted,
11097     *  subsequent sorting is not needed.
11098     */
11099     if (! filter)
11100         xmlXPathCompileExpr(ctxt, 0);
11101     else
11102         xmlXPathCompileExpr(ctxt, 1);
11103     CHECK_ERROR;
11104
11105     if (CUR != ']') {
11106         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11107     }
11108
11109     if (filter)
11110         PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11111     else
11112         PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11113
11114     NEXT;
11115     SKIP_BLANKS;
11116 }
11117
11118 /**
11119  * xmlXPathCompNodeTest:
11120  * @ctxt:  the XPath Parser context
11121  * @test:  pointer to a xmlXPathTestVal
11122  * @type:  pointer to a xmlXPathTypeVal
11123  * @prefix:  placeholder for a possible name prefix
11124  *
11125  * [7] NodeTest ::=   NameTest
11126  *                  | NodeType '(' ')'
11127  *                  | 'processing-instruction' '(' Literal ')'
11128  *
11129  * [37] NameTest ::=  '*'
11130  *                  | NCName ':' '*'
11131  *                  | QName
11132  * [38] NodeType ::= 'comment'
11133  *                 | 'text'
11134  *                 | 'processing-instruction'
11135  *                 | 'node'
11136  *
11137  * Returns the name found and updates @test, @type and @prefix appropriately
11138  */
11139 static xmlChar *
11140 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11141                      xmlXPathTypeVal *type, const xmlChar **prefix,
11142                      xmlChar *name) {
11143     int blanks;
11144
11145     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11146         STRANGE;
11147         return(NULL);
11148     }
11149     *type = (xmlXPathTypeVal) 0;
11150     *test = (xmlXPathTestVal) 0;
11151     *prefix = NULL;
11152     SKIP_BLANKS;
11153
11154     if ((name == NULL) && (CUR == '*')) {
11155         /*
11156          * All elements
11157          */
11158         NEXT;
11159         *test = NODE_TEST_ALL;
11160         return(NULL);
11161     }
11162
11163     if (name == NULL)
11164         name = xmlXPathParseNCName(ctxt);
11165     if (name == NULL) {
11166         XP_ERRORNULL(XPATH_EXPR_ERROR);
11167     }
11168
11169     blanks = IS_BLANK_CH(CUR);
11170     SKIP_BLANKS;
11171     if (CUR == '(') {
11172         NEXT;
11173         /*
11174          * NodeType or PI search
11175          */
11176         if (xmlStrEqual(name, BAD_CAST "comment"))
11177             *type = NODE_TYPE_COMMENT;
11178         else if (xmlStrEqual(name, BAD_CAST "node"))
11179             *type = NODE_TYPE_NODE;
11180         else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11181             *type = NODE_TYPE_PI;
11182         else if (xmlStrEqual(name, BAD_CAST "text"))
11183             *type = NODE_TYPE_TEXT;
11184         else {
11185             if (name != NULL)
11186                 xmlFree(name);
11187             XP_ERRORNULL(XPATH_EXPR_ERROR);
11188         }
11189
11190         *test = NODE_TEST_TYPE;
11191
11192         SKIP_BLANKS;
11193         if (*type == NODE_TYPE_PI) {
11194             /*
11195              * Specific case: search a PI by name.
11196              */
11197             if (name != NULL)
11198                 xmlFree(name);
11199             name = NULL;
11200             if (CUR != ')') {
11201                 name = xmlXPathParseLiteral(ctxt);
11202                 CHECK_ERROR NULL;
11203                 *test = NODE_TEST_PI;
11204                 SKIP_BLANKS;
11205             }
11206         }
11207         if (CUR != ')') {
11208             if (name != NULL)
11209                 xmlFree(name);
11210             XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11211         }
11212         NEXT;
11213         return(name);
11214     }
11215     *test = NODE_TEST_NAME;
11216     if ((!blanks) && (CUR == ':')) {
11217         NEXT;
11218
11219         /*
11220          * Since currently the parser context don't have a
11221          * namespace list associated:
11222          * The namespace name for this prefix can be computed
11223          * only at evaluation time. The compilation is done
11224          * outside of any context.
11225          */
11226 #if 0
11227         *prefix = xmlXPathNsLookup(ctxt->context, name);
11228         if (name != NULL)
11229             xmlFree(name);
11230         if (*prefix == NULL) {
11231             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11232         }
11233 #else
11234         *prefix = name;
11235 #endif
11236
11237         if (CUR == '*') {
11238             /*
11239              * All elements
11240              */
11241             NEXT;
11242             *test = NODE_TEST_ALL;
11243             return(NULL);
11244         }
11245
11246         name = xmlXPathParseNCName(ctxt);
11247         if (name == NULL) {
11248             XP_ERRORNULL(XPATH_EXPR_ERROR);
11249         }
11250     }
11251     return(name);
11252 }
11253
11254 /**
11255  * xmlXPathIsAxisName:
11256  * @name:  a preparsed name token
11257  *
11258  * [6] AxisName ::=   'ancestor'
11259  *                  | 'ancestor-or-self'
11260  *                  | 'attribute'
11261  *                  | 'child'
11262  *                  | 'descendant'
11263  *                  | 'descendant-or-self'
11264  *                  | 'following'
11265  *                  | 'following-sibling'
11266  *                  | 'namespace'
11267  *                  | 'parent'
11268  *                  | 'preceding'
11269  *                  | 'preceding-sibling'
11270  *                  | 'self'
11271  *
11272  * Returns the axis or 0
11273  */
11274 static xmlXPathAxisVal
11275 xmlXPathIsAxisName(const xmlChar *name) {
11276     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11277     switch (name[0]) {
11278         case 'a':
11279             if (xmlStrEqual(name, BAD_CAST "ancestor"))
11280                 ret = AXIS_ANCESTOR;
11281             if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11282                 ret = AXIS_ANCESTOR_OR_SELF;
11283             if (xmlStrEqual(name, BAD_CAST "attribute"))
11284                 ret = AXIS_ATTRIBUTE;
11285             break;
11286         case 'c':
11287             if (xmlStrEqual(name, BAD_CAST "child"))
11288                 ret = AXIS_CHILD;
11289             break;
11290         case 'd':
11291             if (xmlStrEqual(name, BAD_CAST "descendant"))
11292                 ret = AXIS_DESCENDANT;
11293             if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11294                 ret = AXIS_DESCENDANT_OR_SELF;
11295             break;
11296         case 'f':
11297             if (xmlStrEqual(name, BAD_CAST "following"))
11298                 ret = AXIS_FOLLOWING;
11299             if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11300                 ret = AXIS_FOLLOWING_SIBLING;
11301             break;
11302         case 'n':
11303             if (xmlStrEqual(name, BAD_CAST "namespace"))
11304                 ret = AXIS_NAMESPACE;
11305             break;
11306         case 'p':
11307             if (xmlStrEqual(name, BAD_CAST "parent"))
11308                 ret = AXIS_PARENT;
11309             if (xmlStrEqual(name, BAD_CAST "preceding"))
11310                 ret = AXIS_PRECEDING;
11311             if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11312                 ret = AXIS_PRECEDING_SIBLING;
11313             break;
11314         case 's':
11315             if (xmlStrEqual(name, BAD_CAST "self"))
11316                 ret = AXIS_SELF;
11317             break;
11318     }
11319     return(ret);
11320 }
11321
11322 /**
11323  * xmlXPathCompStep:
11324  * @ctxt:  the XPath Parser context
11325  *
11326  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11327  *                  | AbbreviatedStep
11328  *
11329  * [12] AbbreviatedStep ::=   '.' | '..'
11330  *
11331  * [5] AxisSpecifier ::= AxisName '::'
11332  *                  | AbbreviatedAxisSpecifier
11333  *
11334  * [13] AbbreviatedAxisSpecifier ::= '@'?
11335  *
11336  * Modified for XPtr range support as:
11337  *
11338  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11339  *                     | AbbreviatedStep
11340  *                     | 'range-to' '(' Expr ')' Predicate*
11341  *
11342  * Compile one step in a Location Path
11343  * A location step of . is short for self::node(). This is
11344  * particularly useful in conjunction with //. For example, the
11345  * location path .//para is short for
11346  * self::node()/descendant-or-self::node()/child::para
11347  * and so will select all para descendant elements of the context
11348  * node.
11349  * Similarly, a location step of .. is short for parent::node().
11350  * For example, ../title is short for parent::node()/child::title
11351  * and so will select the title children of the parent of the context
11352  * node.
11353  */
11354 static void
11355 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11356 #ifdef LIBXML_XPTR_ENABLED
11357     int rangeto = 0;
11358     int op2 = -1;
11359 #endif
11360
11361     SKIP_BLANKS;
11362     if ((CUR == '.') && (NXT(1) == '.')) {
11363         SKIP(2);
11364         SKIP_BLANKS;
11365         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11366                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11367     } else if (CUR == '.') {
11368         NEXT;
11369         SKIP_BLANKS;
11370     } else {
11371         xmlChar *name = NULL;
11372         const xmlChar *prefix = NULL;
11373         xmlXPathTestVal test = (xmlXPathTestVal) 0;
11374         xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11375         xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11376         int op1;
11377
11378         /*
11379          * The modification needed for XPointer change to the production
11380          */
11381 #ifdef LIBXML_XPTR_ENABLED
11382         if (ctxt->xptr) {
11383             name = xmlXPathParseNCName(ctxt);
11384             if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11385                 op2 = ctxt->comp->last;
11386                 xmlFree(name);
11387                 SKIP_BLANKS;
11388                 if (CUR != '(') {
11389                     XP_ERROR(XPATH_EXPR_ERROR);
11390                 }
11391                 NEXT;
11392                 SKIP_BLANKS;
11393
11394                 xmlXPathCompileExpr(ctxt, 1);
11395                 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11396                 CHECK_ERROR;
11397
11398                 SKIP_BLANKS;
11399                 if (CUR != ')') {
11400                     XP_ERROR(XPATH_EXPR_ERROR);
11401                 }
11402                 NEXT;
11403                 rangeto = 1;
11404                 goto eval_predicates;
11405             }
11406         }
11407 #endif
11408         if (CUR == '*') {
11409             axis = AXIS_CHILD;
11410         } else {
11411             if (name == NULL)
11412                 name = xmlXPathParseNCName(ctxt);
11413             if (name != NULL) {
11414                 axis = xmlXPathIsAxisName(name);
11415                 if (axis != 0) {
11416                     SKIP_BLANKS;
11417                     if ((CUR == ':') && (NXT(1) == ':')) {
11418                         SKIP(2);
11419                         xmlFree(name);
11420                         name = NULL;
11421                     } else {
11422                         /* an element name can conflict with an axis one :-\ */
11423                         axis = AXIS_CHILD;
11424                     }
11425                 } else {
11426                     axis = AXIS_CHILD;
11427                 }
11428             } else if (CUR == '@') {
11429                 NEXT;
11430                 axis = AXIS_ATTRIBUTE;
11431             } else {
11432                 axis = AXIS_CHILD;
11433             }
11434         }
11435
11436         if (ctxt->error != XPATH_EXPRESSION_OK) {
11437             xmlFree(name);
11438             return;
11439         }
11440
11441         name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11442         if (test == 0)
11443             return;
11444
11445         if ((prefix != NULL) && (ctxt->context != NULL) &&
11446             (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11447             if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11448                 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11449             }
11450         }
11451 #ifdef DEBUG_STEP
11452         xmlGenericError(xmlGenericErrorContext,
11453                 "Basis : computing new set\n");
11454 #endif
11455
11456 #ifdef DEBUG_STEP
11457         xmlGenericError(xmlGenericErrorContext, "Basis : ");
11458         if (ctxt->value == NULL)
11459             xmlGenericError(xmlGenericErrorContext, "no value\n");
11460         else if (ctxt->value->nodesetval == NULL)
11461             xmlGenericError(xmlGenericErrorContext, "Empty\n");
11462         else
11463             xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11464 #endif
11465
11466 #ifdef LIBXML_XPTR_ENABLED
11467 eval_predicates:
11468 #endif
11469         op1 = ctxt->comp->last;
11470         ctxt->comp->last = -1;
11471
11472         SKIP_BLANKS;
11473         while (CUR == '[') {
11474             xmlXPathCompPredicate(ctxt, 0);
11475         }
11476
11477 #ifdef LIBXML_XPTR_ENABLED
11478         if (rangeto) {
11479             PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11480         } else
11481 #endif
11482             PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11483                            test, type, (void *)prefix, (void *)name);
11484
11485     }
11486 #ifdef DEBUG_STEP
11487     xmlGenericError(xmlGenericErrorContext, "Step : ");
11488     if (ctxt->value == NULL)
11489         xmlGenericError(xmlGenericErrorContext, "no value\n");
11490     else if (ctxt->value->nodesetval == NULL)
11491         xmlGenericError(xmlGenericErrorContext, "Empty\n");
11492     else
11493         xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11494                 ctxt->value->nodesetval);
11495 #endif
11496 }
11497
11498 /**
11499  * xmlXPathCompRelativeLocationPath:
11500  * @ctxt:  the XPath Parser context
11501  *
11502  *  [3]   RelativeLocationPath ::=   Step
11503  *                     | RelativeLocationPath '/' Step
11504  *                     | AbbreviatedRelativeLocationPath
11505  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11506  *
11507  * Compile a relative location path.
11508  */
11509 static void
11510 xmlXPathCompRelativeLocationPath
11511 (xmlXPathParserContextPtr ctxt) {
11512     SKIP_BLANKS;
11513     if ((CUR == '/') && (NXT(1) == '/')) {
11514         SKIP(2);
11515         SKIP_BLANKS;
11516         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11517                          NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11518     } else if (CUR == '/') {
11519             NEXT;
11520         SKIP_BLANKS;
11521     }
11522     xmlXPathCompStep(ctxt);
11523     CHECK_ERROR;
11524     SKIP_BLANKS;
11525     while (CUR == '/') {
11526         if ((CUR == '/') && (NXT(1) == '/')) {
11527             SKIP(2);
11528             SKIP_BLANKS;
11529             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11530                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11531             xmlXPathCompStep(ctxt);
11532         } else if (CUR == '/') {
11533             NEXT;
11534             SKIP_BLANKS;
11535             xmlXPathCompStep(ctxt);
11536         }
11537         SKIP_BLANKS;
11538     }
11539 }
11540
11541 /**
11542  * xmlXPathCompLocationPath:
11543  * @ctxt:  the XPath Parser context
11544  *
11545  *  [1]   LocationPath ::=   RelativeLocationPath
11546  *                     | AbsoluteLocationPath
11547  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11548  *                     | AbbreviatedAbsoluteLocationPath
11549  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11550  *                           '//' RelativeLocationPath
11551  *
11552  * Compile a location path
11553  *
11554  * // is short for /descendant-or-self::node()/. For example,
11555  * //para is short for /descendant-or-self::node()/child::para and
11556  * so will select any para element in the document (even a para element
11557  * that is a document element will be selected by //para since the
11558  * document element node is a child of the root node); div//para is
11559  * short for div/descendant-or-self::node()/child::para and so will
11560  * select all para descendants of div children.
11561  */
11562 static void
11563 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11564     SKIP_BLANKS;
11565     if (CUR != '/') {
11566         xmlXPathCompRelativeLocationPath(ctxt);
11567     } else {
11568         while (CUR == '/') {
11569             if ((CUR == '/') && (NXT(1) == '/')) {
11570                 SKIP(2);
11571                 SKIP_BLANKS;
11572                 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11573                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11574                 xmlXPathCompRelativeLocationPath(ctxt);
11575             } else if (CUR == '/') {
11576                 NEXT;
11577                 SKIP_BLANKS;
11578                 if ((CUR != 0 ) &&
11579                     ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11580                      (CUR == '@') || (CUR == '*')))
11581                     xmlXPathCompRelativeLocationPath(ctxt);
11582             }
11583             CHECK_ERROR;
11584         }
11585     }
11586 }
11587
11588 /************************************************************************
11589  *                                                                      *
11590  *              XPath precompiled expression evaluation                 *
11591  *                                                                      *
11592  ************************************************************************/
11593
11594 static int
11595 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11596
11597 #ifdef DEBUG_STEP
11598 static void
11599 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11600                           int nbNodes)
11601 {
11602     xmlGenericError(xmlGenericErrorContext, "new step : ");
11603     switch (op->value) {
11604         case AXIS_ANCESTOR:
11605             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11606             break;
11607         case AXIS_ANCESTOR_OR_SELF:
11608             xmlGenericError(xmlGenericErrorContext,
11609                             "axis 'ancestors-or-self' ");
11610             break;
11611         case AXIS_ATTRIBUTE:
11612             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11613             break;
11614         case AXIS_CHILD:
11615             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11616             break;
11617         case AXIS_DESCENDANT:
11618             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11619             break;
11620         case AXIS_DESCENDANT_OR_SELF:
11621             xmlGenericError(xmlGenericErrorContext,
11622                             "axis 'descendant-or-self' ");
11623             break;
11624         case AXIS_FOLLOWING:
11625             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11626             break;
11627         case AXIS_FOLLOWING_SIBLING:
11628             xmlGenericError(xmlGenericErrorContext,
11629                             "axis 'following-siblings' ");
11630             break;
11631         case AXIS_NAMESPACE:
11632             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11633             break;
11634         case AXIS_PARENT:
11635             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11636             break;
11637         case AXIS_PRECEDING:
11638             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11639             break;
11640         case AXIS_PRECEDING_SIBLING:
11641             xmlGenericError(xmlGenericErrorContext,
11642                             "axis 'preceding-sibling' ");
11643             break;
11644         case AXIS_SELF:
11645             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11646             break;
11647     }
11648     xmlGenericError(xmlGenericErrorContext,
11649         " context contains %d nodes\n", nbNodes);
11650     switch (op->value2) {
11651         case NODE_TEST_NONE:
11652             xmlGenericError(xmlGenericErrorContext,
11653                             "           searching for none !!!\n");
11654             break;
11655         case NODE_TEST_TYPE:
11656             xmlGenericError(xmlGenericErrorContext,
11657                             "           searching for type %d\n", op->value3);
11658             break;
11659         case NODE_TEST_PI:
11660             xmlGenericError(xmlGenericErrorContext,
11661                             "           searching for PI !!!\n");
11662             break;
11663         case NODE_TEST_ALL:
11664             xmlGenericError(xmlGenericErrorContext,
11665                             "           searching for *\n");
11666             break;
11667         case NODE_TEST_NS:
11668             xmlGenericError(xmlGenericErrorContext,
11669                             "           searching for namespace %s\n",
11670                             op->value5);
11671             break;
11672         case NODE_TEST_NAME:
11673             xmlGenericError(xmlGenericErrorContext,
11674                             "           searching for name %s\n", op->value5);
11675             if (op->value4)
11676                 xmlGenericError(xmlGenericErrorContext,
11677                                 "           with namespace %s\n", op->value4);
11678             break;
11679     }
11680     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11681 }
11682 #endif /* DEBUG_STEP */
11683
11684 static int
11685 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11686                             xmlXPathStepOpPtr op,
11687                             xmlNodeSetPtr set,
11688                             int contextSize,
11689                             int hasNsNodes)
11690 {
11691     if (op->ch1 != -1) {
11692         xmlXPathCompExprPtr comp = ctxt->comp;
11693         /*
11694         * Process inner predicates first.
11695         */
11696         if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11697             /*
11698             * TODO: raise an internal error.
11699             */
11700         }
11701         contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11702             &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11703         CHECK_ERROR0;
11704         if (contextSize <= 0)
11705             return(0);
11706     }
11707     if (op->ch2 != -1) {
11708         xmlXPathContextPtr xpctxt = ctxt->context;
11709         xmlNodePtr contextNode, oldContextNode;
11710         xmlDocPtr oldContextDoc;
11711         int i, res, contextPos = 0, newContextSize;
11712         xmlXPathStepOpPtr exprOp;
11713         xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11714
11715 #ifdef LIBXML_XPTR_ENABLED
11716         /*
11717         * URGENT TODO: Check the following:
11718         *  We don't expect location sets if evaluating prediates, right?
11719         *  Only filters should expect location sets, right?
11720         */
11721 #endif
11722         /*
11723         * SPEC XPath 1.0:
11724         *  "For each node in the node-set to be filtered, the
11725         *  PredicateExpr is evaluated with that node as the
11726         *  context node, with the number of nodes in the
11727         *  node-set as the context size, and with the proximity
11728         *  position of the node in the node-set with respect to
11729         *  the axis as the context position;"
11730         * @oldset is the node-set" to be filtered.
11731         *
11732         * SPEC XPath 1.0:
11733         *  "only predicates change the context position and
11734         *  context size (see [2.4 Predicates])."
11735         * Example:
11736         *   node-set  context pos
11737         *    nA         1
11738         *    nB         2
11739         *    nC         3
11740         *   After applying predicate [position() > 1] :
11741         *   node-set  context pos
11742         *    nB         1
11743         *    nC         2
11744         */
11745         oldContextNode = xpctxt->node;
11746         oldContextDoc = xpctxt->doc;
11747         /*
11748         * Get the expression of this predicate.
11749         */
11750         exprOp = &ctxt->comp->steps[op->ch2];
11751         newContextSize = 0;
11752         for (i = 0; i < set->nodeNr; i++) {
11753             if (set->nodeTab[i] == NULL)
11754                 continue;
11755
11756             contextNode = set->nodeTab[i];
11757             xpctxt->node = contextNode;
11758             xpctxt->contextSize = contextSize;
11759             xpctxt->proximityPosition = ++contextPos;
11760
11761             /*
11762             * Also set the xpath document in case things like
11763             * key() are evaluated in the predicate.
11764             */
11765             if ((contextNode->type != XML_NAMESPACE_DECL) &&
11766                 (contextNode->doc != NULL))
11767                 xpctxt->doc = contextNode->doc;
11768             /*
11769             * Evaluate the predicate expression with 1 context node
11770             * at a time; this node is packaged into a node set; this
11771             * node set is handed over to the evaluation mechanism.
11772             */
11773             if (contextObj == NULL)
11774                 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11775             else {
11776                 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11777                     contextNode) < 0) {
11778                     ctxt->error = XPATH_MEMORY_ERROR;
11779                     goto evaluation_exit;
11780                 }
11781             }
11782
11783             valuePush(ctxt, contextObj);
11784
11785             res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11786
11787             if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11788                 xmlXPathNodeSetClear(set, hasNsNodes);
11789                 newContextSize = 0;
11790                 goto evaluation_exit;
11791             }
11792
11793             if (res != 0) {
11794                 newContextSize++;
11795             } else {
11796                 /*
11797                 * Remove the entry from the initial node set.
11798                 */
11799                 set->nodeTab[i] = NULL;
11800                 if (contextNode->type == XML_NAMESPACE_DECL)
11801                     xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11802             }
11803             if (ctxt->value == contextObj) {
11804                 /*
11805                 * Don't free the temporary XPath object holding the
11806                 * context node, in order to avoid massive recreation
11807                 * inside this loop.
11808                 */
11809                 valuePop(ctxt);
11810                 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11811             } else {
11812                 /*
11813                 * TODO: The object was lost in the evaluation machinery.
11814                 *  Can this happen? Maybe in internal-error cases.
11815                 */
11816                 contextObj = NULL;
11817             }
11818         }
11819
11820         if (contextObj != NULL) {
11821             if (ctxt->value == contextObj)
11822                 valuePop(ctxt);
11823             xmlXPathReleaseObject(xpctxt, contextObj);
11824         }
11825 evaluation_exit:
11826         if (exprRes != NULL)
11827             xmlXPathReleaseObject(ctxt->context, exprRes);
11828         /*
11829         * Reset/invalidate the context.
11830         */
11831         xpctxt->node = oldContextNode;
11832         xpctxt->doc = oldContextDoc;
11833         xpctxt->contextSize = -1;
11834         xpctxt->proximityPosition = -1;
11835         return(newContextSize);
11836     }
11837     return(contextSize);
11838 }
11839
11840 static int
11841 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11842                                       xmlXPathStepOpPtr op,
11843                                       xmlNodeSetPtr set,
11844                                       int contextSize,
11845                                       int minPos,
11846                                       int maxPos,
11847                                       int hasNsNodes)
11848 {
11849     if (op->ch1 != -1) {
11850         xmlXPathCompExprPtr comp = ctxt->comp;
11851         if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11852             /*
11853             * TODO: raise an internal error.
11854             */
11855         }
11856         contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11857             &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11858         CHECK_ERROR0;
11859         if (contextSize <= 0)
11860             return(0);
11861     }
11862     /*
11863     * Check if the node set contains a sufficient number of nodes for
11864     * the requested range.
11865     */
11866     if (contextSize < minPos) {
11867         xmlXPathNodeSetClear(set, hasNsNodes);
11868         return(0);
11869     }
11870     if (op->ch2 == -1) {
11871         /*
11872         * TODO: Can this ever happen?
11873         */
11874         return (contextSize);
11875     } else {
11876         xmlDocPtr oldContextDoc;
11877         int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11878         xmlXPathStepOpPtr exprOp;
11879         xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11880         xmlNodePtr oldContextNode, contextNode = NULL;
11881         xmlXPathContextPtr xpctxt = ctxt->context;
11882         int frame;
11883
11884 #ifdef LIBXML_XPTR_ENABLED
11885             /*
11886             * URGENT TODO: Check the following:
11887             *  We don't expect location sets if evaluating prediates, right?
11888             *  Only filters should expect location sets, right?
11889         */
11890 #endif /* LIBXML_XPTR_ENABLED */
11891
11892         /*
11893         * Save old context.
11894         */
11895         oldContextNode = xpctxt->node;
11896         oldContextDoc = xpctxt->doc;
11897         /*
11898         * Get the expression of this predicate.
11899         */
11900         exprOp = &ctxt->comp->steps[op->ch2];
11901         for (i = 0; i < set->nodeNr; i++) {
11902             xmlXPathObjectPtr tmp;
11903
11904             if (set->nodeTab[i] == NULL)
11905                 continue;
11906
11907             contextNode = set->nodeTab[i];
11908             xpctxt->node = contextNode;
11909             xpctxt->contextSize = contextSize;
11910             xpctxt->proximityPosition = ++contextPos;
11911
11912             /*
11913             * Initialize the new set.
11914             * Also set the xpath document in case things like
11915             * key() evaluation are attempted on the predicate
11916             */
11917             if ((contextNode->type != XML_NAMESPACE_DECL) &&
11918                 (contextNode->doc != NULL))
11919                 xpctxt->doc = contextNode->doc;
11920             /*
11921             * Evaluate the predicate expression with 1 context node
11922             * at a time; this node is packaged into a node set; this
11923             * node set is handed over to the evaluation mechanism.
11924             */
11925             if (contextObj == NULL)
11926                 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11927             else {
11928                 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11929                     contextNode) < 0) {
11930                     ctxt->error = XPATH_MEMORY_ERROR;
11931                     goto evaluation_exit;
11932                 }
11933             }
11934
11935             valuePush(ctxt, contextObj);
11936             frame = xmlXPathSetFrame(ctxt);
11937             res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11938             xmlXPathPopFrame(ctxt, frame);
11939             tmp = valuePop(ctxt);
11940
11941             if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11942                 while (tmp != contextObj) {
11943                     /*
11944                      * Free up the result
11945                      * then pop off contextObj, which will be freed later
11946                      */
11947                     xmlXPathReleaseObject(xpctxt, tmp);
11948                     tmp = valuePop(ctxt);
11949                 }
11950                 goto evaluation_error;
11951             }
11952             /* push the result back onto the stack */
11953             valuePush(ctxt, tmp);
11954
11955             if (res)
11956                 pos++;
11957
11958             if (res && (pos >= minPos) && (pos <= maxPos)) {
11959                 /*
11960                 * Fits in the requested range.
11961                 */
11962                 newContextSize++;
11963                 if (minPos == maxPos) {
11964                     /*
11965                     * Only 1 node was requested.
11966                     */
11967                     if (contextNode->type == XML_NAMESPACE_DECL) {
11968                         /*
11969                         * As always: take care of those nasty
11970                         * namespace nodes.
11971                         */
11972                         set->nodeTab[i] = NULL;
11973                     }
11974                     xmlXPathNodeSetClear(set, hasNsNodes);
11975                     set->nodeNr = 1;
11976                     set->nodeTab[0] = contextNode;
11977                     goto evaluation_exit;
11978                 }
11979                 if (pos == maxPos) {
11980                     /*
11981                     * We are done.
11982                     */
11983                     xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11984                     goto evaluation_exit;
11985                 }
11986             } else {
11987                 /*
11988                 * Remove the entry from the initial node set.
11989                 */
11990                 set->nodeTab[i] = NULL;
11991                 if (contextNode->type == XML_NAMESPACE_DECL)
11992                     xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11993             }
11994             if (exprRes != NULL) {
11995                 xmlXPathReleaseObject(ctxt->context, exprRes);
11996                 exprRes = NULL;
11997             }
11998             if (ctxt->value == contextObj) {
11999                 /*
12000                 * Don't free the temporary XPath object holding the
12001                 * context node, in order to avoid massive recreation
12002                 * inside this loop.
12003                 */
12004                 valuePop(ctxt);
12005                 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
12006             } else {
12007                 /*
12008                 * The object was lost in the evaluation machinery.
12009                 * Can this happen? Maybe in case of internal-errors.
12010                 */
12011                 contextObj = NULL;
12012             }
12013         }
12014         goto evaluation_exit;
12015
12016 evaluation_error:
12017         xmlXPathNodeSetClear(set, hasNsNodes);
12018         newContextSize = 0;
12019
12020 evaluation_exit:
12021         if (contextObj != NULL) {
12022             if (ctxt->value == contextObj)
12023                 valuePop(ctxt);
12024             xmlXPathReleaseObject(xpctxt, contextObj);
12025         }
12026         if (exprRes != NULL)
12027             xmlXPathReleaseObject(ctxt->context, exprRes);
12028         /*
12029         * Reset/invalidate the context.
12030         */
12031         xpctxt->node = oldContextNode;
12032         xpctxt->doc = oldContextDoc;
12033         xpctxt->contextSize = -1;
12034         xpctxt->proximityPosition = -1;
12035         return(newContextSize);
12036     }
12037     return(contextSize);
12038 }
12039
12040 static int
12041 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12042                             xmlXPathStepOpPtr op,
12043                             int *maxPos)
12044 {
12045
12046     xmlXPathStepOpPtr exprOp;
12047
12048     /*
12049     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12050     */
12051
12052     /*
12053     * If not -1, then ch1 will point to:
12054     * 1) For predicates (XPATH_OP_PREDICATE):
12055     *    - an inner predicate operator
12056     * 2) For filters (XPATH_OP_FILTER):
12057     *    - an inner filter operater OR
12058     *    - an expression selecting the node set.
12059     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
12060     */
12061     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12062         return(0);
12063
12064     if (op->ch2 != -1) {
12065         exprOp = &ctxt->comp->steps[op->ch2];
12066     } else
12067         return(0);
12068
12069     if ((exprOp != NULL) &&
12070         (exprOp->op == XPATH_OP_VALUE) &&
12071         (exprOp->value4 != NULL) &&
12072         (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12073     {
12074         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12075
12076         /*
12077         * We have a "[n]" predicate here.
12078         * TODO: Unfortunately this simplistic test here is not
12079         * able to detect a position() predicate in compound
12080         * expressions like "[@attr = 'a" and position() = 1],
12081         * and even not the usage of position() in
12082         * "[position() = 1]"; thus - obviously - a position-range,
12083         * like it "[position() < 5]", is also not detected.
12084         * Maybe we could rewrite the AST to ease the optimization.
12085         */
12086
12087         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12088             *maxPos = (int) floatval;
12089             if (floatval == (double) *maxPos)
12090                 return(1);
12091         }
12092     }
12093     return(0);
12094 }
12095
12096 static int
12097 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12098                            xmlXPathStepOpPtr op,
12099                            xmlNodePtr * first, xmlNodePtr * last,
12100                            int toBool)
12101 {
12102
12103 #define XP_TEST_HIT \
12104     if (hasAxisRange != 0) { \
12105         if (++pos == maxPos) { \
12106             if (addNode(seq, cur) < 0) \
12107                 ctxt->error = XPATH_MEMORY_ERROR; \
12108             goto axis_range_end; } \
12109     } else { \
12110         if (addNode(seq, cur) < 0) \
12111             ctxt->error = XPATH_MEMORY_ERROR; \
12112         if (breakOnFirstHit) goto first_hit; }
12113
12114 #define XP_TEST_HIT_NS \
12115     if (hasAxisRange != 0) { \
12116         if (++pos == maxPos) { \
12117             hasNsNodes = 1; \
12118             if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12119                 ctxt->error = XPATH_MEMORY_ERROR; \
12120         goto axis_range_end; } \
12121     } else { \
12122         hasNsNodes = 1; \
12123         if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12124             ctxt->error = XPATH_MEMORY_ERROR; \
12125         if (breakOnFirstHit) goto first_hit; }
12126
12127     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12128     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12129     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12130     const xmlChar *prefix = op->value4;
12131     const xmlChar *name = op->value5;
12132     const xmlChar *URI = NULL;
12133
12134 #ifdef DEBUG_STEP
12135     int nbMatches = 0, prevMatches = 0;
12136 #endif
12137     int total = 0, hasNsNodes = 0;
12138     /* The popped object holding the context nodes */
12139     xmlXPathObjectPtr obj;
12140     /* The set of context nodes for the node tests */
12141     xmlNodeSetPtr contextSeq;
12142     int contextIdx;
12143     xmlNodePtr contextNode;
12144     /* The final resulting node set wrt to all context nodes */
12145     xmlNodeSetPtr outSeq;
12146     /*
12147     * The temporary resulting node set wrt 1 context node.
12148     * Used to feed predicate evaluation.
12149     */
12150     xmlNodeSetPtr seq;
12151     xmlNodePtr cur;
12152     /* First predicate operator */
12153     xmlXPathStepOpPtr predOp;
12154     int maxPos; /* The requested position() (when a "[n]" predicate) */
12155     int hasPredicateRange, hasAxisRange, pos, size, newSize;
12156     int breakOnFirstHit;
12157
12158     xmlXPathTraversalFunction next = NULL;
12159     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12160     xmlXPathNodeSetMergeFunction mergeAndClear;
12161     xmlNodePtr oldContextNode;
12162     xmlXPathContextPtr xpctxt = ctxt->context;
12163
12164
12165     CHECK_TYPE0(XPATH_NODESET);
12166     obj = valuePop(ctxt);
12167     /*
12168     * Setup namespaces.
12169     */
12170     if (prefix != NULL) {
12171         URI = xmlXPathNsLookup(xpctxt, prefix);
12172         if (URI == NULL) {
12173             xmlXPathReleaseObject(xpctxt, obj);
12174             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12175         }
12176     }
12177     /*
12178     * Setup axis.
12179     *
12180     * MAYBE FUTURE TODO: merging optimizations:
12181     * - If the nodes to be traversed wrt to the initial nodes and
12182     *   the current axis cannot overlap, then we could avoid searching
12183     *   for duplicates during the merge.
12184     *   But the question is how/when to evaluate if they cannot overlap.
12185     *   Example: if we know that for two initial nodes, the one is
12186     *   not in the ancestor-or-self axis of the other, then we could safely
12187     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12188     *   the descendant-or-self axis.
12189     */
12190     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12191     switch (axis) {
12192         case AXIS_ANCESTOR:
12193             first = NULL;
12194             next = xmlXPathNextAncestor;
12195             break;
12196         case AXIS_ANCESTOR_OR_SELF:
12197             first = NULL;
12198             next = xmlXPathNextAncestorOrSelf;
12199             break;
12200         case AXIS_ATTRIBUTE:
12201             first = NULL;
12202             last = NULL;
12203             next = xmlXPathNextAttribute;
12204             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12205             break;
12206         case AXIS_CHILD:
12207             last = NULL;
12208             if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12209                 (type == NODE_TYPE_NODE))
12210             {
12211                 /*
12212                 * Optimization if an element node type is 'element'.
12213                 */
12214                 next = xmlXPathNextChildElement;
12215             } else
12216                 next = xmlXPathNextChild;
12217             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12218             break;
12219         case AXIS_DESCENDANT:
12220             last = NULL;
12221             next = xmlXPathNextDescendant;
12222             break;
12223         case AXIS_DESCENDANT_OR_SELF:
12224             last = NULL;
12225             next = xmlXPathNextDescendantOrSelf;
12226             break;
12227         case AXIS_FOLLOWING:
12228             last = NULL;
12229             next = xmlXPathNextFollowing;
12230             break;
12231         case AXIS_FOLLOWING_SIBLING:
12232             last = NULL;
12233             next = xmlXPathNextFollowingSibling;
12234             break;
12235         case AXIS_NAMESPACE:
12236             first = NULL;
12237             last = NULL;
12238             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12239             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12240             break;
12241         case AXIS_PARENT:
12242             first = NULL;
12243             next = xmlXPathNextParent;
12244             break;
12245         case AXIS_PRECEDING:
12246             first = NULL;
12247             next = xmlXPathNextPrecedingInternal;
12248             break;
12249         case AXIS_PRECEDING_SIBLING:
12250             first = NULL;
12251             next = xmlXPathNextPrecedingSibling;
12252             break;
12253         case AXIS_SELF:
12254             first = NULL;
12255             last = NULL;
12256             next = xmlXPathNextSelf;
12257             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12258             break;
12259     }
12260
12261 #ifdef DEBUG_STEP
12262     xmlXPathDebugDumpStepAxis(op,
12263         (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12264 #endif
12265
12266     if (next == NULL) {
12267         xmlXPathReleaseObject(xpctxt, obj);
12268         return(0);
12269     }
12270     contextSeq = obj->nodesetval;
12271     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12272         xmlXPathReleaseObject(xpctxt, obj);
12273         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12274         return(0);
12275     }
12276     /*
12277     * Predicate optimization ---------------------------------------------
12278     * If this step has a last predicate, which contains a position(),
12279     * then we'll optimize (although not exactly "position()", but only
12280     * the  short-hand form, i.e., "[n]".
12281     *
12282     * Example - expression "/foo[parent::bar][1]":
12283     *
12284     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12285     *   ROOT                               -- op->ch1
12286     *   PREDICATE                          -- op->ch2 (predOp)
12287     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12288     *       SORT
12289     *         COLLECT  'parent' 'name' 'node' bar
12290     *           NODE
12291     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12292     *
12293     */
12294     maxPos = 0;
12295     predOp = NULL;
12296     hasPredicateRange = 0;
12297     hasAxisRange = 0;
12298     if (op->ch2 != -1) {
12299         /*
12300         * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12301         */
12302         predOp = &ctxt->comp->steps[op->ch2];
12303         if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12304             if (predOp->ch1 != -1) {
12305                 /*
12306                 * Use the next inner predicate operator.
12307                 */
12308                 predOp = &ctxt->comp->steps[predOp->ch1];
12309                 hasPredicateRange = 1;
12310             } else {
12311                 /*
12312                 * There's no other predicate than the [n] predicate.
12313                 */
12314                 predOp = NULL;
12315                 hasAxisRange = 1;
12316             }
12317         }
12318     }
12319     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12320     /*
12321     * Axis traversal -----------------------------------------------------
12322     */
12323     /*
12324      * 2.3 Node Tests
12325      *  - For the attribute axis, the principal node type is attribute.
12326      *  - For the namespace axis, the principal node type is namespace.
12327      *  - For other axes, the principal node type is element.
12328      *
12329      * A node test * is true for any node of the
12330      * principal node type. For example, child::* will
12331      * select all element children of the context node
12332      */
12333     oldContextNode = xpctxt->node;
12334     addNode = xmlXPathNodeSetAddUnique;
12335     outSeq = NULL;
12336     seq = NULL;
12337     contextNode = NULL;
12338     contextIdx = 0;
12339
12340
12341     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12342            (ctxt->error == XPATH_EXPRESSION_OK)) {
12343         xpctxt->node = contextSeq->nodeTab[contextIdx++];
12344
12345         if (seq == NULL) {
12346             seq = xmlXPathNodeSetCreate(NULL);
12347             if (seq == NULL) {
12348                 total = 0;
12349                 goto error;
12350             }
12351         }
12352         /*
12353         * Traverse the axis and test the nodes.
12354         */
12355         pos = 0;
12356         cur = NULL;
12357         hasNsNodes = 0;
12358         do {
12359             cur = next(ctxt, cur);
12360             if (cur == NULL)
12361                 break;
12362
12363             /*
12364             * QUESTION TODO: What does the "first" and "last" stuff do?
12365             */
12366             if ((first != NULL) && (*first != NULL)) {
12367                 if (*first == cur)
12368                     break;
12369                 if (((total % 256) == 0) &&
12370 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12371                     (xmlXPathCmpNodesExt(*first, cur) >= 0))
12372 #else
12373                     (xmlXPathCmpNodes(*first, cur) >= 0))
12374 #endif
12375                 {
12376                     break;
12377                 }
12378             }
12379             if ((last != NULL) && (*last != NULL)) {
12380                 if (*last == cur)
12381                     break;
12382                 if (((total % 256) == 0) &&
12383 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12384                     (xmlXPathCmpNodesExt(cur, *last) >= 0))
12385 #else
12386                     (xmlXPathCmpNodes(cur, *last) >= 0))
12387 #endif
12388                 {
12389                     break;
12390                 }
12391             }
12392
12393             total++;
12394
12395 #ifdef DEBUG_STEP
12396             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12397 #endif
12398
12399             switch (test) {
12400                 case NODE_TEST_NONE:
12401                     total = 0;
12402                     STRANGE
12403                     goto error;
12404                 case NODE_TEST_TYPE:
12405                     if (type == NODE_TYPE_NODE) {
12406                         switch (cur->type) {
12407                             case XML_DOCUMENT_NODE:
12408                             case XML_HTML_DOCUMENT_NODE:
12409 #ifdef LIBXML_DOCB_ENABLED
12410                             case XML_DOCB_DOCUMENT_NODE:
12411 #endif
12412                             case XML_ELEMENT_NODE:
12413                             case XML_ATTRIBUTE_NODE:
12414                             case XML_PI_NODE:
12415                             case XML_COMMENT_NODE:
12416                             case XML_CDATA_SECTION_NODE:
12417                             case XML_TEXT_NODE:
12418                                 XP_TEST_HIT
12419                                 break;
12420                             case XML_NAMESPACE_DECL: {
12421                                 if (axis == AXIS_NAMESPACE) {
12422                                     XP_TEST_HIT_NS
12423                                 } else {
12424                                     hasNsNodes = 1;
12425                                     XP_TEST_HIT
12426                                 }
12427                                 break;
12428                             }
12429                             default:
12430                                 break;
12431                         }
12432                     } else if (cur->type == type) {
12433                         if (cur->type == XML_NAMESPACE_DECL)
12434                             XP_TEST_HIT_NS
12435                         else
12436                             XP_TEST_HIT
12437                     } else if ((type == NODE_TYPE_TEXT) &&
12438                          (cur->type == XML_CDATA_SECTION_NODE))
12439                     {
12440                         XP_TEST_HIT
12441                     }
12442                     break;
12443                 case NODE_TEST_PI:
12444                     if ((cur->type == XML_PI_NODE) &&
12445                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12446                     {
12447                         XP_TEST_HIT
12448                     }
12449                     break;
12450                 case NODE_TEST_ALL:
12451                     if (axis == AXIS_ATTRIBUTE) {
12452                         if (cur->type == XML_ATTRIBUTE_NODE)
12453                         {
12454                             if (prefix == NULL)
12455                             {
12456                                 XP_TEST_HIT
12457                             } else if ((cur->ns != NULL) &&
12458                                 (xmlStrEqual(URI, cur->ns->href)))
12459                             {
12460                                 XP_TEST_HIT
12461                             }
12462                         }
12463                     } else if (axis == AXIS_NAMESPACE) {
12464                         if (cur->type == XML_NAMESPACE_DECL)
12465                         {
12466                             XP_TEST_HIT_NS
12467                         }
12468                     } else {
12469                         if (cur->type == XML_ELEMENT_NODE) {
12470                             if (prefix == NULL)
12471                             {
12472                                 XP_TEST_HIT
12473
12474                             } else if ((cur->ns != NULL) &&
12475                                 (xmlStrEqual(URI, cur->ns->href)))
12476                             {
12477                                 XP_TEST_HIT
12478                             }
12479                         }
12480                     }
12481                     break;
12482                 case NODE_TEST_NS:{
12483                         TODO;
12484                         break;
12485                     }
12486                 case NODE_TEST_NAME:
12487                     if (axis == AXIS_ATTRIBUTE) {
12488                         if (cur->type != XML_ATTRIBUTE_NODE)
12489                             break;
12490                     } else if (axis == AXIS_NAMESPACE) {
12491                         if (cur->type != XML_NAMESPACE_DECL)
12492                             break;
12493                     } else {
12494                         if (cur->type != XML_ELEMENT_NODE)
12495                             break;
12496                     }
12497                     switch (cur->type) {
12498                         case XML_ELEMENT_NODE:
12499                             if (xmlStrEqual(name, cur->name)) {
12500                                 if (prefix == NULL) {
12501                                     if (cur->ns == NULL)
12502                                     {
12503                                         XP_TEST_HIT
12504                                     }
12505                                 } else {
12506                                     if ((cur->ns != NULL) &&
12507                                         (xmlStrEqual(URI, cur->ns->href)))
12508                                     {
12509                                         XP_TEST_HIT
12510                                     }
12511                                 }
12512                             }
12513                             break;
12514                         case XML_ATTRIBUTE_NODE:{
12515                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12516
12517                                 if (xmlStrEqual(name, attr->name)) {
12518                                     if (prefix == NULL) {
12519                                         if ((attr->ns == NULL) ||
12520                                             (attr->ns->prefix == NULL))
12521                                         {
12522                                             XP_TEST_HIT
12523                                         }
12524                                     } else {
12525                                         if ((attr->ns != NULL) &&
12526                                             (xmlStrEqual(URI,
12527                                               attr->ns->href)))
12528                                         {
12529                                             XP_TEST_HIT
12530                                         }
12531                                     }
12532                                 }
12533                                 break;
12534                             }
12535                         case XML_NAMESPACE_DECL:
12536                             if (cur->type == XML_NAMESPACE_DECL) {
12537                                 xmlNsPtr ns = (xmlNsPtr) cur;
12538
12539                                 if ((ns->prefix != NULL) && (name != NULL)
12540                                     && (xmlStrEqual(ns->prefix, name)))
12541                                 {
12542                                     XP_TEST_HIT_NS
12543                                 }
12544                             }
12545                             break;
12546                         default:
12547                             break;
12548                     }
12549                     break;
12550             } /* switch(test) */
12551         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12552
12553         goto apply_predicates;
12554
12555 axis_range_end: /* ----------------------------------------------------- */
12556         /*
12557         * We have a "/foo[n]", and position() = n was reached.
12558         * Note that we can have as well "/foo/::parent::foo[1]", so
12559         * a duplicate-aware merge is still needed.
12560         * Merge with the result.
12561         */
12562         if (outSeq == NULL) {
12563             outSeq = seq;
12564             seq = NULL;
12565         } else
12566             outSeq = mergeAndClear(outSeq, seq, 0);
12567         /*
12568         * Break if only a true/false result was requested.
12569         */
12570         if (toBool)
12571             break;
12572         continue;
12573
12574 first_hit: /* ---------------------------------------------------------- */
12575         /*
12576         * Break if only a true/false result was requested and
12577         * no predicates existed and a node test succeeded.
12578         */
12579         if (outSeq == NULL) {
12580             outSeq = seq;
12581             seq = NULL;
12582         } else
12583             outSeq = mergeAndClear(outSeq, seq, 0);
12584         break;
12585
12586 #ifdef DEBUG_STEP
12587         if (seq != NULL)
12588             nbMatches += seq->nodeNr;
12589 #endif
12590
12591 apply_predicates: /* --------------------------------------------------- */
12592         if (ctxt->error != XPATH_EXPRESSION_OK)
12593             goto error;
12594
12595         /*
12596         * Apply predicates.
12597         */
12598         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12599             /*
12600             * E.g. when we have a "/foo[some expression][n]".
12601             */
12602             /*
12603             * QUESTION TODO: The old predicate evaluation took into
12604             *  account location-sets.
12605             *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12606             *  Do we expect such a set here?
12607             *  All what I learned now from the evaluation semantics
12608             *  does not indicate that a location-set will be processed
12609             *  here, so this looks OK.
12610             */
12611             /*
12612             * Iterate over all predicates, starting with the outermost
12613             * predicate.
12614             * TODO: Problem: we cannot execute the inner predicates first
12615             *  since we cannot go back *up* the operator tree!
12616             *  Options we have:
12617             *  1) Use of recursive functions (like is it currently done
12618             *     via xmlXPathCompOpEval())
12619             *  2) Add a predicate evaluation information stack to the
12620             *     context struct
12621             *  3) Change the way the operators are linked; we need a
12622             *     "parent" field on xmlXPathStepOp
12623             *
12624             * For the moment, I'll try to solve this with a recursive
12625             * function: xmlXPathCompOpEvalPredicate().
12626             */
12627             size = seq->nodeNr;
12628             if (hasPredicateRange != 0)
12629                 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12630                     predOp, seq, size, maxPos, maxPos, hasNsNodes);
12631             else
12632                 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12633                     predOp, seq, size, hasNsNodes);
12634
12635             if (ctxt->error != XPATH_EXPRESSION_OK) {
12636                 total = 0;
12637                 goto error;
12638             }
12639             /*
12640             * Add the filtered set of nodes to the result node set.
12641             */
12642             if (newSize == 0) {
12643                 /*
12644                 * The predicates filtered all nodes out.
12645                 */
12646                 xmlXPathNodeSetClear(seq, hasNsNodes);
12647             } else if (seq->nodeNr > 0) {
12648                 /*
12649                 * Add to result set.
12650                 */
12651                 if (outSeq == NULL) {
12652                     if (size != newSize) {
12653                         /*
12654                         * We need to merge and clear here, since
12655                         * the sequence will contained NULLed entries.
12656                         */
12657                         outSeq = mergeAndClear(NULL, seq, 1);
12658                     } else {
12659                         outSeq = seq;
12660                         seq = NULL;
12661                     }
12662                 } else
12663                     outSeq = mergeAndClear(outSeq, seq,
12664                         (size != newSize) ? 1: 0);
12665                 /*
12666                 * Break if only a true/false result was requested.
12667                 */
12668                 if (toBool)
12669                     break;
12670             }
12671         } else if (seq->nodeNr > 0) {
12672             /*
12673             * Add to result set.
12674             */
12675             if (outSeq == NULL) {
12676                 outSeq = seq;
12677                 seq = NULL;
12678             } else {
12679                 outSeq = mergeAndClear(outSeq, seq, 0);
12680             }
12681         }
12682     }
12683
12684 error:
12685     if ((obj->boolval) && (obj->user != NULL)) {
12686         /*
12687         * QUESTION TODO: What does this do and why?
12688         * TODO: Do we have to do this also for the "error"
12689         * cleanup further down?
12690         */
12691         ctxt->value->boolval = 1;
12692         ctxt->value->user = obj->user;
12693         obj->user = NULL;
12694         obj->boolval = 0;
12695     }
12696     xmlXPathReleaseObject(xpctxt, obj);
12697
12698     /*
12699     * Ensure we return at least an emtpy set.
12700     */
12701     if (outSeq == NULL) {
12702         if ((seq != NULL) && (seq->nodeNr == 0))
12703             outSeq = seq;
12704         else
12705             outSeq = xmlXPathNodeSetCreate(NULL);
12706         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12707     }
12708     if ((seq != NULL) && (seq != outSeq)) {
12709          xmlXPathFreeNodeSet(seq);
12710     }
12711     /*
12712     * Hand over the result. Better to push the set also in
12713     * case of errors.
12714     */
12715     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12716     /*
12717     * Reset the context node.
12718     */
12719     xpctxt->node = oldContextNode;
12720     /*
12721     * When traversing the namespace axis in "toBool" mode, it's
12722     * possible that tmpNsList wasn't freed.
12723     */
12724     if (xpctxt->tmpNsList != NULL) {
12725         xmlFree(xpctxt->tmpNsList);
12726         xpctxt->tmpNsList = NULL;
12727     }
12728
12729 #ifdef DEBUG_STEP
12730     xmlGenericError(xmlGenericErrorContext,
12731         "\nExamined %d nodes, found %d nodes at that step\n",
12732         total, nbMatches);
12733 #endif
12734
12735     return(total);
12736 }
12737
12738 static int
12739 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12740                               xmlXPathStepOpPtr op, xmlNodePtr * first);
12741
12742 /**
12743  * xmlXPathCompOpEvalFirst:
12744  * @ctxt:  the XPath parser context with the compiled expression
12745  * @op:  an XPath compiled operation
12746  * @first:  the first elem found so far
12747  *
12748  * Evaluate the Precompiled XPath operation searching only the first
12749  * element in document order
12750  *
12751  * Returns the number of examined objects.
12752  */
12753 static int
12754 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12755                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12756 {
12757     int total = 0, cur;
12758     xmlXPathCompExprPtr comp;
12759     xmlXPathObjectPtr arg1, arg2;
12760
12761     CHECK_ERROR0;
12762     comp = ctxt->comp;
12763     switch (op->op) {
12764         case XPATH_OP_END:
12765             return (0);
12766         case XPATH_OP_UNION:
12767             total =
12768                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12769                                         first);
12770             CHECK_ERROR0;
12771             if ((ctxt->value != NULL)
12772                 && (ctxt->value->type == XPATH_NODESET)
12773                 && (ctxt->value->nodesetval != NULL)
12774                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12775                 /*
12776                  * limit tree traversing to first node in the result
12777                  */
12778                 /*
12779                 * OPTIMIZE TODO: This implicitely sorts
12780                 *  the result, even if not needed. E.g. if the argument
12781                 *  of the count() function, no sorting is needed.
12782                 * OPTIMIZE TODO: How do we know if the node-list wasn't
12783                 *  aready sorted?
12784                 */
12785                 if (ctxt->value->nodesetval->nodeNr > 1)
12786                     xmlXPathNodeSetSort(ctxt->value->nodesetval);
12787                 *first = ctxt->value->nodesetval->nodeTab[0];
12788             }
12789             cur =
12790                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12791                                         first);
12792             CHECK_ERROR0;
12793
12794             arg2 = valuePop(ctxt);
12795             arg1 = valuePop(ctxt);
12796             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12797                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12798                 xmlXPathReleaseObject(ctxt->context, arg1);
12799                 xmlXPathReleaseObject(ctxt->context, arg2);
12800                 XP_ERROR0(XPATH_INVALID_TYPE);
12801             }
12802
12803             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12804                                                     arg2->nodesetval);
12805             valuePush(ctxt, arg1);
12806             xmlXPathReleaseObject(ctxt->context, arg2);
12807             /* optimizer */
12808             if (total > cur)
12809                 xmlXPathCompSwap(op);
12810             return (total + cur);
12811         case XPATH_OP_ROOT:
12812             xmlXPathRoot(ctxt);
12813             return (0);
12814         case XPATH_OP_NODE:
12815             if (op->ch1 != -1)
12816                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12817             CHECK_ERROR0;
12818             if (op->ch2 != -1)
12819                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12820             CHECK_ERROR0;
12821             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12822                 ctxt->context->node));
12823             return (total);
12824         case XPATH_OP_RESET:
12825             if (op->ch1 != -1)
12826                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12827             CHECK_ERROR0;
12828             if (op->ch2 != -1)
12829                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12830             CHECK_ERROR0;
12831             ctxt->context->node = NULL;
12832             return (total);
12833         case XPATH_OP_COLLECT:{
12834                 if (op->ch1 == -1)
12835                     return (total);
12836
12837                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12838                 CHECK_ERROR0;
12839
12840                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12841                 return (total);
12842             }
12843         case XPATH_OP_VALUE:
12844             valuePush(ctxt,
12845                       xmlXPathCacheObjectCopy(ctxt->context,
12846                         (xmlXPathObjectPtr) op->value4));
12847             return (0);
12848         case XPATH_OP_SORT:
12849             if (op->ch1 != -1)
12850                 total +=
12851                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12852                                             first);
12853             CHECK_ERROR0;
12854             if ((ctxt->value != NULL)
12855                 && (ctxt->value->type == XPATH_NODESET)
12856                 && (ctxt->value->nodesetval != NULL)
12857                 && (ctxt->value->nodesetval->nodeNr > 1))
12858                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12859             return (total);
12860 #ifdef XP_OPTIMIZED_FILTER_FIRST
12861         case XPATH_OP_FILTER:
12862                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12863             return (total);
12864 #endif
12865         default:
12866             return (xmlXPathCompOpEval(ctxt, op));
12867     }
12868 }
12869
12870 /**
12871  * xmlXPathCompOpEvalLast:
12872  * @ctxt:  the XPath parser context with the compiled expression
12873  * @op:  an XPath compiled operation
12874  * @last:  the last elem found so far
12875  *
12876  * Evaluate the Precompiled XPath operation searching only the last
12877  * element in document order
12878  *
12879  * Returns the number of nodes traversed
12880  */
12881 static int
12882 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12883                        xmlNodePtr * last)
12884 {
12885     int total = 0, cur;
12886     xmlXPathCompExprPtr comp;
12887     xmlXPathObjectPtr arg1, arg2;
12888     xmlNodePtr bak;
12889     xmlDocPtr bakd;
12890     int pp;
12891     int cs;
12892
12893     CHECK_ERROR0;
12894     comp = ctxt->comp;
12895     switch (op->op) {
12896         case XPATH_OP_END:
12897             return (0);
12898         case XPATH_OP_UNION:
12899             bakd = ctxt->context->doc;
12900             bak = ctxt->context->node;
12901             pp = ctxt->context->proximityPosition;
12902             cs = ctxt->context->contextSize;
12903             total =
12904                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12905             CHECK_ERROR0;
12906             if ((ctxt->value != NULL)
12907                 && (ctxt->value->type == XPATH_NODESET)
12908                 && (ctxt->value->nodesetval != NULL)
12909                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12910                 /*
12911                  * limit tree traversing to first node in the result
12912                  */
12913                 if (ctxt->value->nodesetval->nodeNr > 1)
12914                     xmlXPathNodeSetSort(ctxt->value->nodesetval);
12915                 *last =
12916                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12917                                                      nodesetval->nodeNr -
12918                                                      1];
12919             }
12920             ctxt->context->doc = bakd;
12921             ctxt->context->node = bak;
12922             ctxt->context->proximityPosition = pp;
12923             ctxt->context->contextSize = cs;
12924             cur =
12925                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12926             CHECK_ERROR0;
12927             if ((ctxt->value != NULL)
12928                 && (ctxt->value->type == XPATH_NODESET)
12929                 && (ctxt->value->nodesetval != NULL)
12930                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12931             }
12932
12933             arg2 = valuePop(ctxt);
12934             arg1 = valuePop(ctxt);
12935             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12936                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12937                 xmlXPathReleaseObject(ctxt->context, arg1);
12938                 xmlXPathReleaseObject(ctxt->context, arg2);
12939                 XP_ERROR0(XPATH_INVALID_TYPE);
12940             }
12941
12942             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12943                                                     arg2->nodesetval);
12944             valuePush(ctxt, arg1);
12945             xmlXPathReleaseObject(ctxt->context, arg2);
12946             /* optimizer */
12947             if (total > cur)
12948                 xmlXPathCompSwap(op);
12949             return (total + cur);
12950         case XPATH_OP_ROOT:
12951             xmlXPathRoot(ctxt);
12952             return (0);
12953         case XPATH_OP_NODE:
12954             if (op->ch1 != -1)
12955                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12956             CHECK_ERROR0;
12957             if (op->ch2 != -1)
12958                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12959             CHECK_ERROR0;
12960             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12961                 ctxt->context->node));
12962             return (total);
12963         case XPATH_OP_RESET:
12964             if (op->ch1 != -1)
12965                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12966             CHECK_ERROR0;
12967             if (op->ch2 != -1)
12968                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12969             CHECK_ERROR0;
12970             ctxt->context->node = NULL;
12971             return (total);
12972         case XPATH_OP_COLLECT:{
12973                 if (op->ch1 == -1)
12974                     return (0);
12975
12976                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12977                 CHECK_ERROR0;
12978
12979                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12980                 return (total);
12981             }
12982         case XPATH_OP_VALUE:
12983             valuePush(ctxt,
12984                       xmlXPathCacheObjectCopy(ctxt->context,
12985                         (xmlXPathObjectPtr) op->value4));
12986             return (0);
12987         case XPATH_OP_SORT:
12988             if (op->ch1 != -1)
12989                 total +=
12990                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12991                                            last);
12992             CHECK_ERROR0;
12993             if ((ctxt->value != NULL)
12994                 && (ctxt->value->type == XPATH_NODESET)
12995                 && (ctxt->value->nodesetval != NULL)
12996                 && (ctxt->value->nodesetval->nodeNr > 1))
12997                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12998             return (total);
12999         default:
13000             return (xmlXPathCompOpEval(ctxt, op));
13001     }
13002 }
13003
13004 #ifdef XP_OPTIMIZED_FILTER_FIRST
13005 static int
13006 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
13007                               xmlXPathStepOpPtr op, xmlNodePtr * first)
13008 {
13009     int total = 0;
13010     xmlXPathCompExprPtr comp;
13011     xmlXPathObjectPtr res;
13012     xmlXPathObjectPtr obj;
13013     xmlNodeSetPtr oldset;
13014     xmlNodePtr oldnode;
13015     xmlDocPtr oldDoc;
13016     int i;
13017
13018     CHECK_ERROR0;
13019     comp = ctxt->comp;
13020     /*
13021     * Optimization for ()[last()] selection i.e. the last elem
13022     */
13023     if ((op->ch1 != -1) && (op->ch2 != -1) &&
13024         (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13025         (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13026         int f = comp->steps[op->ch2].ch1;
13027
13028         if ((f != -1) &&
13029             (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13030             (comp->steps[f].value5 == NULL) &&
13031             (comp->steps[f].value == 0) &&
13032             (comp->steps[f].value4 != NULL) &&
13033             (xmlStrEqual
13034             (comp->steps[f].value4, BAD_CAST "last"))) {
13035             xmlNodePtr last = NULL;
13036
13037             total +=
13038                 xmlXPathCompOpEvalLast(ctxt,
13039                     &comp->steps[op->ch1],
13040                     &last);
13041             CHECK_ERROR0;
13042             /*
13043             * The nodeset should be in document order,
13044             * Keep only the last value
13045             */
13046             if ((ctxt->value != NULL) &&
13047                 (ctxt->value->type == XPATH_NODESET) &&
13048                 (ctxt->value->nodesetval != NULL) &&
13049                 (ctxt->value->nodesetval->nodeTab != NULL) &&
13050                 (ctxt->value->nodesetval->nodeNr > 1)) {
13051                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13052                 *first = *(ctxt->value->nodesetval->nodeTab);
13053             }
13054             return (total);
13055         }
13056     }
13057
13058     if (op->ch1 != -1)
13059         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13060     CHECK_ERROR0;
13061     if (op->ch2 == -1)
13062         return (total);
13063     if (ctxt->value == NULL)
13064         return (total);
13065
13066 #ifdef LIBXML_XPTR_ENABLED
13067     oldnode = ctxt->context->node;
13068     /*
13069     * Hum are we filtering the result of an XPointer expression
13070     */
13071     if (ctxt->value->type == XPATH_LOCATIONSET) {
13072         xmlXPathObjectPtr tmp = NULL;
13073         xmlLocationSetPtr newlocset = NULL;
13074         xmlLocationSetPtr oldlocset;
13075
13076         /*
13077         * Extract the old locset, and then evaluate the result of the
13078         * expression for all the element in the locset. use it to grow
13079         * up a new locset.
13080         */
13081         CHECK_TYPE0(XPATH_LOCATIONSET);
13082         obj = valuePop(ctxt);
13083         oldlocset = obj->user;
13084         ctxt->context->node = NULL;
13085
13086         if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13087             ctxt->context->contextSize = 0;
13088             ctxt->context->proximityPosition = 0;
13089             if (op->ch2 != -1)
13090                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13091             res = valuePop(ctxt);
13092             if (res != NULL) {
13093                 xmlXPathReleaseObject(ctxt->context, res);
13094             }
13095             valuePush(ctxt, obj);
13096             CHECK_ERROR0;
13097             return (total);
13098         }
13099         newlocset = xmlXPtrLocationSetCreate(NULL);
13100
13101         for (i = 0; i < oldlocset->locNr; i++) {
13102             /*
13103             * Run the evaluation with a node list made of a
13104             * single item in the nodelocset.
13105             */
13106             ctxt->context->node = oldlocset->locTab[i]->user;
13107             ctxt->context->contextSize = oldlocset->locNr;
13108             ctxt->context->proximityPosition = i + 1;
13109             if (tmp == NULL) {
13110                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13111                     ctxt->context->node);
13112             } else {
13113                 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13114                                              ctxt->context->node) < 0) {
13115                     ctxt->error = XPATH_MEMORY_ERROR;
13116                 }
13117             }
13118             valuePush(ctxt, tmp);
13119             if (op->ch2 != -1)
13120                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13121             if (ctxt->error != XPATH_EXPRESSION_OK) {
13122                 xmlXPathFreeObject(obj);
13123                 return(0);
13124             }
13125             /*
13126             * The result of the evaluation need to be tested to
13127             * decided whether the filter succeeded or not
13128             */
13129             res = valuePop(ctxt);
13130             if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13131                 xmlXPtrLocationSetAdd(newlocset,
13132                     xmlXPathCacheObjectCopy(ctxt->context,
13133                         oldlocset->locTab[i]));
13134             }
13135             /*
13136             * Cleanup
13137             */
13138             if (res != NULL) {
13139                 xmlXPathReleaseObject(ctxt->context, res);
13140             }
13141             if (ctxt->value == tmp) {
13142                 valuePop(ctxt);
13143                 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13144                 /*
13145                 * REVISIT TODO: Don't create a temporary nodeset
13146                 * for everly iteration.
13147                 */
13148                 /* OLD: xmlXPathFreeObject(res); */
13149             } else
13150                 tmp = NULL;
13151             ctxt->context->node = NULL;
13152             /*
13153             * Only put the first node in the result, then leave.
13154             */
13155             if (newlocset->locNr > 0) {
13156                 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13157                 break;
13158             }
13159         }
13160         if (tmp != NULL) {
13161             xmlXPathReleaseObject(ctxt->context, tmp);
13162         }
13163         /*
13164         * The result is used as the new evaluation locset.
13165         */
13166         xmlXPathReleaseObject(ctxt->context, obj);
13167         ctxt->context->node = NULL;
13168         ctxt->context->contextSize = -1;
13169         ctxt->context->proximityPosition = -1;
13170         valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13171         ctxt->context->node = oldnode;
13172         return (total);
13173     }
13174 #endif /* LIBXML_XPTR_ENABLED */
13175
13176     /*
13177     * Extract the old set, and then evaluate the result of the
13178     * expression for all the element in the set. use it to grow
13179     * up a new set.
13180     */
13181     CHECK_TYPE0(XPATH_NODESET);
13182     obj = valuePop(ctxt);
13183     oldset = obj->nodesetval;
13184
13185     oldnode = ctxt->context->node;
13186     oldDoc = ctxt->context->doc;
13187     ctxt->context->node = NULL;
13188
13189     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13190         ctxt->context->contextSize = 0;
13191         ctxt->context->proximityPosition = 0;
13192         /* QUESTION TODO: Why was this code commented out?
13193             if (op->ch2 != -1)
13194                 total +=
13195                     xmlXPathCompOpEval(ctxt,
13196                         &comp->steps[op->ch2]);
13197             CHECK_ERROR0;
13198             res = valuePop(ctxt);
13199             if (res != NULL)
13200                 xmlXPathFreeObject(res);
13201         */
13202         valuePush(ctxt, obj);
13203         ctxt->context->node = oldnode;
13204         CHECK_ERROR0;
13205     } else {
13206         xmlNodeSetPtr newset;
13207         xmlXPathObjectPtr tmp = NULL;
13208         /*
13209         * Initialize the new set.
13210         * Also set the xpath document in case things like
13211         * key() evaluation are attempted on the predicate
13212         */
13213         newset = xmlXPathNodeSetCreate(NULL);
13214         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13215
13216         for (i = 0; i < oldset->nodeNr; i++) {
13217             /*
13218             * Run the evaluation with a node list made of
13219             * a single item in the nodeset.
13220             */
13221             ctxt->context->node = oldset->nodeTab[i];
13222             if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13223                 (oldset->nodeTab[i]->doc != NULL))
13224                 ctxt->context->doc = oldset->nodeTab[i]->doc;
13225             if (tmp == NULL) {
13226                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13227                     ctxt->context->node);
13228             } else {
13229                 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13230                                              ctxt->context->node) < 0) {
13231                     ctxt->error = XPATH_MEMORY_ERROR;
13232                 }
13233             }
13234             valuePush(ctxt, tmp);
13235             ctxt->context->contextSize = oldset->nodeNr;
13236             ctxt->context->proximityPosition = i + 1;
13237             if (op->ch2 != -1)
13238                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13239             if (ctxt->error != XPATH_EXPRESSION_OK) {
13240                 xmlXPathFreeNodeSet(newset);
13241                 xmlXPathFreeObject(obj);
13242                 return(0);
13243             }
13244             /*
13245             * The result of the evaluation needs to be tested to
13246             * decide whether the filter succeeded or not
13247             */
13248             res = valuePop(ctxt);
13249             if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13250                 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13251                     ctxt->error = XPATH_MEMORY_ERROR;
13252             }
13253             /*
13254             * Cleanup
13255             */
13256             if (res != NULL) {
13257                 xmlXPathReleaseObject(ctxt->context, res);
13258             }
13259             if (ctxt->value == tmp) {
13260                 valuePop(ctxt);
13261                 /*
13262                 * Don't free the temporary nodeset
13263                 * in order to avoid massive recreation inside this
13264                 * loop.
13265                 */
13266                 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13267             } else
13268                 tmp = NULL;
13269             ctxt->context->node = NULL;
13270             /*
13271             * Only put the first node in the result, then leave.
13272             */
13273             if (newset->nodeNr > 0) {
13274                 *first = *(newset->nodeTab);
13275                 break;
13276             }
13277         }
13278         if (tmp != NULL) {
13279             xmlXPathReleaseObject(ctxt->context, tmp);
13280         }
13281         /*
13282         * The result is used as the new evaluation set.
13283         */
13284         xmlXPathReleaseObject(ctxt->context, obj);
13285         ctxt->context->node = NULL;
13286         ctxt->context->contextSize = -1;
13287         ctxt->context->proximityPosition = -1;
13288         /* may want to move this past the '}' later */
13289         ctxt->context->doc = oldDoc;
13290         valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13291     }
13292     ctxt->context->node = oldnode;
13293     return(total);
13294 }
13295 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13296
13297 /**
13298  * xmlXPathCompOpEval:
13299  * @ctxt:  the XPath parser context with the compiled expression
13300  * @op:  an XPath compiled operation
13301  *
13302  * Evaluate the Precompiled XPath operation
13303  * Returns the number of nodes traversed
13304  */
13305 static int
13306 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13307 {
13308     int total = 0;
13309     int equal, ret;
13310     xmlXPathCompExprPtr comp;
13311     xmlXPathObjectPtr arg1, arg2;
13312     xmlNodePtr bak;
13313     xmlDocPtr bakd;
13314     int pp;
13315     int cs;
13316
13317     CHECK_ERROR0;
13318     comp = ctxt->comp;
13319     switch (op->op) {
13320         case XPATH_OP_END:
13321             return (0);
13322         case XPATH_OP_AND:
13323             bakd = ctxt->context->doc;
13324             bak = ctxt->context->node;
13325             pp = ctxt->context->proximityPosition;
13326             cs = ctxt->context->contextSize;
13327             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13328             CHECK_ERROR0;
13329             xmlXPathBooleanFunction(ctxt, 1);
13330             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13331                 return (total);
13332             arg2 = valuePop(ctxt);
13333             ctxt->context->doc = bakd;
13334             ctxt->context->node = bak;
13335             ctxt->context->proximityPosition = pp;
13336             ctxt->context->contextSize = cs;
13337             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13338             if (ctxt->error) {
13339                 xmlXPathFreeObject(arg2);
13340                 return(0);
13341             }
13342             xmlXPathBooleanFunction(ctxt, 1);
13343             arg1 = valuePop(ctxt);
13344             arg1->boolval &= arg2->boolval;
13345             valuePush(ctxt, arg1);
13346             xmlXPathReleaseObject(ctxt->context, arg2);
13347             return (total);
13348         case XPATH_OP_OR:
13349             bakd = ctxt->context->doc;
13350             bak = ctxt->context->node;
13351             pp = ctxt->context->proximityPosition;
13352             cs = ctxt->context->contextSize;
13353             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13354             CHECK_ERROR0;
13355             xmlXPathBooleanFunction(ctxt, 1);
13356             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13357                 return (total);
13358             arg2 = valuePop(ctxt);
13359             ctxt->context->doc = bakd;
13360             ctxt->context->node = bak;
13361             ctxt->context->proximityPosition = pp;
13362             ctxt->context->contextSize = cs;
13363             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13364             if (ctxt->error) {
13365                 xmlXPathFreeObject(arg2);
13366                 return(0);
13367             }
13368             xmlXPathBooleanFunction(ctxt, 1);
13369             arg1 = valuePop(ctxt);
13370             arg1->boolval |= arg2->boolval;
13371             valuePush(ctxt, arg1);
13372             xmlXPathReleaseObject(ctxt->context, arg2);
13373             return (total);
13374         case XPATH_OP_EQUAL:
13375             bakd = ctxt->context->doc;
13376             bak = ctxt->context->node;
13377             pp = ctxt->context->proximityPosition;
13378             cs = ctxt->context->contextSize;
13379             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13380             CHECK_ERROR0;
13381             ctxt->context->doc = bakd;
13382             ctxt->context->node = bak;
13383             ctxt->context->proximityPosition = pp;
13384             ctxt->context->contextSize = cs;
13385             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13386             CHECK_ERROR0;
13387             if (op->value)
13388                 equal = xmlXPathEqualValues(ctxt);
13389             else
13390                 equal = xmlXPathNotEqualValues(ctxt);
13391             valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13392             return (total);
13393         case XPATH_OP_CMP:
13394             bakd = ctxt->context->doc;
13395             bak = ctxt->context->node;
13396             pp = ctxt->context->proximityPosition;
13397             cs = ctxt->context->contextSize;
13398             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13399             CHECK_ERROR0;
13400             ctxt->context->doc = bakd;
13401             ctxt->context->node = bak;
13402             ctxt->context->proximityPosition = pp;
13403             ctxt->context->contextSize = cs;
13404             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13405             CHECK_ERROR0;
13406             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13407             valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13408             return (total);
13409         case XPATH_OP_PLUS:
13410             bakd = ctxt->context->doc;
13411             bak = ctxt->context->node;
13412             pp = ctxt->context->proximityPosition;
13413             cs = ctxt->context->contextSize;
13414             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13415             CHECK_ERROR0;
13416             if (op->ch2 != -1) {
13417                 ctxt->context->doc = bakd;
13418                 ctxt->context->node = bak;
13419                 ctxt->context->proximityPosition = pp;
13420                 ctxt->context->contextSize = cs;
13421                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13422             }
13423             CHECK_ERROR0;
13424             if (op->value == 0)
13425                 xmlXPathSubValues(ctxt);
13426             else if (op->value == 1)
13427                 xmlXPathAddValues(ctxt);
13428             else if (op->value == 2)
13429                 xmlXPathValueFlipSign(ctxt);
13430             else if (op->value == 3) {
13431                 CAST_TO_NUMBER;
13432                 CHECK_TYPE0(XPATH_NUMBER);
13433             }
13434             return (total);
13435         case XPATH_OP_MULT:
13436             bakd = ctxt->context->doc;
13437             bak = ctxt->context->node;
13438             pp = ctxt->context->proximityPosition;
13439             cs = ctxt->context->contextSize;
13440             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13441             CHECK_ERROR0;
13442             ctxt->context->doc = bakd;
13443             ctxt->context->node = bak;
13444             ctxt->context->proximityPosition = pp;
13445             ctxt->context->contextSize = cs;
13446             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13447             CHECK_ERROR0;
13448             if (op->value == 0)
13449                 xmlXPathMultValues(ctxt);
13450             else if (op->value == 1)
13451                 xmlXPathDivValues(ctxt);
13452             else if (op->value == 2)
13453                 xmlXPathModValues(ctxt);
13454             return (total);
13455         case XPATH_OP_UNION:
13456             bakd = ctxt->context->doc;
13457             bak = ctxt->context->node;
13458             pp = ctxt->context->proximityPosition;
13459             cs = ctxt->context->contextSize;
13460             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13461             CHECK_ERROR0;
13462             ctxt->context->doc = bakd;
13463             ctxt->context->node = bak;
13464             ctxt->context->proximityPosition = pp;
13465             ctxt->context->contextSize = cs;
13466             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13467             CHECK_ERROR0;
13468
13469             arg2 = valuePop(ctxt);
13470             arg1 = valuePop(ctxt);
13471             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13472                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13473                 xmlXPathReleaseObject(ctxt->context, arg1);
13474                 xmlXPathReleaseObject(ctxt->context, arg2);
13475                 XP_ERROR0(XPATH_INVALID_TYPE);
13476             }
13477
13478             if ((arg1->nodesetval == NULL) ||
13479                 ((arg2->nodesetval != NULL) &&
13480                  (arg2->nodesetval->nodeNr != 0)))
13481             {
13482                 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13483                                                         arg2->nodesetval);
13484             }
13485
13486             valuePush(ctxt, arg1);
13487             xmlXPathReleaseObject(ctxt->context, arg2);
13488             return (total);
13489         case XPATH_OP_ROOT:
13490             xmlXPathRoot(ctxt);
13491             return (total);
13492         case XPATH_OP_NODE:
13493             if (op->ch1 != -1)
13494                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13495             CHECK_ERROR0;
13496             if (op->ch2 != -1)
13497                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13498             CHECK_ERROR0;
13499             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13500                 ctxt->context->node));
13501             return (total);
13502         case XPATH_OP_RESET:
13503             if (op->ch1 != -1)
13504                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13505             CHECK_ERROR0;
13506             if (op->ch2 != -1)
13507                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13508             CHECK_ERROR0;
13509             ctxt->context->node = NULL;
13510             return (total);
13511         case XPATH_OP_COLLECT:{
13512                 if (op->ch1 == -1)
13513                     return (total);
13514
13515                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13516                 CHECK_ERROR0;
13517
13518                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13519                 return (total);
13520             }
13521         case XPATH_OP_VALUE:
13522             valuePush(ctxt,
13523                       xmlXPathCacheObjectCopy(ctxt->context,
13524                         (xmlXPathObjectPtr) op->value4));
13525             return (total);
13526         case XPATH_OP_VARIABLE:{
13527                 xmlXPathObjectPtr val;
13528
13529                 if (op->ch1 != -1)
13530                     total +=
13531                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13532                 if (op->value5 == NULL) {
13533                     val = xmlXPathVariableLookup(ctxt->context, op->value4);
13534                     if (val == NULL)
13535                         XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13536                     valuePush(ctxt, val);
13537                 } else {
13538                     const xmlChar *URI;
13539
13540                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13541                     if (URI == NULL) {
13542                         xmlGenericError(xmlGenericErrorContext,
13543             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13544                                     (char *) op->value4, (char *)op->value5);
13545                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13546                         return (total);
13547                     }
13548                     val = xmlXPathVariableLookupNS(ctxt->context,
13549                                                        op->value4, URI);
13550                     if (val == NULL)
13551                         XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13552                     valuePush(ctxt, val);
13553                 }
13554                 return (total);
13555             }
13556         case XPATH_OP_FUNCTION:{
13557                 xmlXPathFunction func;
13558                 const xmlChar *oldFunc, *oldFuncURI;
13559                 int i;
13560                 int frame;
13561
13562                 frame = xmlXPathSetFrame(ctxt);
13563                 if (op->ch1 != -1) {
13564                     total +=
13565                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13566                     if (ctxt->error != XPATH_EXPRESSION_OK) {
13567                         xmlXPathPopFrame(ctxt, frame);
13568                         return (total);
13569                     }
13570                 }
13571                 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13572                     xmlGenericError(xmlGenericErrorContext,
13573                             "xmlXPathCompOpEval: parameter error\n");
13574                     ctxt->error = XPATH_INVALID_OPERAND;
13575                     xmlXPathPopFrame(ctxt, frame);
13576                     return (total);
13577                 }
13578                 for (i = 0; i < op->value; i++) {
13579                     if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13580                         xmlGenericError(xmlGenericErrorContext,
13581                                 "xmlXPathCompOpEval: parameter error\n");
13582                         ctxt->error = XPATH_INVALID_OPERAND;
13583                         xmlXPathPopFrame(ctxt, frame);
13584                         return (total);
13585                     }
13586                 }
13587                 if (op->cache != NULL)
13588                     func = op->cache;
13589                 else {
13590                     const xmlChar *URI = NULL;
13591
13592                     if (op->value5 == NULL)
13593                         func =
13594                             xmlXPathFunctionLookup(ctxt->context,
13595                                                    op->value4);
13596                     else {
13597                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13598                         if (URI == NULL) {
13599                             xmlGenericError(xmlGenericErrorContext,
13600             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13601                                     (char *)op->value4, (char *)op->value5);
13602                             xmlXPathPopFrame(ctxt, frame);
13603                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13604                             return (total);
13605                         }
13606                         func = xmlXPathFunctionLookupNS(ctxt->context,
13607                                                         op->value4, URI);
13608                     }
13609                     if (func == NULL) {
13610                         xmlGenericError(xmlGenericErrorContext,
13611                                 "xmlXPathCompOpEval: function %s not found\n",
13612                                         (char *)op->value4);
13613                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13614                     }
13615                     op->cache = func;
13616                     op->cacheURI = (void *) URI;
13617                 }
13618                 oldFunc = ctxt->context->function;
13619                 oldFuncURI = ctxt->context->functionURI;
13620                 ctxt->context->function = op->value4;
13621                 ctxt->context->functionURI = op->cacheURI;
13622                 func(ctxt, op->value);
13623                 ctxt->context->function = oldFunc;
13624                 ctxt->context->functionURI = oldFuncURI;
13625                 xmlXPathPopFrame(ctxt, frame);
13626                 return (total);
13627             }
13628         case XPATH_OP_ARG:
13629             bakd = ctxt->context->doc;
13630             bak = ctxt->context->node;
13631             pp = ctxt->context->proximityPosition;
13632             cs = ctxt->context->contextSize;
13633             if (op->ch1 != -1) {
13634                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13635                 ctxt->context->contextSize = cs;
13636                 ctxt->context->proximityPosition = pp;
13637                 ctxt->context->node = bak;
13638                 ctxt->context->doc = bakd;
13639                 CHECK_ERROR0;
13640             }
13641             if (op->ch2 != -1) {
13642                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13643                 ctxt->context->contextSize = cs;
13644                 ctxt->context->proximityPosition = pp;
13645                 ctxt->context->node = bak;
13646                 ctxt->context->doc = bakd;
13647                 CHECK_ERROR0;
13648             }
13649             return (total);
13650         case XPATH_OP_PREDICATE:
13651         case XPATH_OP_FILTER:{
13652                 xmlXPathObjectPtr res;
13653                 xmlXPathObjectPtr obj, tmp;
13654                 xmlNodeSetPtr newset = NULL;
13655                 xmlNodeSetPtr oldset;
13656                 xmlNodePtr oldnode;
13657                 xmlDocPtr oldDoc;
13658                 int i;
13659
13660                 /*
13661                  * Optimization for ()[1] selection i.e. the first elem
13662                  */
13663                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13664 #ifdef XP_OPTIMIZED_FILTER_FIRST
13665                     /*
13666                     * FILTER TODO: Can we assume that the inner processing
13667                     *  will result in an ordered list if we have an
13668                     *  XPATH_OP_FILTER?
13669                     *  What about an additional field or flag on
13670                     *  xmlXPathObject like @sorted ? This way we wouln'd need
13671                     *  to assume anything, so it would be more robust and
13672                     *  easier to optimize.
13673                     */
13674                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13675                      (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13676 #else
13677                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13678 #endif
13679                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13680                     xmlXPathObjectPtr val;
13681
13682                     val = comp->steps[op->ch2].value4;
13683                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13684                         (val->floatval == 1.0)) {
13685                         xmlNodePtr first = NULL;
13686
13687                         total +=
13688                             xmlXPathCompOpEvalFirst(ctxt,
13689                                                     &comp->steps[op->ch1],
13690                                                     &first);
13691                         CHECK_ERROR0;
13692                         /*
13693                          * The nodeset should be in document order,
13694                          * Keep only the first value
13695                          */
13696                         if ((ctxt->value != NULL) &&
13697                             (ctxt->value->type == XPATH_NODESET) &&
13698                             (ctxt->value->nodesetval != NULL) &&
13699                             (ctxt->value->nodesetval->nodeNr > 1))
13700                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13701                                                         1, 1);
13702                         return (total);
13703                     }
13704                 }
13705                 /*
13706                  * Optimization for ()[last()] selection i.e. the last elem
13707                  */
13708                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13709                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13710                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13711                     int f = comp->steps[op->ch2].ch1;
13712
13713                     if ((f != -1) &&
13714                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13715                         (comp->steps[f].value5 == NULL) &&
13716                         (comp->steps[f].value == 0) &&
13717                         (comp->steps[f].value4 != NULL) &&
13718                         (xmlStrEqual
13719                          (comp->steps[f].value4, BAD_CAST "last"))) {
13720                         xmlNodePtr last = NULL;
13721
13722                         total +=
13723                             xmlXPathCompOpEvalLast(ctxt,
13724                                                    &comp->steps[op->ch1],
13725                                                    &last);
13726                         CHECK_ERROR0;
13727                         /*
13728                          * The nodeset should be in document order,
13729                          * Keep only the last value
13730                          */
13731                         if ((ctxt->value != NULL) &&
13732                             (ctxt->value->type == XPATH_NODESET) &&
13733                             (ctxt->value->nodesetval != NULL) &&
13734                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13735                             (ctxt->value->nodesetval->nodeNr > 1))
13736                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13737                         return (total);
13738                     }
13739                 }
13740                 /*
13741                 * Process inner predicates first.
13742                 * Example "index[parent::book][1]":
13743                 * ...
13744                 *   PREDICATE   <-- we are here "[1]"
13745                 *     PREDICATE <-- process "[parent::book]" first
13746                 *       SORT
13747                 *         COLLECT  'parent' 'name' 'node' book
13748                 *           NODE
13749                 *     ELEM Object is a number : 1
13750                 */
13751                 if (op->ch1 != -1)
13752                     total +=
13753                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13754                 CHECK_ERROR0;
13755                 if (op->ch2 == -1)
13756                     return (total);
13757                 if (ctxt->value == NULL)
13758                     return (total);
13759
13760                 oldnode = ctxt->context->node;
13761
13762 #ifdef LIBXML_XPTR_ENABLED
13763                 /*
13764                  * Hum are we filtering the result of an XPointer expression
13765                  */
13766                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13767                     xmlLocationSetPtr newlocset = NULL;
13768                     xmlLocationSetPtr oldlocset;
13769
13770                     /*
13771                      * Extract the old locset, and then evaluate the result of the
13772                      * expression for all the element in the locset. use it to grow
13773                      * up a new locset.
13774                      */
13775                     CHECK_TYPE0(XPATH_LOCATIONSET);
13776                     obj = valuePop(ctxt);
13777                     oldlocset = obj->user;
13778                     ctxt->context->node = NULL;
13779
13780                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13781                         ctxt->context->contextSize = 0;
13782                         ctxt->context->proximityPosition = 0;
13783                         if (op->ch2 != -1)
13784                             total +=
13785                                 xmlXPathCompOpEval(ctxt,
13786                                                    &comp->steps[op->ch2]);
13787                         res = valuePop(ctxt);
13788                         if (res != NULL) {
13789                             xmlXPathReleaseObject(ctxt->context, res);
13790                         }
13791                         valuePush(ctxt, obj);
13792                         CHECK_ERROR0;
13793                         return (total);
13794                     }
13795                     newlocset = xmlXPtrLocationSetCreate(NULL);
13796
13797                     for (i = 0; i < oldlocset->locNr; i++) {
13798                         /*
13799                          * Run the evaluation with a node list made of a
13800                          * single item in the nodelocset.
13801                          */
13802                         ctxt->context->node = oldlocset->locTab[i]->user;
13803                         ctxt->context->contextSize = oldlocset->locNr;
13804                         ctxt->context->proximityPosition = i + 1;
13805                         tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13806                             ctxt->context->node);
13807                         valuePush(ctxt, tmp);
13808
13809                         if (op->ch2 != -1)
13810                             total +=
13811                                 xmlXPathCompOpEval(ctxt,
13812                                                    &comp->steps[op->ch2]);
13813                         if (ctxt->error != XPATH_EXPRESSION_OK) {
13814                             xmlXPathFreeObject(obj);
13815                             return(0);
13816                         }
13817
13818                         /*
13819                          * The result of the evaluation need to be tested to
13820                          * decided whether the filter succeeded or not
13821                          */
13822                         res = valuePop(ctxt);
13823                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13824                             xmlXPtrLocationSetAdd(newlocset,
13825                                                   xmlXPathObjectCopy
13826                                                   (oldlocset->locTab[i]));
13827                         }
13828
13829                         /*
13830                          * Cleanup
13831                          */
13832                         if (res != NULL) {
13833                             xmlXPathReleaseObject(ctxt->context, res);
13834                         }
13835                         if (ctxt->value == tmp) {
13836                             res = valuePop(ctxt);
13837                             xmlXPathReleaseObject(ctxt->context, res);
13838                         }
13839
13840                         ctxt->context->node = NULL;
13841                     }
13842
13843                     /*
13844                      * The result is used as the new evaluation locset.
13845                      */
13846                     xmlXPathReleaseObject(ctxt->context, obj);
13847                     ctxt->context->node = NULL;
13848                     ctxt->context->contextSize = -1;
13849                     ctxt->context->proximityPosition = -1;
13850                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13851                     ctxt->context->node = oldnode;
13852                     return (total);
13853                 }
13854 #endif /* LIBXML_XPTR_ENABLED */
13855
13856                 /*
13857                  * Extract the old set, and then evaluate the result of the
13858                  * expression for all the element in the set. use it to grow
13859                  * up a new set.
13860                  */
13861                 CHECK_TYPE0(XPATH_NODESET);
13862                 obj = valuePop(ctxt);
13863                 oldset = obj->nodesetval;
13864
13865                 oldnode = ctxt->context->node;
13866                 oldDoc = ctxt->context->doc;
13867                 ctxt->context->node = NULL;
13868
13869                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13870                     ctxt->context->contextSize = 0;
13871                     ctxt->context->proximityPosition = 0;
13872 /*
13873                     if (op->ch2 != -1)
13874                         total +=
13875                             xmlXPathCompOpEval(ctxt,
13876                                                &comp->steps[op->ch2]);
13877                     CHECK_ERROR0;
13878                     res = valuePop(ctxt);
13879                     if (res != NULL)
13880                         xmlXPathFreeObject(res);
13881 */
13882                     valuePush(ctxt, obj);
13883                     ctxt->context->node = oldnode;
13884                     CHECK_ERROR0;
13885                 } else {
13886                     tmp = NULL;
13887                     /*
13888                      * Initialize the new set.
13889                      * Also set the xpath document in case things like
13890                      * key() evaluation are attempted on the predicate
13891                      */
13892                     newset = xmlXPathNodeSetCreate(NULL);
13893                     /*
13894                     * SPEC XPath 1.0:
13895                     *  "For each node in the node-set to be filtered, the
13896                     *  PredicateExpr is evaluated with that node as the
13897                     *  context node, with the number of nodes in the
13898                     *  node-set as the context size, and with the proximity
13899                     *  position of the node in the node-set with respect to
13900                     *  the axis as the context position;"
13901                     * @oldset is the node-set" to be filtered.
13902                     *
13903                     * SPEC XPath 1.0:
13904                     *  "only predicates change the context position and
13905                     *  context size (see [2.4 Predicates])."
13906                     * Example:
13907                     *   node-set  context pos
13908                     *    nA         1
13909                     *    nB         2
13910                     *    nC         3
13911                     *   After applying predicate [position() > 1] :
13912                     *   node-set  context pos
13913                     *    nB         1
13914                     *    nC         2
13915                     *
13916                     * removed the first node in the node-set, then
13917                     * the context position of the
13918                     */
13919                     for (i = 0; i < oldset->nodeNr; i++) {
13920                         /*
13921                          * Run the evaluation with a node list made of
13922                          * a single item in the nodeset.
13923                          */
13924                         ctxt->context->node = oldset->nodeTab[i];
13925                         if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13926                             (oldset->nodeTab[i]->doc != NULL))
13927                             ctxt->context->doc = oldset->nodeTab[i]->doc;
13928                         if (tmp == NULL) {
13929                             tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13930                                 ctxt->context->node);
13931                         } else {
13932                             if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13933                                                ctxt->context->node) < 0) {
13934                                 ctxt->error = XPATH_MEMORY_ERROR;
13935                             }
13936                         }
13937                         valuePush(ctxt, tmp);
13938                         ctxt->context->contextSize = oldset->nodeNr;
13939                         ctxt->context->proximityPosition = i + 1;
13940                         /*
13941                         * Evaluate the predicate against the context node.
13942                         * Can/should we optimize position() predicates
13943                         * here (e.g. "[1]")?
13944                         */
13945                         if (op->ch2 != -1)
13946                             total +=
13947                                 xmlXPathCompOpEval(ctxt,
13948                                                    &comp->steps[op->ch2]);
13949                         if (ctxt->error != XPATH_EXPRESSION_OK) {
13950                             xmlXPathFreeNodeSet(newset);
13951                             xmlXPathFreeObject(obj);
13952                             return(0);
13953                         }
13954
13955                         /*
13956                          * The result of the evaluation needs to be tested to
13957                          * decide whether the filter succeeded or not
13958                          */
13959                         /*
13960                         * OPTIMIZE TODO: Can we use
13961                         * xmlXPathNodeSetAdd*Unique()* instead?
13962                         */
13963                         res = valuePop(ctxt);
13964                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13965                             if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13966                                 < 0)
13967                                 ctxt->error = XPATH_MEMORY_ERROR;
13968                         }
13969
13970                         /*
13971                          * Cleanup
13972                          */
13973                         if (res != NULL) {
13974                             xmlXPathReleaseObject(ctxt->context, res);
13975                         }
13976                         if (ctxt->value == tmp) {
13977                             valuePop(ctxt);
13978                             xmlXPathNodeSetClear(tmp->nodesetval, 1);
13979                             /*
13980                             * Don't free the temporary nodeset
13981                             * in order to avoid massive recreation inside this
13982                             * loop.
13983                             */
13984                         } else
13985                             tmp = NULL;
13986                         ctxt->context->node = NULL;
13987                     }
13988                     if (tmp != NULL)
13989                         xmlXPathReleaseObject(ctxt->context, tmp);
13990                     /*
13991                      * The result is used as the new evaluation set.
13992                      */
13993                     xmlXPathReleaseObject(ctxt->context, obj);
13994                     ctxt->context->node = NULL;
13995                     ctxt->context->contextSize = -1;
13996                     ctxt->context->proximityPosition = -1;
13997                     /* may want to move this past the '}' later */
13998                     ctxt->context->doc = oldDoc;
13999                     valuePush(ctxt,
14000                         xmlXPathCacheWrapNodeSet(ctxt->context, newset));
14001                 }
14002                 ctxt->context->node = oldnode;
14003                 return (total);
14004             }
14005         case XPATH_OP_SORT:
14006             if (op->ch1 != -1)
14007                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
14008             CHECK_ERROR0;
14009             if ((ctxt->value != NULL) &&
14010                 (ctxt->value->type == XPATH_NODESET) &&
14011                 (ctxt->value->nodesetval != NULL) &&
14012                 (ctxt->value->nodesetval->nodeNr > 1))
14013             {
14014                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
14015             }
14016             return (total);
14017 #ifdef LIBXML_XPTR_ENABLED
14018         case XPATH_OP_RANGETO:{
14019                 xmlXPathObjectPtr range;
14020                 xmlXPathObjectPtr res, obj;
14021                 xmlXPathObjectPtr tmp;
14022                 xmlLocationSetPtr newlocset = NULL;
14023                     xmlLocationSetPtr oldlocset;
14024                 xmlNodeSetPtr oldset;
14025                 int i, j;
14026
14027                 if (op->ch1 != -1) {
14028                     total +=
14029                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
14030                     CHECK_ERROR0;
14031                 }
14032                 if (ctxt->value == NULL) {
14033                     XP_ERROR0(XPATH_INVALID_OPERAND);
14034                 }
14035                 if (op->ch2 == -1)
14036                     return (total);
14037
14038                 if (ctxt->value->type == XPATH_LOCATIONSET) {
14039                     /*
14040                      * Extract the old locset, and then evaluate the result of the
14041                      * expression for all the element in the locset. use it to grow
14042                      * up a new locset.
14043                      */
14044                     CHECK_TYPE0(XPATH_LOCATIONSET);
14045                     obj = valuePop(ctxt);
14046                     oldlocset = obj->user;
14047
14048                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
14049                         ctxt->context->node = NULL;
14050                         ctxt->context->contextSize = 0;
14051                         ctxt->context->proximityPosition = 0;
14052                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
14053                         res = valuePop(ctxt);
14054                         if (res != NULL) {
14055                             xmlXPathReleaseObject(ctxt->context, res);
14056                         }
14057                         valuePush(ctxt, obj);
14058                         CHECK_ERROR0;
14059                         return (total);
14060                     }
14061                     newlocset = xmlXPtrLocationSetCreate(NULL);
14062
14063                     for (i = 0; i < oldlocset->locNr; i++) {
14064                         /*
14065                          * Run the evaluation with a node list made of a
14066                          * single item in the nodelocset.
14067                          */
14068                         ctxt->context->node = oldlocset->locTab[i]->user;
14069                         ctxt->context->contextSize = oldlocset->locNr;
14070                         ctxt->context->proximityPosition = i + 1;
14071                         tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14072                             ctxt->context->node);
14073                         valuePush(ctxt, tmp);
14074
14075                         if (op->ch2 != -1)
14076                             total +=
14077                                 xmlXPathCompOpEval(ctxt,
14078                                                    &comp->steps[op->ch2]);
14079                         if (ctxt->error != XPATH_EXPRESSION_OK) {
14080                             xmlXPathFreeObject(obj);
14081                             return(0);
14082                         }
14083
14084                         res = valuePop(ctxt);
14085                         if (res->type == XPATH_LOCATIONSET) {
14086                             xmlLocationSetPtr rloc =
14087                                 (xmlLocationSetPtr)res->user;
14088                             for (j=0; j<rloc->locNr; j++) {
14089                                 range = xmlXPtrNewRange(
14090                                   oldlocset->locTab[i]->user,
14091                                   oldlocset->locTab[i]->index,
14092                                   rloc->locTab[j]->user2,
14093                                   rloc->locTab[j]->index2);
14094                                 if (range != NULL) {
14095                                     xmlXPtrLocationSetAdd(newlocset, range);
14096                                 }
14097                             }
14098                         } else {
14099                             range = xmlXPtrNewRangeNodeObject(
14100                                 (xmlNodePtr)oldlocset->locTab[i]->user, res);
14101                             if (range != NULL) {
14102                                 xmlXPtrLocationSetAdd(newlocset,range);
14103                             }
14104                         }
14105
14106                         /*
14107                          * Cleanup
14108                          */
14109                         if (res != NULL) {
14110                             xmlXPathReleaseObject(ctxt->context, res);
14111                         }
14112                         if (ctxt->value == tmp) {
14113                             res = valuePop(ctxt);
14114                             xmlXPathReleaseObject(ctxt->context, res);
14115                         }
14116
14117                         ctxt->context->node = NULL;
14118                     }
14119                 } else {        /* Not a location set */
14120                     CHECK_TYPE0(XPATH_NODESET);
14121                     obj = valuePop(ctxt);
14122                     oldset = obj->nodesetval;
14123                     ctxt->context->node = NULL;
14124
14125                     newlocset = xmlXPtrLocationSetCreate(NULL);
14126
14127                     if (oldset != NULL) {
14128                         for (i = 0; i < oldset->nodeNr; i++) {
14129                             /*
14130                              * Run the evaluation with a node list made of a single item
14131                              * in the nodeset.
14132                              */
14133                             ctxt->context->node = oldset->nodeTab[i];
14134                             /*
14135                             * OPTIMIZE TODO: Avoid recreation for every iteration.
14136                             */
14137                             tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14138                                 ctxt->context->node);
14139                             valuePush(ctxt, tmp);
14140
14141                             if (op->ch2 != -1)
14142                                 total +=
14143                                     xmlXPathCompOpEval(ctxt,
14144                                                    &comp->steps[op->ch2]);
14145                             if (ctxt->error != XPATH_EXPRESSION_OK) {
14146                                 xmlXPathFreeObject(obj);
14147                                 return(0);
14148                             }
14149
14150                             res = valuePop(ctxt);
14151                             range =
14152                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14153                                                       res);
14154                             if (range != NULL) {
14155                                 xmlXPtrLocationSetAdd(newlocset, range);
14156                             }
14157
14158                             /*
14159                              * Cleanup
14160                              */
14161                             if (res != NULL) {
14162                                 xmlXPathReleaseObject(ctxt->context, res);
14163                             }
14164                             if (ctxt->value == tmp) {
14165                                 res = valuePop(ctxt);
14166                                 xmlXPathReleaseObject(ctxt->context, res);
14167                             }
14168
14169                             ctxt->context->node = NULL;
14170                         }
14171                     }
14172                 }
14173
14174                 /*
14175                  * The result is used as the new evaluation set.
14176                  */
14177                 xmlXPathReleaseObject(ctxt->context, obj);
14178                 ctxt->context->node = NULL;
14179                 ctxt->context->contextSize = -1;
14180                 ctxt->context->proximityPosition = -1;
14181                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14182                 return (total);
14183             }
14184 #endif /* LIBXML_XPTR_ENABLED */
14185     }
14186     xmlGenericError(xmlGenericErrorContext,
14187                     "XPath: unknown precompiled operation %d\n", op->op);
14188     ctxt->error = XPATH_INVALID_OPERAND;
14189     return (total);
14190 }
14191
14192 /**
14193  * xmlXPathCompOpEvalToBoolean:
14194  * @ctxt:  the XPath parser context
14195  *
14196  * Evaluates if the expression evaluates to true.
14197  *
14198  * Returns 1 if true, 0 if false and -1 on API or internal errors.
14199  */
14200 static int
14201 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14202                             xmlXPathStepOpPtr op,
14203                             int isPredicate)
14204 {
14205     xmlXPathObjectPtr resObj = NULL;
14206
14207 start:
14208     /* comp = ctxt->comp; */
14209     switch (op->op) {
14210         case XPATH_OP_END:
14211             return (0);
14212         case XPATH_OP_VALUE:
14213             resObj = (xmlXPathObjectPtr) op->value4;
14214             if (isPredicate)
14215                 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14216             return(xmlXPathCastToBoolean(resObj));
14217         case XPATH_OP_SORT:
14218             /*
14219             * We don't need sorting for boolean results. Skip this one.
14220             */
14221             if (op->ch1 != -1) {
14222                 op = &ctxt->comp->steps[op->ch1];
14223                 goto start;
14224             }
14225             return(0);
14226         case XPATH_OP_COLLECT:
14227             if (op->ch1 == -1)
14228                 return(0);
14229
14230             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14231             if (ctxt->error != XPATH_EXPRESSION_OK)
14232                 return(-1);
14233
14234             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14235             if (ctxt->error != XPATH_EXPRESSION_OK)
14236                 return(-1);
14237
14238             resObj = valuePop(ctxt);
14239             if (resObj == NULL)
14240                 return(-1);
14241             break;
14242         default:
14243             /*
14244             * Fallback to call xmlXPathCompOpEval().
14245             */
14246             xmlXPathCompOpEval(ctxt, op);
14247             if (ctxt->error != XPATH_EXPRESSION_OK)
14248                 return(-1);
14249
14250             resObj = valuePop(ctxt);
14251             if (resObj == NULL)
14252                 return(-1);
14253             break;
14254     }
14255
14256     if (resObj) {
14257         int res;
14258
14259         if (resObj->type == XPATH_BOOLEAN) {
14260             res = resObj->boolval;
14261         } else if (isPredicate) {
14262             /*
14263             * For predicates a result of type "number" is handled
14264             * differently:
14265             * SPEC XPath 1.0:
14266             * "If the result is a number, the result will be converted
14267             *  to true if the number is equal to the context position
14268             *  and will be converted to false otherwise;"
14269             */
14270             res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14271         } else {
14272             res = xmlXPathCastToBoolean(resObj);
14273         }
14274         xmlXPathReleaseObject(ctxt->context, resObj);
14275         return(res);
14276     }
14277
14278     return(0);
14279 }
14280
14281 #ifdef XPATH_STREAMING
14282 /**
14283  * xmlXPathRunStreamEval:
14284  * @ctxt:  the XPath parser context with the compiled expression
14285  *
14286  * Evaluate the Precompiled Streamable XPath expression in the given context.
14287  */
14288 static int
14289 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14290                       xmlXPathObjectPtr *resultSeq, int toBool)
14291 {
14292     int max_depth, min_depth;
14293     int from_root;
14294     int ret, depth;
14295     int eval_all_nodes;
14296     xmlNodePtr cur = NULL, limit = NULL;
14297     xmlStreamCtxtPtr patstream = NULL;
14298
14299     int nb_nodes = 0;
14300
14301     if ((ctxt == NULL) || (comp == NULL))
14302         return(-1);
14303     max_depth = xmlPatternMaxDepth(comp);
14304     if (max_depth == -1)
14305         return(-1);
14306     if (max_depth == -2)
14307         max_depth = 10000;
14308     min_depth = xmlPatternMinDepth(comp);
14309     if (min_depth == -1)
14310         return(-1);
14311     from_root = xmlPatternFromRoot(comp);
14312     if (from_root < 0)
14313         return(-1);
14314 #if 0
14315     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14316 #endif
14317
14318     if (! toBool) {
14319         if (resultSeq == NULL)
14320             return(-1);
14321         *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14322         if (*resultSeq == NULL)
14323             return(-1);
14324     }
14325
14326     /*
14327      * handle the special cases of "/" amd "." being matched
14328      */
14329     if (min_depth == 0) {
14330         if (from_root) {
14331             /* Select "/" */
14332             if (toBool)
14333                 return(1);
14334             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14335                                      (xmlNodePtr) ctxt->doc);
14336         } else {
14337             /* Select "self::node()" */
14338             if (toBool)
14339                 return(1);
14340             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14341         }
14342     }
14343     if (max_depth == 0) {
14344         return(0);
14345     }
14346
14347     if (from_root) {
14348         cur = (xmlNodePtr)ctxt->doc;
14349     } else if (ctxt->node != NULL) {
14350         switch (ctxt->node->type) {
14351             case XML_ELEMENT_NODE:
14352             case XML_DOCUMENT_NODE:
14353             case XML_DOCUMENT_FRAG_NODE:
14354             case XML_HTML_DOCUMENT_NODE:
14355 #ifdef LIBXML_DOCB_ENABLED
14356             case XML_DOCB_DOCUMENT_NODE:
14357 #endif
14358                 cur = ctxt->node;
14359                 break;
14360             case XML_ATTRIBUTE_NODE:
14361             case XML_TEXT_NODE:
14362             case XML_CDATA_SECTION_NODE:
14363             case XML_ENTITY_REF_NODE:
14364             case XML_ENTITY_NODE:
14365             case XML_PI_NODE:
14366             case XML_COMMENT_NODE:
14367             case XML_NOTATION_NODE:
14368             case XML_DTD_NODE:
14369             case XML_DOCUMENT_TYPE_NODE:
14370             case XML_ELEMENT_DECL:
14371             case XML_ATTRIBUTE_DECL:
14372             case XML_ENTITY_DECL:
14373             case XML_NAMESPACE_DECL:
14374             case XML_XINCLUDE_START:
14375             case XML_XINCLUDE_END:
14376                 break;
14377         }
14378         limit = cur;
14379     }
14380     if (cur == NULL) {
14381         return(0);
14382     }
14383
14384     patstream = xmlPatternGetStreamCtxt(comp);
14385     if (patstream == NULL) {
14386         /*
14387         * QUESTION TODO: Is this an error?
14388         */
14389         return(0);
14390     }
14391
14392     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14393
14394     if (from_root) {
14395         ret = xmlStreamPush(patstream, NULL, NULL);
14396         if (ret < 0) {
14397         } else if (ret == 1) {
14398             if (toBool)
14399                 goto return_1;
14400             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14401         }
14402     }
14403     depth = 0;
14404     goto scan_children;
14405 next_node:
14406     do {
14407         nb_nodes++;
14408
14409         switch (cur->type) {
14410             case XML_ELEMENT_NODE:
14411             case XML_TEXT_NODE:
14412             case XML_CDATA_SECTION_NODE:
14413             case XML_COMMENT_NODE:
14414             case XML_PI_NODE:
14415                 if (cur->type == XML_ELEMENT_NODE) {
14416                     ret = xmlStreamPush(patstream, cur->name,
14417                                 (cur->ns ? cur->ns->href : NULL));
14418                 } else if (eval_all_nodes)
14419                     ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14420                 else
14421                     break;
14422
14423                 if (ret < 0) {
14424                     /* NOP. */
14425                 } else if (ret == 1) {
14426                     if (toBool)
14427                         goto return_1;
14428                     if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14429                         < 0) {
14430                         ctxt->lastError.domain = XML_FROM_XPATH;
14431                         ctxt->lastError.code = XML_ERR_NO_MEMORY;
14432                     }
14433                 }
14434                 if ((cur->children == NULL) || (depth >= max_depth)) {
14435                     ret = xmlStreamPop(patstream);
14436                     while (cur->next != NULL) {
14437                         cur = cur->next;
14438                         if ((cur->type != XML_ENTITY_DECL) &&
14439                             (cur->type != XML_DTD_NODE))
14440                             goto next_node;
14441                     }
14442                 }
14443             default:
14444                 break;
14445         }
14446
14447 scan_children:
14448         if (cur->type == XML_NAMESPACE_DECL) break;
14449         if ((cur->children != NULL) && (depth < max_depth)) {
14450             /*
14451              * Do not descend on entities declarations
14452              */
14453             if (cur->children->type != XML_ENTITY_DECL) {
14454                 cur = cur->children;
14455                 depth++;
14456                 /*
14457                  * Skip DTDs
14458                  */
14459                 if (cur->type != XML_DTD_NODE)
14460                     continue;
14461             }
14462         }
14463
14464         if (cur == limit)
14465             break;
14466
14467         while (cur->next != NULL) {
14468             cur = cur->next;
14469             if ((cur->type != XML_ENTITY_DECL) &&
14470                 (cur->type != XML_DTD_NODE))
14471                 goto next_node;
14472         }
14473
14474         do {
14475             cur = cur->parent;
14476             depth--;
14477             if ((cur == NULL) || (cur == limit))
14478                 goto done;
14479             if (cur->type == XML_ELEMENT_NODE) {
14480                 ret = xmlStreamPop(patstream);
14481             } else if ((eval_all_nodes) &&
14482                 ((cur->type == XML_TEXT_NODE) ||
14483                  (cur->type == XML_CDATA_SECTION_NODE) ||
14484                  (cur->type == XML_COMMENT_NODE) ||
14485                  (cur->type == XML_PI_NODE)))
14486             {
14487                 ret = xmlStreamPop(patstream);
14488             }
14489             if (cur->next != NULL) {
14490                 cur = cur->next;
14491                 break;
14492             }
14493         } while (cur != NULL);
14494
14495     } while ((cur != NULL) && (depth >= 0));
14496
14497 done:
14498
14499 #if 0
14500     printf("stream eval: checked %d nodes selected %d\n",
14501            nb_nodes, retObj->nodesetval->nodeNr);
14502 #endif
14503
14504     if (patstream)
14505         xmlFreeStreamCtxt(patstream);
14506     return(0);
14507
14508 return_1:
14509     if (patstream)
14510         xmlFreeStreamCtxt(patstream);
14511     return(1);
14512 }
14513 #endif /* XPATH_STREAMING */
14514
14515 /**
14516  * xmlXPathRunEval:
14517  * @ctxt:  the XPath parser context with the compiled expression
14518  * @toBool:  evaluate to a boolean result
14519  *
14520  * Evaluate the Precompiled XPath expression in the given context.
14521  */
14522 static int
14523 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14524 {
14525     xmlXPathCompExprPtr comp;
14526
14527     if ((ctxt == NULL) || (ctxt->comp == NULL))
14528         return(-1);
14529
14530     if (ctxt->valueTab == NULL) {
14531         /* Allocate the value stack */
14532         ctxt->valueTab = (xmlXPathObjectPtr *)
14533                          xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14534         if (ctxt->valueTab == NULL) {
14535             xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14536             xmlFree(ctxt);
14537         }
14538         ctxt->valueNr = 0;
14539         ctxt->valueMax = 10;
14540         ctxt->value = NULL;
14541         ctxt->valueFrame = 0;
14542     }
14543 #ifdef XPATH_STREAMING
14544     if (ctxt->comp->stream) {
14545         int res;
14546
14547         if (toBool) {
14548             /*
14549             * Evaluation to boolean result.
14550             */
14551             res = xmlXPathRunStreamEval(ctxt->context,
14552                 ctxt->comp->stream, NULL, 1);
14553             if (res != -1)
14554                 return(res);
14555         } else {
14556             xmlXPathObjectPtr resObj = NULL;
14557
14558             /*
14559             * Evaluation to a sequence.
14560             */
14561             res = xmlXPathRunStreamEval(ctxt->context,
14562                 ctxt->comp->stream, &resObj, 0);
14563
14564             if ((res != -1) && (resObj != NULL)) {
14565                 valuePush(ctxt, resObj);
14566                 return(0);
14567             }
14568             if (resObj != NULL)
14569                 xmlXPathReleaseObject(ctxt->context, resObj);
14570         }
14571         /*
14572         * QUESTION TODO: This falls back to normal XPath evaluation
14573         * if res == -1. Is this intended?
14574         */
14575     }
14576 #endif
14577     comp = ctxt->comp;
14578     if (comp->last < 0) {
14579         xmlGenericError(xmlGenericErrorContext,
14580             "xmlXPathRunEval: last is less than zero\n");
14581         return(-1);
14582     }
14583     if (toBool)
14584         return(xmlXPathCompOpEvalToBoolean(ctxt,
14585             &comp->steps[comp->last], 0));
14586     else
14587         xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14588
14589     return(0);
14590 }
14591
14592 /************************************************************************
14593  *                                                                      *
14594  *                      Public interfaces                               *
14595  *                                                                      *
14596  ************************************************************************/
14597
14598 /**
14599  * xmlXPathEvalPredicate:
14600  * @ctxt:  the XPath context
14601  * @res:  the Predicate Expression evaluation result
14602  *
14603  * Evaluate a predicate result for the current node.
14604  * A PredicateExpr is evaluated by evaluating the Expr and converting
14605  * the result to a boolean. If the result is a number, the result will
14606  * be converted to true if the number is equal to the position of the
14607  * context node in the context node list (as returned by the position
14608  * function) and will be converted to false otherwise; if the result
14609  * is not a number, then the result will be converted as if by a call
14610  * to the boolean function.
14611  *
14612  * Returns 1 if predicate is true, 0 otherwise
14613  */
14614 int
14615 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14616     if ((ctxt == NULL) || (res == NULL)) return(0);
14617     switch (res->type) {
14618         case XPATH_BOOLEAN:
14619             return(res->boolval);
14620         case XPATH_NUMBER:
14621             return(res->floatval == ctxt->proximityPosition);
14622         case XPATH_NODESET:
14623         case XPATH_XSLT_TREE:
14624             if (res->nodesetval == NULL)
14625                 return(0);
14626             return(res->nodesetval->nodeNr != 0);
14627         case XPATH_STRING:
14628             return((res->stringval != NULL) &&
14629                    (xmlStrlen(res->stringval) != 0));
14630         default:
14631             STRANGE
14632     }
14633     return(0);
14634 }
14635
14636 /**
14637  * xmlXPathEvaluatePredicateResult:
14638  * @ctxt:  the XPath Parser context
14639  * @res:  the Predicate Expression evaluation result
14640  *
14641  * Evaluate a predicate result for the current node.
14642  * A PredicateExpr is evaluated by evaluating the Expr and converting
14643  * the result to a boolean. If the result is a number, the result will
14644  * be converted to true if the number is equal to the position of the
14645  * context node in the context node list (as returned by the position
14646  * function) and will be converted to false otherwise; if the result
14647  * is not a number, then the result will be converted as if by a call
14648  * to the boolean function.
14649  *
14650  * Returns 1 if predicate is true, 0 otherwise
14651  */
14652 int
14653 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14654                                 xmlXPathObjectPtr res) {
14655     if ((ctxt == NULL) || (res == NULL)) return(0);
14656     switch (res->type) {
14657         case XPATH_BOOLEAN:
14658             return(res->boolval);
14659         case XPATH_NUMBER:
14660 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14661             return((res->floatval == ctxt->context->proximityPosition) &&
14662                    (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14663 #else
14664             return(res->floatval == ctxt->context->proximityPosition);
14665 #endif
14666         case XPATH_NODESET:
14667         case XPATH_XSLT_TREE:
14668             if (res->nodesetval == NULL)
14669                 return(0);
14670             return(res->nodesetval->nodeNr != 0);
14671         case XPATH_STRING:
14672             return((res->stringval != NULL) && (res->stringval[0] != 0));
14673 #ifdef LIBXML_XPTR_ENABLED
14674         case XPATH_LOCATIONSET:{
14675             xmlLocationSetPtr ptr = res->user;
14676             if (ptr == NULL)
14677                 return(0);
14678             return (ptr->locNr != 0);
14679             }
14680 #endif
14681         default:
14682             STRANGE
14683     }
14684     return(0);
14685 }
14686
14687 #ifdef XPATH_STREAMING
14688 /**
14689  * xmlXPathTryStreamCompile:
14690  * @ctxt: an XPath context
14691  * @str:  the XPath expression
14692  *
14693  * Try to compile the XPath expression as a streamable subset.
14694  *
14695  * Returns the compiled expression or NULL if failed to compile.
14696  */
14697 static xmlXPathCompExprPtr
14698 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14699     /*
14700      * Optimization: use streaming patterns when the XPath expression can
14701      * be compiled to a stream lookup
14702      */
14703     xmlPatternPtr stream;
14704     xmlXPathCompExprPtr comp;
14705     xmlDictPtr dict = NULL;
14706     const xmlChar **namespaces = NULL;
14707     xmlNsPtr ns;
14708     int i, j;
14709
14710     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14711         (!xmlStrchr(str, '@'))) {
14712         const xmlChar *tmp;
14713
14714         /*
14715          * We don't try to handle expressions using the verbose axis
14716          * specifiers ("::"), just the simplied form at this point.
14717          * Additionally, if there is no list of namespaces available and
14718          *  there's a ":" in the expression, indicating a prefixed QName,
14719          *  then we won't try to compile either. xmlPatterncompile() needs
14720          *  to have a list of namespaces at compilation time in order to
14721          *  compile prefixed name tests.
14722          */
14723         tmp = xmlStrchr(str, ':');
14724         if ((tmp != NULL) &&
14725             ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14726             return(NULL);
14727
14728         if (ctxt != NULL) {
14729             dict = ctxt->dict;
14730             if (ctxt->nsNr > 0) {
14731                 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14732                 if (namespaces == NULL) {
14733                     xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14734                     return(NULL);
14735                 }
14736                 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14737                     ns = ctxt->namespaces[j];
14738                     namespaces[i++] = ns->href;
14739                     namespaces[i++] = ns->prefix;
14740                 }
14741                 namespaces[i++] = NULL;
14742                 namespaces[i] = NULL;
14743             }
14744         }
14745
14746         stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14747                         &namespaces[0]);
14748         if (namespaces != NULL) {
14749             xmlFree((xmlChar **)namespaces);
14750         }
14751         if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14752             comp = xmlXPathNewCompExpr();
14753             if (comp == NULL) {
14754                 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14755                 return(NULL);
14756             }
14757             comp->stream = stream;
14758             comp->dict = dict;
14759             if (comp->dict)
14760                 xmlDictReference(comp->dict);
14761             return(comp);
14762         }
14763         xmlFreePattern(stream);
14764     }
14765     return(NULL);
14766 }
14767 #endif /* XPATH_STREAMING */
14768
14769 static void
14770 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14771 {
14772     /*
14773     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14774     * internal representation.
14775     */
14776
14777     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14778         (op->ch1 != -1) &&
14779         (op->ch2 == -1 /* no predicate */))
14780     {
14781         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14782
14783         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14784             ((xmlXPathAxisVal) prevop->value ==
14785                 AXIS_DESCENDANT_OR_SELF) &&
14786             (prevop->ch2 == -1) &&
14787             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14788             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14789         {
14790             /*
14791             * This is a "descendant-or-self::node()" without predicates.
14792             * Try to eliminate it.
14793             */
14794
14795             switch ((xmlXPathAxisVal) op->value) {
14796                 case AXIS_CHILD:
14797                 case AXIS_DESCENDANT:
14798                     /*
14799                     * Convert "descendant-or-self::node()/child::" or
14800                     * "descendant-or-self::node()/descendant::" to
14801                     * "descendant::"
14802                     */
14803                     op->ch1   = prevop->ch1;
14804                     op->value = AXIS_DESCENDANT;
14805                     break;
14806                 case AXIS_SELF:
14807                 case AXIS_DESCENDANT_OR_SELF:
14808                     /*
14809                     * Convert "descendant-or-self::node()/self::" or
14810                     * "descendant-or-self::node()/descendant-or-self::" to
14811                     * to "descendant-or-self::"
14812                     */
14813                     op->ch1   = prevop->ch1;
14814                     op->value = AXIS_DESCENDANT_OR_SELF;
14815                     break;
14816                 default:
14817                     break;
14818             }
14819         }
14820     }
14821
14822     /* OP_VALUE has invalid ch1. */
14823     if (op->op == XPATH_OP_VALUE)
14824         return;
14825
14826     /* Recurse */
14827     if (op->ch1 != -1)
14828         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14829     if (op->ch2 != -1)
14830         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14831 }
14832
14833 /**
14834  * xmlXPathCtxtCompile:
14835  * @ctxt: an XPath context
14836  * @str:  the XPath expression
14837  *
14838  * Compile an XPath expression
14839  *
14840  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14841  *         the caller has to free the object.
14842  */
14843 xmlXPathCompExprPtr
14844 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14845     xmlXPathParserContextPtr pctxt;
14846     xmlXPathCompExprPtr comp;
14847
14848 #ifdef XPATH_STREAMING
14849     comp = xmlXPathTryStreamCompile(ctxt, str);
14850     if (comp != NULL)
14851         return(comp);
14852 #endif
14853
14854     xmlXPathInit();
14855
14856     pctxt = xmlXPathNewParserContext(str, ctxt);
14857     if (pctxt == NULL)
14858         return NULL;
14859     xmlXPathCompileExpr(pctxt, 1);
14860
14861     if( pctxt->error != XPATH_EXPRESSION_OK )
14862     {
14863         xmlXPathFreeParserContext(pctxt);
14864         return(NULL);
14865     }
14866
14867     if (*pctxt->cur != 0) {
14868         /*
14869          * aleksey: in some cases this line prints *second* error message
14870          * (see bug #78858) and probably this should be fixed.
14871          * However, we are not sure that all error messages are printed
14872          * out in other places. It's not critical so we leave it as-is for now
14873          */
14874         xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14875         comp = NULL;
14876     } else {
14877         comp = pctxt->comp;
14878         pctxt->comp = NULL;
14879     }
14880     xmlXPathFreeParserContext(pctxt);
14881
14882     if (comp != NULL) {
14883         comp->expr = xmlStrdup(str);
14884 #ifdef DEBUG_EVAL_COUNTS
14885         comp->string = xmlStrdup(str);
14886         comp->nb = 0;
14887 #endif
14888         if ((comp->nbStep > 1) && (comp->last >= 0)) {
14889             xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14890         }
14891     }
14892     return(comp);
14893 }
14894
14895 /**
14896  * xmlXPathCompile:
14897  * @str:  the XPath expression
14898  *
14899  * Compile an XPath expression
14900  *
14901  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14902  *         the caller has to free the object.
14903  */
14904 xmlXPathCompExprPtr
14905 xmlXPathCompile(const xmlChar *str) {
14906     return(xmlXPathCtxtCompile(NULL, str));
14907 }
14908
14909 /**
14910  * xmlXPathCompiledEvalInternal:
14911  * @comp:  the compiled XPath expression
14912  * @ctxt:  the XPath context
14913  * @resObj: the resulting XPath object or NULL
14914  * @toBool: 1 if only a boolean result is requested
14915  *
14916  * Evaluate the Precompiled XPath expression in the given context.
14917  * The caller has to free @resObj.
14918  *
14919  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14920  *         the caller has to free the object.
14921  */
14922 static int
14923 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14924                              xmlXPathContextPtr ctxt,
14925                              xmlXPathObjectPtr *resObjPtr,
14926                              int toBool)
14927 {
14928     xmlXPathParserContextPtr pctxt;
14929     xmlXPathObjectPtr resObj;
14930 #ifndef LIBXML_THREAD_ENABLED
14931     static int reentance = 0;
14932 #endif
14933     int res;
14934
14935     CHECK_CTXT_NEG(ctxt)
14936
14937     if (comp == NULL)
14938         return(-1);
14939     xmlXPathInit();
14940
14941 #ifndef LIBXML_THREAD_ENABLED
14942     reentance++;
14943     if (reentance > 1)
14944         xmlXPathDisableOptimizer = 1;
14945 #endif
14946
14947 #ifdef DEBUG_EVAL_COUNTS
14948     comp->nb++;
14949     if ((comp->string != NULL) && (comp->nb > 100)) {
14950         fprintf(stderr, "100 x %s\n", comp->string);
14951         comp->nb = 0;
14952     }
14953 #endif
14954     pctxt = xmlXPathCompParserContext(comp, ctxt);
14955     res = xmlXPathRunEval(pctxt, toBool);
14956
14957     if (pctxt->error != XPATH_EXPRESSION_OK) {
14958         resObj = NULL;
14959     } else {
14960         resObj = valuePop(pctxt);
14961         if (resObj == NULL) {
14962             if (!toBool)
14963                 xmlGenericError(xmlGenericErrorContext,
14964                     "xmlXPathCompiledEval: No result on the stack.\n");
14965         } else if (pctxt->valueNr > 0) {
14966             xmlGenericError(xmlGenericErrorContext,
14967                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14968                 pctxt->valueNr);
14969         }
14970     }
14971
14972     if (resObjPtr)
14973         *resObjPtr = resObj;
14974     else
14975         xmlXPathReleaseObject(ctxt, resObj);
14976
14977     pctxt->comp = NULL;
14978     xmlXPathFreeParserContext(pctxt);
14979 #ifndef LIBXML_THREAD_ENABLED
14980     reentance--;
14981 #endif
14982
14983     return(res);
14984 }
14985
14986 /**
14987  * xmlXPathCompiledEval:
14988  * @comp:  the compiled XPath expression
14989  * @ctx:  the XPath context
14990  *
14991  * Evaluate the Precompiled XPath expression in the given context.
14992  *
14993  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14994  *         the caller has to free the object.
14995  */
14996 xmlXPathObjectPtr
14997 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14998 {
14999     xmlXPathObjectPtr res = NULL;
15000
15001     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
15002     return(res);
15003 }
15004
15005 /**
15006  * xmlXPathCompiledEvalToBoolean:
15007  * @comp:  the compiled XPath expression
15008  * @ctxt:  the XPath context
15009  *
15010  * Applies the XPath boolean() function on the result of the given
15011  * compiled expression.
15012  *
15013  * Returns 1 if the expression evaluated to true, 0 if to false and
15014  *         -1 in API and internal errors.
15015  */
15016 int
15017 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
15018                               xmlXPathContextPtr ctxt)
15019 {
15020     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
15021 }
15022
15023 /**
15024  * xmlXPathEvalExpr:
15025  * @ctxt:  the XPath Parser context
15026  *
15027  * Parse and evaluate an XPath expression in the given context,
15028  * then push the result on the context stack
15029  */
15030 void
15031 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
15032 #ifdef XPATH_STREAMING
15033     xmlXPathCompExprPtr comp;
15034 #endif
15035
15036     if (ctxt == NULL) return;
15037
15038 #ifdef XPATH_STREAMING
15039     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
15040     if (comp != NULL) {
15041         if (ctxt->comp != NULL)
15042             xmlXPathFreeCompExpr(ctxt->comp);
15043         ctxt->comp = comp;
15044     } else
15045 #endif
15046     {
15047         xmlXPathCompileExpr(ctxt, 1);
15048         CHECK_ERROR;
15049
15050         /* Check for trailing characters. */
15051         if (*ctxt->cur != 0)
15052             XP_ERROR(XPATH_EXPR_ERROR);
15053
15054         if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
15055             xmlXPathOptimizeExpression(ctxt->comp,
15056                 &ctxt->comp->steps[ctxt->comp->last]);
15057     }
15058
15059     xmlXPathRunEval(ctxt, 0);
15060 }
15061
15062 /**
15063  * xmlXPathEval:
15064  * @str:  the XPath expression
15065  * @ctx:  the XPath context
15066  *
15067  * Evaluate the XPath Location Path in the given context.
15068  *
15069  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15070  *         the caller has to free the object.
15071  */
15072 xmlXPathObjectPtr
15073 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15074     xmlXPathParserContextPtr ctxt;
15075     xmlXPathObjectPtr res;
15076
15077     CHECK_CTXT(ctx)
15078
15079     xmlXPathInit();
15080
15081     ctxt = xmlXPathNewParserContext(str, ctx);
15082     if (ctxt == NULL)
15083         return NULL;
15084     xmlXPathEvalExpr(ctxt);
15085
15086     if (ctxt->error != XPATH_EXPRESSION_OK) {
15087         res = NULL;
15088     } else {
15089         res = valuePop(ctxt);
15090         if (res == NULL) {
15091             xmlGenericError(xmlGenericErrorContext,
15092                 "xmlXPathCompiledEval: No result on the stack.\n");
15093         } else if (ctxt->valueNr > 0) {
15094             xmlGenericError(xmlGenericErrorContext,
15095                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
15096                 ctxt->valueNr);
15097         }
15098     }
15099
15100     xmlXPathFreeParserContext(ctxt);
15101     return(res);
15102 }
15103
15104 /**
15105  * xmlXPathSetContextNode:
15106  * @node: the node to to use as the context node
15107  * @ctx:  the XPath context
15108  *
15109  * Sets 'node' as the context node. The node must be in the same
15110  * document as that associated with the context.
15111  *
15112  * Returns -1 in case of error or 0 if successful
15113  */
15114 int
15115 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15116     if ((node == NULL) || (ctx == NULL))
15117         return(-1);
15118
15119     if (node->doc == ctx->doc) {
15120         ctx->node = node;
15121         return(0);
15122     }
15123     return(-1);
15124 }
15125
15126 /**
15127  * xmlXPathNodeEval:
15128  * @node: the node to to use as the context node
15129  * @str:  the XPath expression
15130  * @ctx:  the XPath context
15131  *
15132  * Evaluate the XPath Location Path in the given context. The node 'node'
15133  * is set as the context node. The context node is not restored.
15134  *
15135  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15136  *         the caller has to free the object.
15137  */
15138 xmlXPathObjectPtr
15139 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15140     if (str == NULL)
15141         return(NULL);
15142     if (xmlXPathSetContextNode(node, ctx) < 0)
15143         return(NULL);
15144     return(xmlXPathEval(str, ctx));
15145 }
15146
15147 /**
15148  * xmlXPathEvalExpression:
15149  * @str:  the XPath expression
15150  * @ctxt:  the XPath context
15151  *
15152  * Alias for xmlXPathEval().
15153  *
15154  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15155  *         the caller has to free the object.
15156  */
15157 xmlXPathObjectPtr
15158 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15159     return(xmlXPathEval(str, ctxt));
15160 }
15161
15162 /************************************************************************
15163  *                                                                      *
15164  *      Extra functions not pertaining to the XPath spec                *
15165  *                                                                      *
15166  ************************************************************************/
15167 /**
15168  * xmlXPathEscapeUriFunction:
15169  * @ctxt:  the XPath Parser context
15170  * @nargs:  the number of arguments
15171  *
15172  * Implement the escape-uri() XPath function
15173  *    string escape-uri(string $str, bool $escape-reserved)
15174  *
15175  * This function applies the URI escaping rules defined in section 2 of [RFC
15176  * 2396] to the string supplied as $uri-part, which typically represents all
15177  * or part of a URI. The effect of the function is to replace any special
15178  * character in the string by an escape sequence of the form %xx%yy...,
15179  * where xxyy... is the hexadecimal representation of the octets used to
15180  * represent the character in UTF-8.
15181  *
15182  * The set of characters that are escaped depends on the setting of the
15183  * boolean argument $escape-reserved.
15184  *
15185  * If $escape-reserved is true, all characters are escaped other than lower
15186  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15187  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15188  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15189  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15190  * A-F).
15191  *
15192  * If $escape-reserved is false, the behavior differs in that characters
15193  * referred to in [RFC 2396] as reserved characters are not escaped. These
15194  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15195  *
15196  * [RFC 2396] does not define whether escaped URIs should use lower case or
15197  * upper case for hexadecimal digits. To ensure that escaped URIs can be
15198  * compared using string comparison functions, this function must always use
15199  * the upper-case letters A-F.
15200  *
15201  * Generally, $escape-reserved should be set to true when escaping a string
15202  * that is to form a single part of a URI, and to false when escaping an
15203  * entire URI or URI reference.
15204  *
15205  * In the case of non-ascii characters, the string is encoded according to
15206  * utf-8 and then converted according to RFC 2396.
15207  *
15208  * Examples
15209  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15210  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15211  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15212  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15213  *
15214  */
15215 static void
15216 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15217     xmlXPathObjectPtr str;
15218     int escape_reserved;
15219     xmlBufPtr target;
15220     xmlChar *cptr;
15221     xmlChar escape[4];
15222
15223     CHECK_ARITY(2);
15224
15225     escape_reserved = xmlXPathPopBoolean(ctxt);
15226
15227     CAST_TO_STRING;
15228     str = valuePop(ctxt);
15229
15230     target = xmlBufCreate();
15231
15232     escape[0] = '%';
15233     escape[3] = 0;
15234
15235     if (target) {
15236         for (cptr = str->stringval; *cptr; cptr++) {
15237             if ((*cptr >= 'A' && *cptr <= 'Z') ||
15238                 (*cptr >= 'a' && *cptr <= 'z') ||
15239                 (*cptr >= '0' && *cptr <= '9') ||
15240                 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15241                 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15242                 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15243                 (*cptr == '%' &&
15244                  ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15245                   (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15246                   (cptr[1] >= '0' && cptr[1] <= '9')) &&
15247                  ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15248                   (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15249                   (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15250                 (!escape_reserved &&
15251                  (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15252                   *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15253                   *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15254                   *cptr == ','))) {
15255                 xmlBufAdd(target, cptr, 1);
15256             } else {
15257                 if ((*cptr >> 4) < 10)
15258                     escape[1] = '0' + (*cptr >> 4);
15259                 else
15260                     escape[1] = 'A' - 10 + (*cptr >> 4);
15261                 if ((*cptr & 0xF) < 10)
15262                     escape[2] = '0' + (*cptr & 0xF);
15263                 else
15264                     escape[2] = 'A' - 10 + (*cptr & 0xF);
15265
15266                 xmlBufAdd(target, &escape[0], 3);
15267             }
15268         }
15269     }
15270     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15271         xmlBufContent(target)));
15272     xmlBufFree(target);
15273     xmlXPathReleaseObject(ctxt->context, str);
15274 }
15275
15276 /**
15277  * xmlXPathRegisterAllFunctions:
15278  * @ctxt:  the XPath context
15279  *
15280  * Registers all default XPath functions in this context
15281  */
15282 void
15283 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15284 {
15285     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15286                          xmlXPathBooleanFunction);
15287     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15288                          xmlXPathCeilingFunction);
15289     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15290                          xmlXPathCountFunction);
15291     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15292                          xmlXPathConcatFunction);
15293     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15294                          xmlXPathContainsFunction);
15295     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15296                          xmlXPathIdFunction);
15297     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15298                          xmlXPathFalseFunction);
15299     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15300                          xmlXPathFloorFunction);
15301     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15302                          xmlXPathLastFunction);
15303     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15304                          xmlXPathLangFunction);
15305     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15306                          xmlXPathLocalNameFunction);
15307     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15308                          xmlXPathNotFunction);
15309     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15310                          xmlXPathNameFunction);
15311     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15312                          xmlXPathNamespaceURIFunction);
15313     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15314                          xmlXPathNormalizeFunction);
15315     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15316                          xmlXPathNumberFunction);
15317     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15318                          xmlXPathPositionFunction);
15319     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15320                          xmlXPathRoundFunction);
15321     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15322                          xmlXPathStringFunction);
15323     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15324                          xmlXPathStringLengthFunction);
15325     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15326                          xmlXPathStartsWithFunction);
15327     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15328                          xmlXPathSubstringFunction);
15329     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15330                          xmlXPathSubstringBeforeFunction);
15331     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15332                          xmlXPathSubstringAfterFunction);
15333     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15334                          xmlXPathSumFunction);
15335     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15336                          xmlXPathTrueFunction);
15337     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15338                          xmlXPathTranslateFunction);
15339
15340     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15341          (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15342                          xmlXPathEscapeUriFunction);
15343 }
15344
15345 #endif /* LIBXML_XPATH_ENABLED */
15346 #define bottom_xpath
15347 #include "elfgcchack.h"