Imported Upstream version 2.9.5_rc2
[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     fprintf(output, "Compiled Expression : %d elements\n",
1682             comp->nbStep);
1683     i = comp->last;
1684     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1685 }
1686
1687 #ifdef XP_DEBUG_OBJ_USAGE
1688
1689 /*
1690 * XPath object usage related debugging variables.
1691 */
1692 static int xmlXPathDebugObjCounterUndefined = 0;
1693 static int xmlXPathDebugObjCounterNodeset = 0;
1694 static int xmlXPathDebugObjCounterBool = 0;
1695 static int xmlXPathDebugObjCounterNumber = 0;
1696 static int xmlXPathDebugObjCounterString = 0;
1697 static int xmlXPathDebugObjCounterPoint = 0;
1698 static int xmlXPathDebugObjCounterRange = 0;
1699 static int xmlXPathDebugObjCounterLocset = 0;
1700 static int xmlXPathDebugObjCounterUsers = 0;
1701 static int xmlXPathDebugObjCounterXSLTTree = 0;
1702 static int xmlXPathDebugObjCounterAll = 0;
1703
1704 static int xmlXPathDebugObjTotalUndefined = 0;
1705 static int xmlXPathDebugObjTotalNodeset = 0;
1706 static int xmlXPathDebugObjTotalBool = 0;
1707 static int xmlXPathDebugObjTotalNumber = 0;
1708 static int xmlXPathDebugObjTotalString = 0;
1709 static int xmlXPathDebugObjTotalPoint = 0;
1710 static int xmlXPathDebugObjTotalRange = 0;
1711 static int xmlXPathDebugObjTotalLocset = 0;
1712 static int xmlXPathDebugObjTotalUsers = 0;
1713 static int xmlXPathDebugObjTotalXSLTTree = 0;
1714 static int xmlXPathDebugObjTotalAll = 0;
1715
1716 static int xmlXPathDebugObjMaxUndefined = 0;
1717 static int xmlXPathDebugObjMaxNodeset = 0;
1718 static int xmlXPathDebugObjMaxBool = 0;
1719 static int xmlXPathDebugObjMaxNumber = 0;
1720 static int xmlXPathDebugObjMaxString = 0;
1721 static int xmlXPathDebugObjMaxPoint = 0;
1722 static int xmlXPathDebugObjMaxRange = 0;
1723 static int xmlXPathDebugObjMaxLocset = 0;
1724 static int xmlXPathDebugObjMaxUsers = 0;
1725 static int xmlXPathDebugObjMaxXSLTTree = 0;
1726 static int xmlXPathDebugObjMaxAll = 0;
1727
1728 /* REVISIT TODO: Make this static when committing */
1729 static void
1730 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1731 {
1732     if (ctxt != NULL) {
1733         if (ctxt->cache != NULL) {
1734             xmlXPathContextCachePtr cache =
1735                 (xmlXPathContextCachePtr) ctxt->cache;
1736
1737             cache->dbgCachedAll = 0;
1738             cache->dbgCachedNodeset = 0;
1739             cache->dbgCachedString = 0;
1740             cache->dbgCachedBool = 0;
1741             cache->dbgCachedNumber = 0;
1742             cache->dbgCachedPoint = 0;
1743             cache->dbgCachedRange = 0;
1744             cache->dbgCachedLocset = 0;
1745             cache->dbgCachedUsers = 0;
1746             cache->dbgCachedXSLTTree = 0;
1747             cache->dbgCachedUndefined = 0;
1748
1749             cache->dbgReusedAll = 0;
1750             cache->dbgReusedNodeset = 0;
1751             cache->dbgReusedString = 0;
1752             cache->dbgReusedBool = 0;
1753             cache->dbgReusedNumber = 0;
1754             cache->dbgReusedPoint = 0;
1755             cache->dbgReusedRange = 0;
1756             cache->dbgReusedLocset = 0;
1757             cache->dbgReusedUsers = 0;
1758             cache->dbgReusedXSLTTree = 0;
1759             cache->dbgReusedUndefined = 0;
1760         }
1761     }
1762
1763     xmlXPathDebugObjCounterUndefined = 0;
1764     xmlXPathDebugObjCounterNodeset = 0;
1765     xmlXPathDebugObjCounterBool = 0;
1766     xmlXPathDebugObjCounterNumber = 0;
1767     xmlXPathDebugObjCounterString = 0;
1768     xmlXPathDebugObjCounterPoint = 0;
1769     xmlXPathDebugObjCounterRange = 0;
1770     xmlXPathDebugObjCounterLocset = 0;
1771     xmlXPathDebugObjCounterUsers = 0;
1772     xmlXPathDebugObjCounterXSLTTree = 0;
1773     xmlXPathDebugObjCounterAll = 0;
1774
1775     xmlXPathDebugObjTotalUndefined = 0;
1776     xmlXPathDebugObjTotalNodeset = 0;
1777     xmlXPathDebugObjTotalBool = 0;
1778     xmlXPathDebugObjTotalNumber = 0;
1779     xmlXPathDebugObjTotalString = 0;
1780     xmlXPathDebugObjTotalPoint = 0;
1781     xmlXPathDebugObjTotalRange = 0;
1782     xmlXPathDebugObjTotalLocset = 0;
1783     xmlXPathDebugObjTotalUsers = 0;
1784     xmlXPathDebugObjTotalXSLTTree = 0;
1785     xmlXPathDebugObjTotalAll = 0;
1786
1787     xmlXPathDebugObjMaxUndefined = 0;
1788     xmlXPathDebugObjMaxNodeset = 0;
1789     xmlXPathDebugObjMaxBool = 0;
1790     xmlXPathDebugObjMaxNumber = 0;
1791     xmlXPathDebugObjMaxString = 0;
1792     xmlXPathDebugObjMaxPoint = 0;
1793     xmlXPathDebugObjMaxRange = 0;
1794     xmlXPathDebugObjMaxLocset = 0;
1795     xmlXPathDebugObjMaxUsers = 0;
1796     xmlXPathDebugObjMaxXSLTTree = 0;
1797     xmlXPathDebugObjMaxAll = 0;
1798
1799 }
1800
1801 static void
1802 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1803                               xmlXPathObjectType objType)
1804 {
1805     int isCached = 0;
1806
1807     if (ctxt != NULL) {
1808         if (ctxt->cache != NULL) {
1809             xmlXPathContextCachePtr cache =
1810                 (xmlXPathContextCachePtr) ctxt->cache;
1811
1812             isCached = 1;
1813
1814             cache->dbgReusedAll++;
1815             switch (objType) {
1816                 case XPATH_UNDEFINED:
1817                     cache->dbgReusedUndefined++;
1818                     break;
1819                 case XPATH_NODESET:
1820                     cache->dbgReusedNodeset++;
1821                     break;
1822                 case XPATH_BOOLEAN:
1823                     cache->dbgReusedBool++;
1824                     break;
1825                 case XPATH_NUMBER:
1826                     cache->dbgReusedNumber++;
1827                     break;
1828                 case XPATH_STRING:
1829                     cache->dbgReusedString++;
1830                     break;
1831                 case XPATH_POINT:
1832                     cache->dbgReusedPoint++;
1833                     break;
1834                 case XPATH_RANGE:
1835                     cache->dbgReusedRange++;
1836                     break;
1837                 case XPATH_LOCATIONSET:
1838                     cache->dbgReusedLocset++;
1839                     break;
1840                 case XPATH_USERS:
1841                     cache->dbgReusedUsers++;
1842                     break;
1843                 case XPATH_XSLT_TREE:
1844                     cache->dbgReusedXSLTTree++;
1845                     break;
1846                 default:
1847                     break;
1848             }
1849         }
1850     }
1851
1852     switch (objType) {
1853         case XPATH_UNDEFINED:
1854             if (! isCached)
1855                 xmlXPathDebugObjTotalUndefined++;
1856             xmlXPathDebugObjCounterUndefined++;
1857             if (xmlXPathDebugObjCounterUndefined >
1858                 xmlXPathDebugObjMaxUndefined)
1859                 xmlXPathDebugObjMaxUndefined =
1860                     xmlXPathDebugObjCounterUndefined;
1861             break;
1862         case XPATH_NODESET:
1863             if (! isCached)
1864                 xmlXPathDebugObjTotalNodeset++;
1865             xmlXPathDebugObjCounterNodeset++;
1866             if (xmlXPathDebugObjCounterNodeset >
1867                 xmlXPathDebugObjMaxNodeset)
1868                 xmlXPathDebugObjMaxNodeset =
1869                     xmlXPathDebugObjCounterNodeset;
1870             break;
1871         case XPATH_BOOLEAN:
1872             if (! isCached)
1873                 xmlXPathDebugObjTotalBool++;
1874             xmlXPathDebugObjCounterBool++;
1875             if (xmlXPathDebugObjCounterBool >
1876                 xmlXPathDebugObjMaxBool)
1877                 xmlXPathDebugObjMaxBool =
1878                     xmlXPathDebugObjCounterBool;
1879             break;
1880         case XPATH_NUMBER:
1881             if (! isCached)
1882                 xmlXPathDebugObjTotalNumber++;
1883             xmlXPathDebugObjCounterNumber++;
1884             if (xmlXPathDebugObjCounterNumber >
1885                 xmlXPathDebugObjMaxNumber)
1886                 xmlXPathDebugObjMaxNumber =
1887                     xmlXPathDebugObjCounterNumber;
1888             break;
1889         case XPATH_STRING:
1890             if (! isCached)
1891                 xmlXPathDebugObjTotalString++;
1892             xmlXPathDebugObjCounterString++;
1893             if (xmlXPathDebugObjCounterString >
1894                 xmlXPathDebugObjMaxString)
1895                 xmlXPathDebugObjMaxString =
1896                     xmlXPathDebugObjCounterString;
1897             break;
1898         case XPATH_POINT:
1899             if (! isCached)
1900                 xmlXPathDebugObjTotalPoint++;
1901             xmlXPathDebugObjCounterPoint++;
1902             if (xmlXPathDebugObjCounterPoint >
1903                 xmlXPathDebugObjMaxPoint)
1904                 xmlXPathDebugObjMaxPoint =
1905                     xmlXPathDebugObjCounterPoint;
1906             break;
1907         case XPATH_RANGE:
1908             if (! isCached)
1909                 xmlXPathDebugObjTotalRange++;
1910             xmlXPathDebugObjCounterRange++;
1911             if (xmlXPathDebugObjCounterRange >
1912                 xmlXPathDebugObjMaxRange)
1913                 xmlXPathDebugObjMaxRange =
1914                     xmlXPathDebugObjCounterRange;
1915             break;
1916         case XPATH_LOCATIONSET:
1917             if (! isCached)
1918                 xmlXPathDebugObjTotalLocset++;
1919             xmlXPathDebugObjCounterLocset++;
1920             if (xmlXPathDebugObjCounterLocset >
1921                 xmlXPathDebugObjMaxLocset)
1922                 xmlXPathDebugObjMaxLocset =
1923                     xmlXPathDebugObjCounterLocset;
1924             break;
1925         case XPATH_USERS:
1926             if (! isCached)
1927                 xmlXPathDebugObjTotalUsers++;
1928             xmlXPathDebugObjCounterUsers++;
1929             if (xmlXPathDebugObjCounterUsers >
1930                 xmlXPathDebugObjMaxUsers)
1931                 xmlXPathDebugObjMaxUsers =
1932                     xmlXPathDebugObjCounterUsers;
1933             break;
1934         case XPATH_XSLT_TREE:
1935             if (! isCached)
1936                 xmlXPathDebugObjTotalXSLTTree++;
1937             xmlXPathDebugObjCounterXSLTTree++;
1938             if (xmlXPathDebugObjCounterXSLTTree >
1939                 xmlXPathDebugObjMaxXSLTTree)
1940                 xmlXPathDebugObjMaxXSLTTree =
1941                     xmlXPathDebugObjCounterXSLTTree;
1942             break;
1943         default:
1944             break;
1945     }
1946     if (! isCached)
1947         xmlXPathDebugObjTotalAll++;
1948     xmlXPathDebugObjCounterAll++;
1949     if (xmlXPathDebugObjCounterAll >
1950         xmlXPathDebugObjMaxAll)
1951         xmlXPathDebugObjMaxAll =
1952             xmlXPathDebugObjCounterAll;
1953 }
1954
1955 static void
1956 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1957                               xmlXPathObjectType objType)
1958 {
1959     int isCached = 0;
1960
1961     if (ctxt != NULL) {
1962         if (ctxt->cache != NULL) {
1963             xmlXPathContextCachePtr cache =
1964                 (xmlXPathContextCachePtr) ctxt->cache;
1965
1966             isCached = 1;
1967
1968             cache->dbgCachedAll++;
1969             switch (objType) {
1970                 case XPATH_UNDEFINED:
1971                     cache->dbgCachedUndefined++;
1972                     break;
1973                 case XPATH_NODESET:
1974                     cache->dbgCachedNodeset++;
1975                     break;
1976                 case XPATH_BOOLEAN:
1977                     cache->dbgCachedBool++;
1978                     break;
1979                 case XPATH_NUMBER:
1980                     cache->dbgCachedNumber++;
1981                     break;
1982                 case XPATH_STRING:
1983                     cache->dbgCachedString++;
1984                     break;
1985                 case XPATH_POINT:
1986                     cache->dbgCachedPoint++;
1987                     break;
1988                 case XPATH_RANGE:
1989                     cache->dbgCachedRange++;
1990                     break;
1991                 case XPATH_LOCATIONSET:
1992                     cache->dbgCachedLocset++;
1993                     break;
1994                 case XPATH_USERS:
1995                     cache->dbgCachedUsers++;
1996                     break;
1997                 case XPATH_XSLT_TREE:
1998                     cache->dbgCachedXSLTTree++;
1999                     break;
2000                 default:
2001                     break;
2002             }
2003
2004         }
2005     }
2006     switch (objType) {
2007         case XPATH_UNDEFINED:
2008             xmlXPathDebugObjCounterUndefined--;
2009             break;
2010         case XPATH_NODESET:
2011             xmlXPathDebugObjCounterNodeset--;
2012             break;
2013         case XPATH_BOOLEAN:
2014             xmlXPathDebugObjCounterBool--;
2015             break;
2016         case XPATH_NUMBER:
2017             xmlXPathDebugObjCounterNumber--;
2018             break;
2019         case XPATH_STRING:
2020             xmlXPathDebugObjCounterString--;
2021             break;
2022         case XPATH_POINT:
2023             xmlXPathDebugObjCounterPoint--;
2024             break;
2025         case XPATH_RANGE:
2026             xmlXPathDebugObjCounterRange--;
2027             break;
2028         case XPATH_LOCATIONSET:
2029             xmlXPathDebugObjCounterLocset--;
2030             break;
2031         case XPATH_USERS:
2032             xmlXPathDebugObjCounterUsers--;
2033             break;
2034         case XPATH_XSLT_TREE:
2035             xmlXPathDebugObjCounterXSLTTree--;
2036             break;
2037         default:
2038             break;
2039     }
2040     xmlXPathDebugObjCounterAll--;
2041 }
2042
2043 /* REVISIT TODO: Make this static when committing */
2044 static void
2045 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2046 {
2047     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2048         reqXSLTTree, reqUndefined;
2049     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2050         caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2051     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2052         reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2053     int leftObjs = xmlXPathDebugObjCounterAll;
2054
2055     reqAll = xmlXPathDebugObjTotalAll;
2056     reqNodeset = xmlXPathDebugObjTotalNodeset;
2057     reqString = xmlXPathDebugObjTotalString;
2058     reqBool = xmlXPathDebugObjTotalBool;
2059     reqNumber = xmlXPathDebugObjTotalNumber;
2060     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2061     reqUndefined = xmlXPathDebugObjTotalUndefined;
2062
2063     printf("# XPath object usage:\n");
2064
2065     if (ctxt != NULL) {
2066         if (ctxt->cache != NULL) {
2067             xmlXPathContextCachePtr cache =
2068                 (xmlXPathContextCachePtr) ctxt->cache;
2069
2070             reAll = cache->dbgReusedAll;
2071             reqAll += reAll;
2072             reNodeset = cache->dbgReusedNodeset;
2073             reqNodeset += reNodeset;
2074             reString = cache->dbgReusedString;
2075             reqString += reString;
2076             reBool = cache->dbgReusedBool;
2077             reqBool += reBool;
2078             reNumber = cache->dbgReusedNumber;
2079             reqNumber += reNumber;
2080             reXSLTTree = cache->dbgReusedXSLTTree;
2081             reqXSLTTree += reXSLTTree;
2082             reUndefined = cache->dbgReusedUndefined;
2083             reqUndefined += reUndefined;
2084
2085             caAll = cache->dbgCachedAll;
2086             caBool = cache->dbgCachedBool;
2087             caNodeset = cache->dbgCachedNodeset;
2088             caString = cache->dbgCachedString;
2089             caNumber = cache->dbgCachedNumber;
2090             caXSLTTree = cache->dbgCachedXSLTTree;
2091             caUndefined = cache->dbgCachedUndefined;
2092
2093             if (cache->nodesetObjs)
2094                 leftObjs -= cache->nodesetObjs->number;
2095             if (cache->stringObjs)
2096                 leftObjs -= cache->stringObjs->number;
2097             if (cache->booleanObjs)
2098                 leftObjs -= cache->booleanObjs->number;
2099             if (cache->numberObjs)
2100                 leftObjs -= cache->numberObjs->number;
2101             if (cache->miscObjs)
2102                 leftObjs -= cache->miscObjs->number;
2103         }
2104     }
2105
2106     printf("# all\n");
2107     printf("#   total  : %d\n", reqAll);
2108     printf("#   left  : %d\n", leftObjs);
2109     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2110     printf("#   reused : %d\n", reAll);
2111     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2112
2113     printf("# node-sets\n");
2114     printf("#   total  : %d\n", reqNodeset);
2115     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2116     printf("#   reused : %d\n", reNodeset);
2117     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2118
2119     printf("# strings\n");
2120     printf("#   total  : %d\n", reqString);
2121     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2122     printf("#   reused : %d\n", reString);
2123     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2124
2125     printf("# booleans\n");
2126     printf("#   total  : %d\n", reqBool);
2127     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2128     printf("#   reused : %d\n", reBool);
2129     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2130
2131     printf("# numbers\n");
2132     printf("#   total  : %d\n", reqNumber);
2133     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2134     printf("#   reused : %d\n", reNumber);
2135     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2136
2137     printf("# XSLT result tree fragments\n");
2138     printf("#   total  : %d\n", reqXSLTTree);
2139     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2140     printf("#   reused : %d\n", reXSLTTree);
2141     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2142
2143     printf("# undefined\n");
2144     printf("#   total  : %d\n", reqUndefined);
2145     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2146     printf("#   reused : %d\n", reUndefined);
2147     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2148
2149 }
2150
2151 #endif /* XP_DEBUG_OBJ_USAGE */
2152
2153 #endif /* LIBXML_DEBUG_ENABLED */
2154
2155 /************************************************************************
2156  *                                                                      *
2157  *                      XPath object caching                            *
2158  *                                                                      *
2159  ************************************************************************/
2160
2161 /**
2162  * xmlXPathNewCache:
2163  *
2164  * Create a new object cache
2165  *
2166  * Returns the xmlXPathCache just allocated.
2167  */
2168 static xmlXPathContextCachePtr
2169 xmlXPathNewCache(void)
2170 {
2171     xmlXPathContextCachePtr ret;
2172
2173     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2174     if (ret == NULL) {
2175         xmlXPathErrMemory(NULL, "creating object cache\n");
2176         return(NULL);
2177     }
2178     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2179     ret->maxNodeset = 100;
2180     ret->maxString = 100;
2181     ret->maxBoolean = 100;
2182     ret->maxNumber = 100;
2183     ret->maxMisc = 100;
2184     return(ret);
2185 }
2186
2187 static void
2188 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2189 {
2190     int i;
2191     xmlXPathObjectPtr obj;
2192
2193     if (list == NULL)
2194         return;
2195
2196     for (i = 0; i < list->number; i++) {
2197         obj = list->items[i];
2198         /*
2199         * Note that it is already assured that we don't need to
2200         * look out for namespace nodes in the node-set.
2201         */
2202         if (obj->nodesetval != NULL) {
2203             if (obj->nodesetval->nodeTab != NULL)
2204                 xmlFree(obj->nodesetval->nodeTab);
2205             xmlFree(obj->nodesetval);
2206         }
2207         xmlFree(obj);
2208 #ifdef XP_DEBUG_OBJ_USAGE
2209         xmlXPathDebugObjCounterAll--;
2210 #endif
2211     }
2212     xmlPointerListFree(list);
2213 }
2214
2215 static void
2216 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2217 {
2218     if (cache == NULL)
2219         return;
2220     if (cache->nodesetObjs)
2221         xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2222     if (cache->stringObjs)
2223         xmlXPathCacheFreeObjectList(cache->stringObjs);
2224     if (cache->booleanObjs)
2225         xmlXPathCacheFreeObjectList(cache->booleanObjs);
2226     if (cache->numberObjs)
2227         xmlXPathCacheFreeObjectList(cache->numberObjs);
2228     if (cache->miscObjs)
2229         xmlXPathCacheFreeObjectList(cache->miscObjs);
2230     xmlFree(cache);
2231 }
2232
2233 /**
2234  * xmlXPathContextSetCache:
2235  *
2236  * @ctxt:  the XPath context
2237  * @active: enables/disables (creates/frees) the cache
2238  * @value: a value with semantics dependant on @options
2239  * @options: options (currently only the value 0 is used)
2240  *
2241  * Creates/frees an object cache on the XPath context.
2242  * If activates XPath objects (xmlXPathObject) will be cached internally
2243  * to be reused.
2244  * @options:
2245  *   0: This will set the XPath object caching:
2246  *      @value:
2247  *        This will set the maximum number of XPath objects
2248  *        to be cached per slot
2249  *        There are 5 slots for: node-set, string, number, boolean, and
2250  *        misc objects. Use <0 for the default number (100).
2251  *   Other values for @options have currently no effect.
2252  *
2253  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2254  */
2255 int
2256 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2257                         int active,
2258                         int value,
2259                         int options)
2260 {
2261     if (ctxt == NULL)
2262         return(-1);
2263     if (active) {
2264         xmlXPathContextCachePtr cache;
2265
2266         if (ctxt->cache == NULL) {
2267             ctxt->cache = xmlXPathNewCache();
2268             if (ctxt->cache == NULL)
2269                 return(-1);
2270         }
2271         cache = (xmlXPathContextCachePtr) ctxt->cache;
2272         if (options == 0) {
2273             if (value < 0)
2274                 value = 100;
2275             cache->maxNodeset = value;
2276             cache->maxString = value;
2277             cache->maxNumber = value;
2278             cache->maxBoolean = value;
2279             cache->maxMisc = value;
2280         }
2281     } else if (ctxt->cache != NULL) {
2282         xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2283         ctxt->cache = NULL;
2284     }
2285     return(0);
2286 }
2287
2288 /**
2289  * xmlXPathCacheWrapNodeSet:
2290  * @ctxt: the XPath context
2291  * @val:  the NodePtr value
2292  *
2293  * This is the cached version of xmlXPathWrapNodeSet().
2294  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2295  *
2296  * Returns the created or reused object.
2297  */
2298 static xmlXPathObjectPtr
2299 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2300 {
2301     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2302         xmlXPathContextCachePtr cache =
2303             (xmlXPathContextCachePtr) ctxt->cache;
2304
2305         if ((cache->miscObjs != NULL) &&
2306             (cache->miscObjs->number != 0))
2307         {
2308             xmlXPathObjectPtr ret;
2309
2310             ret = (xmlXPathObjectPtr)
2311                 cache->miscObjs->items[--cache->miscObjs->number];
2312             ret->type = XPATH_NODESET;
2313             ret->nodesetval = val;
2314 #ifdef XP_DEBUG_OBJ_USAGE
2315             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2316 #endif
2317             return(ret);
2318         }
2319     }
2320
2321     return(xmlXPathWrapNodeSet(val));
2322
2323 }
2324
2325 /**
2326  * xmlXPathCacheWrapString:
2327  * @ctxt: the XPath context
2328  * @val:  the xmlChar * value
2329  *
2330  * This is the cached version of xmlXPathWrapString().
2331  * Wraps the @val string into an XPath object.
2332  *
2333  * Returns the created or reused object.
2334  */
2335 static xmlXPathObjectPtr
2336 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2337 {
2338     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2339         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2340
2341         if ((cache->stringObjs != NULL) &&
2342             (cache->stringObjs->number != 0))
2343         {
2344
2345             xmlXPathObjectPtr ret;
2346
2347             ret = (xmlXPathObjectPtr)
2348                 cache->stringObjs->items[--cache->stringObjs->number];
2349             ret->type = XPATH_STRING;
2350             ret->stringval = val;
2351 #ifdef XP_DEBUG_OBJ_USAGE
2352             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2353 #endif
2354             return(ret);
2355         } else if ((cache->miscObjs != NULL) &&
2356             (cache->miscObjs->number != 0))
2357         {
2358             xmlXPathObjectPtr ret;
2359             /*
2360             * Fallback to misc-cache.
2361             */
2362             ret = (xmlXPathObjectPtr)
2363                 cache->miscObjs->items[--cache->miscObjs->number];
2364
2365             ret->type = XPATH_STRING;
2366             ret->stringval = val;
2367 #ifdef XP_DEBUG_OBJ_USAGE
2368             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2369 #endif
2370             return(ret);
2371         }
2372     }
2373     return(xmlXPathWrapString(val));
2374 }
2375
2376 /**
2377  * xmlXPathCacheNewNodeSet:
2378  * @ctxt: the XPath context
2379  * @val:  the NodePtr value
2380  *
2381  * This is the cached version of xmlXPathNewNodeSet().
2382  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2383  * it with the single Node @val
2384  *
2385  * Returns the created or reused object.
2386  */
2387 static xmlXPathObjectPtr
2388 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2389 {
2390     if ((ctxt != NULL) && (ctxt->cache)) {
2391         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2392
2393         if ((cache->nodesetObjs != NULL) &&
2394             (cache->nodesetObjs->number != 0))
2395         {
2396             xmlXPathObjectPtr ret;
2397             /*
2398             * Use the nodset-cache.
2399             */
2400             ret = (xmlXPathObjectPtr)
2401                 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2402             ret->type = XPATH_NODESET;
2403             ret->boolval = 0;
2404             if (val) {
2405                 if ((ret->nodesetval->nodeMax == 0) ||
2406                     (val->type == XML_NAMESPACE_DECL))
2407                 {
2408                     xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2409                 } else {
2410                     ret->nodesetval->nodeTab[0] = val;
2411                     ret->nodesetval->nodeNr = 1;
2412                 }
2413             }
2414 #ifdef XP_DEBUG_OBJ_USAGE
2415             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2416 #endif
2417             return(ret);
2418         } else if ((cache->miscObjs != NULL) &&
2419             (cache->miscObjs->number != 0))
2420         {
2421             xmlXPathObjectPtr ret;
2422             /*
2423             * Fallback to misc-cache.
2424             */
2425
2426             ret = (xmlXPathObjectPtr)
2427                 cache->miscObjs->items[--cache->miscObjs->number];
2428
2429             ret->type = XPATH_NODESET;
2430             ret->boolval = 0;
2431             ret->nodesetval = xmlXPathNodeSetCreate(val);
2432             if (ret->nodesetval == NULL) {
2433                 ctxt->lastError.domain = XML_FROM_XPATH;
2434                 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2435                 return(NULL);
2436             }
2437 #ifdef XP_DEBUG_OBJ_USAGE
2438             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2439 #endif
2440             return(ret);
2441         }
2442     }
2443     return(xmlXPathNewNodeSet(val));
2444 }
2445
2446 /**
2447  * xmlXPathCacheNewCString:
2448  * @ctxt: the XPath context
2449  * @val:  the char * value
2450  *
2451  * This is the cached version of xmlXPathNewCString().
2452  * Acquire an xmlXPathObjectPtr of type string and of value @val
2453  *
2454  * Returns the created or reused object.
2455  */
2456 static xmlXPathObjectPtr
2457 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2458 {
2459     if ((ctxt != NULL) && (ctxt->cache)) {
2460         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2461
2462         if ((cache->stringObjs != NULL) &&
2463             (cache->stringObjs->number != 0))
2464         {
2465             xmlXPathObjectPtr ret;
2466
2467             ret = (xmlXPathObjectPtr)
2468                 cache->stringObjs->items[--cache->stringObjs->number];
2469
2470             ret->type = XPATH_STRING;
2471             ret->stringval = xmlStrdup(BAD_CAST val);
2472 #ifdef XP_DEBUG_OBJ_USAGE
2473             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2474 #endif
2475             return(ret);
2476         } else if ((cache->miscObjs != NULL) &&
2477             (cache->miscObjs->number != 0))
2478         {
2479             xmlXPathObjectPtr ret;
2480
2481             ret = (xmlXPathObjectPtr)
2482                 cache->miscObjs->items[--cache->miscObjs->number];
2483
2484             ret->type = XPATH_STRING;
2485             ret->stringval = xmlStrdup(BAD_CAST val);
2486 #ifdef XP_DEBUG_OBJ_USAGE
2487             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2488 #endif
2489             return(ret);
2490         }
2491     }
2492     return(xmlXPathNewCString(val));
2493 }
2494
2495 /**
2496  * xmlXPathCacheNewString:
2497  * @ctxt: the XPath context
2498  * @val:  the xmlChar * value
2499  *
2500  * This is the cached version of xmlXPathNewString().
2501  * Acquire an xmlXPathObjectPtr of type string and of value @val
2502  *
2503  * Returns the created or reused object.
2504  */
2505 static xmlXPathObjectPtr
2506 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2507 {
2508     if ((ctxt != NULL) && (ctxt->cache)) {
2509         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2510
2511         if ((cache->stringObjs != NULL) &&
2512             (cache->stringObjs->number != 0))
2513         {
2514             xmlXPathObjectPtr ret;
2515
2516             ret = (xmlXPathObjectPtr)
2517                 cache->stringObjs->items[--cache->stringObjs->number];
2518             ret->type = XPATH_STRING;
2519             if (val != NULL)
2520                 ret->stringval = xmlStrdup(val);
2521             else
2522                 ret->stringval = xmlStrdup((const xmlChar *)"");
2523 #ifdef XP_DEBUG_OBJ_USAGE
2524             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2525 #endif
2526             return(ret);
2527         } else if ((cache->miscObjs != NULL) &&
2528             (cache->miscObjs->number != 0))
2529         {
2530             xmlXPathObjectPtr ret;
2531
2532             ret = (xmlXPathObjectPtr)
2533                 cache->miscObjs->items[--cache->miscObjs->number];
2534
2535             ret->type = XPATH_STRING;
2536             if (val != NULL)
2537                 ret->stringval = xmlStrdup(val);
2538             else
2539                 ret->stringval = xmlStrdup((const xmlChar *)"");
2540 #ifdef XP_DEBUG_OBJ_USAGE
2541             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2542 #endif
2543             return(ret);
2544         }
2545     }
2546     return(xmlXPathNewString(val));
2547 }
2548
2549 /**
2550  * xmlXPathCacheNewBoolean:
2551  * @ctxt: the XPath context
2552  * @val:  the boolean value
2553  *
2554  * This is the cached version of xmlXPathNewBoolean().
2555  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2556  *
2557  * Returns the created or reused object.
2558  */
2559 static xmlXPathObjectPtr
2560 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2561 {
2562     if ((ctxt != NULL) && (ctxt->cache)) {
2563         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2564
2565         if ((cache->booleanObjs != NULL) &&
2566             (cache->booleanObjs->number != 0))
2567         {
2568             xmlXPathObjectPtr ret;
2569
2570             ret = (xmlXPathObjectPtr)
2571                 cache->booleanObjs->items[--cache->booleanObjs->number];
2572             ret->type = XPATH_BOOLEAN;
2573             ret->boolval = (val != 0);
2574 #ifdef XP_DEBUG_OBJ_USAGE
2575             xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2576 #endif
2577             return(ret);
2578         } else if ((cache->miscObjs != NULL) &&
2579             (cache->miscObjs->number != 0))
2580         {
2581             xmlXPathObjectPtr ret;
2582
2583             ret = (xmlXPathObjectPtr)
2584                 cache->miscObjs->items[--cache->miscObjs->number];
2585
2586             ret->type = XPATH_BOOLEAN;
2587             ret->boolval = (val != 0);
2588 #ifdef XP_DEBUG_OBJ_USAGE
2589             xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2590 #endif
2591             return(ret);
2592         }
2593     }
2594     return(xmlXPathNewBoolean(val));
2595 }
2596
2597 /**
2598  * xmlXPathCacheNewFloat:
2599  * @ctxt: the XPath context
2600  * @val:  the double value
2601  *
2602  * This is the cached version of xmlXPathNewFloat().
2603  * Acquires an xmlXPathObjectPtr of type double and of value @val
2604  *
2605  * Returns the created or reused object.
2606  */
2607 static xmlXPathObjectPtr
2608 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2609 {
2610      if ((ctxt != NULL) && (ctxt->cache)) {
2611         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2612
2613         if ((cache->numberObjs != NULL) &&
2614             (cache->numberObjs->number != 0))
2615         {
2616             xmlXPathObjectPtr ret;
2617
2618             ret = (xmlXPathObjectPtr)
2619                 cache->numberObjs->items[--cache->numberObjs->number];
2620             ret->type = XPATH_NUMBER;
2621             ret->floatval = val;
2622 #ifdef XP_DEBUG_OBJ_USAGE
2623             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2624 #endif
2625             return(ret);
2626         } else if ((cache->miscObjs != NULL) &&
2627             (cache->miscObjs->number != 0))
2628         {
2629             xmlXPathObjectPtr ret;
2630
2631             ret = (xmlXPathObjectPtr)
2632                 cache->miscObjs->items[--cache->miscObjs->number];
2633
2634             ret->type = XPATH_NUMBER;
2635             ret->floatval = val;
2636 #ifdef XP_DEBUG_OBJ_USAGE
2637             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2638 #endif
2639             return(ret);
2640         }
2641     }
2642     return(xmlXPathNewFloat(val));
2643 }
2644
2645 /**
2646  * xmlXPathCacheConvertString:
2647  * @ctxt: the XPath context
2648  * @val:  an XPath object
2649  *
2650  * This is the cached version of xmlXPathConvertString().
2651  * Converts an existing object to its string() equivalent
2652  *
2653  * Returns a created or reused object, the old one is freed (cached)
2654  *         (or the operation is done directly on @val)
2655  */
2656
2657 static xmlXPathObjectPtr
2658 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2659     xmlChar *res = NULL;
2660
2661     if (val == NULL)
2662         return(xmlXPathCacheNewCString(ctxt, ""));
2663
2664     switch (val->type) {
2665     case XPATH_UNDEFINED:
2666 #ifdef DEBUG_EXPR
2667         xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2668 #endif
2669         break;
2670     case XPATH_NODESET:
2671     case XPATH_XSLT_TREE:
2672         res = xmlXPathCastNodeSetToString(val->nodesetval);
2673         break;
2674     case XPATH_STRING:
2675         return(val);
2676     case XPATH_BOOLEAN:
2677         res = xmlXPathCastBooleanToString(val->boolval);
2678         break;
2679     case XPATH_NUMBER:
2680         res = xmlXPathCastNumberToString(val->floatval);
2681         break;
2682     case XPATH_USERS:
2683     case XPATH_POINT:
2684     case XPATH_RANGE:
2685     case XPATH_LOCATIONSET:
2686         TODO;
2687         break;
2688     }
2689     xmlXPathReleaseObject(ctxt, val);
2690     if (res == NULL)
2691         return(xmlXPathCacheNewCString(ctxt, ""));
2692     return(xmlXPathCacheWrapString(ctxt, res));
2693 }
2694
2695 /**
2696  * xmlXPathCacheObjectCopy:
2697  * @ctxt: the XPath context
2698  * @val:  the original object
2699  *
2700  * This is the cached version of xmlXPathObjectCopy().
2701  * Acquire a copy of a given object
2702  *
2703  * Returns a created or reused created object.
2704  */
2705 static xmlXPathObjectPtr
2706 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2707 {
2708     if (val == NULL)
2709         return(NULL);
2710
2711     if (XP_HAS_CACHE(ctxt)) {
2712         switch (val->type) {
2713             case XPATH_NODESET:
2714                 return(xmlXPathCacheWrapNodeSet(ctxt,
2715                     xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2716             case XPATH_STRING:
2717                 return(xmlXPathCacheNewString(ctxt, val->stringval));
2718             case XPATH_BOOLEAN:
2719                 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2720             case XPATH_NUMBER:
2721                 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2722             default:
2723                 break;
2724         }
2725     }
2726     return(xmlXPathObjectCopy(val));
2727 }
2728
2729 /**
2730  * xmlXPathCacheConvertBoolean:
2731  * @ctxt: the XPath context
2732  * @val:  an XPath object
2733  *
2734  * This is the cached version of xmlXPathConvertBoolean().
2735  * Converts an existing object to its boolean() equivalent
2736  *
2737  * Returns a created or reused object, the old one is freed (or the operation
2738  *         is done directly on @val)
2739  */
2740 static xmlXPathObjectPtr
2741 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2742     xmlXPathObjectPtr ret;
2743
2744     if (val == NULL)
2745         return(xmlXPathCacheNewBoolean(ctxt, 0));
2746     if (val->type == XPATH_BOOLEAN)
2747         return(val);
2748     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2749     xmlXPathReleaseObject(ctxt, val);
2750     return(ret);
2751 }
2752
2753 /**
2754  * xmlXPathCacheConvertNumber:
2755  * @ctxt: the XPath context
2756  * @val:  an XPath object
2757  *
2758  * This is the cached version of xmlXPathConvertNumber().
2759  * Converts an existing object to its number() equivalent
2760  *
2761  * Returns a created or reused object, the old one is freed (or the operation
2762  *         is done directly on @val)
2763  */
2764 static xmlXPathObjectPtr
2765 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2766     xmlXPathObjectPtr ret;
2767
2768     if (val == NULL)
2769         return(xmlXPathCacheNewFloat(ctxt, 0.0));
2770     if (val->type == XPATH_NUMBER)
2771         return(val);
2772     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2773     xmlXPathReleaseObject(ctxt, val);
2774     return(ret);
2775 }
2776
2777 /************************************************************************
2778  *                                                                      *
2779  *              Parser stacks related functions and macros              *
2780  *                                                                      *
2781  ************************************************************************/
2782
2783 /**
2784  * xmlXPathSetFrame:
2785  * @ctxt: an XPath parser context
2786  *
2787  * Set the callee evaluation frame
2788  *
2789  * Returns the previous frame value to be restored once done
2790  */
2791 static int
2792 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2793     int ret;
2794
2795     if (ctxt == NULL)
2796         return(0);
2797     ret = ctxt->valueFrame;
2798     ctxt->valueFrame = ctxt->valueNr;
2799     return(ret);
2800 }
2801
2802 /**
2803  * xmlXPathPopFrame:
2804  * @ctxt: an XPath parser context
2805  * @frame: the previous frame value
2806  *
2807  * Remove the callee evaluation frame
2808  */
2809 static void
2810 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2811     if (ctxt == NULL)
2812         return;
2813     if (ctxt->valueNr < ctxt->valueFrame) {
2814         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2815     }
2816     ctxt->valueFrame = frame;
2817 }
2818
2819 /**
2820  * valuePop:
2821  * @ctxt: an XPath evaluation context
2822  *
2823  * Pops the top XPath object from the value stack
2824  *
2825  * Returns the XPath object just removed
2826  */
2827 xmlXPathObjectPtr
2828 valuePop(xmlXPathParserContextPtr ctxt)
2829 {
2830     xmlXPathObjectPtr ret;
2831
2832     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2833         return (NULL);
2834
2835     if (ctxt->valueNr <= ctxt->valueFrame) {
2836         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2837         return (NULL);
2838     }
2839
2840     ctxt->valueNr--;
2841     if (ctxt->valueNr > 0)
2842         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2843     else
2844         ctxt->value = NULL;
2845     ret = ctxt->valueTab[ctxt->valueNr];
2846     ctxt->valueTab[ctxt->valueNr] = NULL;
2847     return (ret);
2848 }
2849 /**
2850  * valuePush:
2851  * @ctxt:  an XPath evaluation context
2852  * @value:  the XPath object
2853  *
2854  * Pushes a new XPath object on top of the value stack
2855  *
2856  * returns the number of items on the value stack
2857  */
2858 int
2859 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2860 {
2861     if ((ctxt == NULL) || (value == NULL)) return(-1);
2862     if (ctxt->valueNr >= ctxt->valueMax) {
2863         xmlXPathObjectPtr *tmp;
2864
2865         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2866             xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2867             ctxt->error = XPATH_MEMORY_ERROR;
2868             return (0);
2869         }
2870         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2871                                              2 * ctxt->valueMax *
2872                                              sizeof(ctxt->valueTab[0]));
2873         if (tmp == NULL) {
2874             xmlXPathErrMemory(NULL, "pushing value\n");
2875             ctxt->error = XPATH_MEMORY_ERROR;
2876             return (0);
2877         }
2878         ctxt->valueMax *= 2;
2879         ctxt->valueTab = tmp;
2880     }
2881     ctxt->valueTab[ctxt->valueNr] = value;
2882     ctxt->value = value;
2883     return (ctxt->valueNr++);
2884 }
2885
2886 /**
2887  * xmlXPathPopBoolean:
2888  * @ctxt:  an XPath parser context
2889  *
2890  * Pops a boolean from the stack, handling conversion if needed.
2891  * Check error with #xmlXPathCheckError.
2892  *
2893  * Returns the boolean
2894  */
2895 int
2896 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2897     xmlXPathObjectPtr obj;
2898     int ret;
2899
2900     obj = valuePop(ctxt);
2901     if (obj == NULL) {
2902         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2903         return(0);
2904     }
2905     if (obj->type != XPATH_BOOLEAN)
2906         ret = xmlXPathCastToBoolean(obj);
2907     else
2908         ret = obj->boolval;
2909     xmlXPathReleaseObject(ctxt->context, obj);
2910     return(ret);
2911 }
2912
2913 /**
2914  * xmlXPathPopNumber:
2915  * @ctxt:  an XPath parser context
2916  *
2917  * Pops a number from the stack, handling conversion if needed.
2918  * Check error with #xmlXPathCheckError.
2919  *
2920  * Returns the number
2921  */
2922 double
2923 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2924     xmlXPathObjectPtr obj;
2925     double ret;
2926
2927     obj = valuePop(ctxt);
2928     if (obj == NULL) {
2929         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2930         return(0);
2931     }
2932     if (obj->type != XPATH_NUMBER)
2933         ret = xmlXPathCastToNumber(obj);
2934     else
2935         ret = obj->floatval;
2936     xmlXPathReleaseObject(ctxt->context, obj);
2937     return(ret);
2938 }
2939
2940 /**
2941  * xmlXPathPopString:
2942  * @ctxt:  an XPath parser context
2943  *
2944  * Pops a string from the stack, handling conversion if needed.
2945  * Check error with #xmlXPathCheckError.
2946  *
2947  * Returns the string
2948  */
2949 xmlChar *
2950 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2951     xmlXPathObjectPtr obj;
2952     xmlChar * ret;
2953
2954     obj = valuePop(ctxt);
2955     if (obj == NULL) {
2956         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2957         return(NULL);
2958     }
2959     ret = xmlXPathCastToString(obj);    /* this does required strdup */
2960     /* TODO: needs refactoring somewhere else */
2961     if (obj->stringval == ret)
2962         obj->stringval = NULL;
2963     xmlXPathReleaseObject(ctxt->context, obj);
2964     return(ret);
2965 }
2966
2967 /**
2968  * xmlXPathPopNodeSet:
2969  * @ctxt:  an XPath parser context
2970  *
2971  * Pops a node-set from the stack, handling conversion if needed.
2972  * Check error with #xmlXPathCheckError.
2973  *
2974  * Returns the node-set
2975  */
2976 xmlNodeSetPtr
2977 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2978     xmlXPathObjectPtr obj;
2979     xmlNodeSetPtr ret;
2980
2981     if (ctxt == NULL) return(NULL);
2982     if (ctxt->value == NULL) {
2983         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2984         return(NULL);
2985     }
2986     if (!xmlXPathStackIsNodeSet(ctxt)) {
2987         xmlXPathSetTypeError(ctxt);
2988         return(NULL);
2989     }
2990     obj = valuePop(ctxt);
2991     ret = obj->nodesetval;
2992 #if 0
2993     /* to fix memory leak of not clearing obj->user */
2994     if (obj->boolval && obj->user != NULL)
2995         xmlFreeNodeList((xmlNodePtr) obj->user);
2996 #endif
2997     obj->nodesetval = NULL;
2998     xmlXPathReleaseObject(ctxt->context, obj);
2999     return(ret);
3000 }
3001
3002 /**
3003  * xmlXPathPopExternal:
3004  * @ctxt:  an XPath parser context
3005  *
3006  * Pops an external object from the stack, handling conversion if needed.
3007  * Check error with #xmlXPathCheckError.
3008  *
3009  * Returns the object
3010  */
3011 void *
3012 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3013     xmlXPathObjectPtr obj;
3014     void * ret;
3015
3016     if ((ctxt == NULL) || (ctxt->value == NULL)) {
3017         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3018         return(NULL);
3019     }
3020     if (ctxt->value->type != XPATH_USERS) {
3021         xmlXPathSetTypeError(ctxt);
3022         return(NULL);
3023     }
3024     obj = valuePop(ctxt);
3025     ret = obj->user;
3026     obj->user = NULL;
3027     xmlXPathReleaseObject(ctxt->context, obj);
3028     return(ret);
3029 }
3030
3031 /*
3032  * Macros for accessing the content. Those should be used only by the parser,
3033  * and not exported.
3034  *
3035  * Dirty macros, i.e. one need to make assumption on the context to use them
3036  *
3037  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3038  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3039  *           in ISO-Latin or UTF-8.
3040  *           This should be used internally by the parser
3041  *           only to compare to ASCII values otherwise it would break when
3042  *           running with UTF-8 encoding.
3043  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3044  *           to compare on ASCII based substring.
3045  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3046  *           strings within the parser.
3047  *   CURRENT Returns the current char value, with the full decoding of
3048  *           UTF-8 if we are using this mode. It returns an int.
3049  *   NEXT    Skip to the next character, this does the proper decoding
3050  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3051  *           It returns the pointer to the current xmlChar.
3052  */
3053
3054 #define CUR (*ctxt->cur)
3055 #define SKIP(val) ctxt->cur += (val)
3056 #define NXT(val) ctxt->cur[(val)]
3057 #define CUR_PTR ctxt->cur
3058 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3059
3060 #define COPY_BUF(l,b,i,v)                                              \
3061     if (l == 1) b[i++] = (xmlChar) v;                                  \
3062     else i += xmlCopyChar(l,&b[i],v)
3063
3064 #define NEXTL(l)  ctxt->cur += l
3065
3066 #define SKIP_BLANKS                                                     \
3067     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3068
3069 #define CURRENT (*ctxt->cur)
3070 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3071
3072
3073 #ifndef DBL_DIG
3074 #define DBL_DIG 16
3075 #endif
3076 #ifndef DBL_EPSILON
3077 #define DBL_EPSILON 1E-9
3078 #endif
3079
3080 #define UPPER_DOUBLE 1E9
3081 #define LOWER_DOUBLE 1E-5
3082 #define LOWER_DOUBLE_EXP 5
3083
3084 #define INTEGER_DIGITS DBL_DIG
3085 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3086 #define EXPONENT_DIGITS (3 + 2)
3087
3088 /**
3089  * xmlXPathFormatNumber:
3090  * @number:     number to format
3091  * @buffer:     output buffer
3092  * @buffersize: size of output buffer
3093  *
3094  * Convert the number into a string representation.
3095  */
3096 static void
3097 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3098 {
3099     switch (xmlXPathIsInf(number)) {
3100     case 1:
3101         if (buffersize > (int)sizeof("Infinity"))
3102             snprintf(buffer, buffersize, "Infinity");
3103         break;
3104     case -1:
3105         if (buffersize > (int)sizeof("-Infinity"))
3106             snprintf(buffer, buffersize, "-Infinity");
3107         break;
3108     default:
3109         if (xmlXPathIsNaN(number)) {
3110             if (buffersize > (int)sizeof("NaN"))
3111                 snprintf(buffer, buffersize, "NaN");
3112         } else if (number == 0 && xmlXPathGetSign(number) != 0) {
3113             snprintf(buffer, buffersize, "0");
3114         } else if ((number > INT_MIN) && (number < INT_MAX) &&
3115                    (number == (int) number)) {
3116             char work[30];
3117             char *ptr, *cur;
3118             int value = (int) number;
3119
3120             ptr = &buffer[0];
3121             if (value == 0) {
3122                 *ptr++ = '0';
3123             } else {
3124                 snprintf(work, 29, "%d", value);
3125                 cur = &work[0];
3126                 while ((*cur) && (ptr - buffer < buffersize)) {
3127                     *ptr++ = *cur++;
3128                 }
3129             }
3130             if (ptr - buffer < buffersize) {
3131                 *ptr = 0;
3132             } else if (buffersize > 0) {
3133                 ptr--;
3134                 *ptr = 0;
3135             }
3136         } else {
3137             /*
3138               For the dimension of work,
3139                   DBL_DIG is number of significant digits
3140                   EXPONENT is only needed for "scientific notation"
3141                   3 is sign, decimal point, and terminating zero
3142                   LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3143               Note that this dimension is slightly (a few characters)
3144               larger than actually necessary.
3145             */
3146             char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3147             int integer_place, fraction_place;
3148             char *ptr;
3149             char *after_fraction;
3150             double absolute_value;
3151             int size;
3152
3153             absolute_value = fabs(number);
3154
3155             /*
3156              * First choose format - scientific or regular floating point.
3157              * In either case, result is in work, and after_fraction points
3158              * just past the fractional part.
3159             */
3160             if ( ((absolute_value > UPPER_DOUBLE) ||
3161                   (absolute_value < LOWER_DOUBLE)) &&
3162                  (absolute_value != 0.0) ) {
3163                 /* Use scientific notation */
3164                 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3165                 fraction_place = DBL_DIG - 1;
3166                 size = snprintf(work, sizeof(work),"%*.*e",
3167                          integer_place, fraction_place, number);
3168                 while ((size > 0) && (work[size] != 'e')) size--;
3169
3170             }
3171             else {
3172                 /* Use regular notation */
3173                 if (absolute_value > 0.0) {
3174                     integer_place = (int)log10(absolute_value);
3175                     if (integer_place > 0)
3176                         fraction_place = DBL_DIG - integer_place - 1;
3177                     else
3178                         fraction_place = DBL_DIG - integer_place;
3179                 } else {
3180                     fraction_place = 1;
3181                 }
3182                 size = snprintf(work, sizeof(work), "%0.*f",
3183                                 fraction_place, number);
3184             }
3185
3186             /* Remove leading spaces sometimes inserted by snprintf */
3187             while (work[0] == ' ') {
3188                 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3189                 size--;
3190             }
3191
3192             /* Remove fractional trailing zeroes */
3193             after_fraction = work + size;
3194             ptr = after_fraction;
3195             while (*(--ptr) == '0')
3196                 ;
3197             if (*ptr != '.')
3198                 ptr++;
3199             while ((*ptr++ = *after_fraction++) != 0);
3200
3201             /* Finally copy result back to caller */
3202             size = strlen(work) + 1;
3203             if (size > buffersize) {
3204                 work[buffersize - 1] = 0;
3205                 size = buffersize;
3206             }
3207             memmove(buffer, work, size);
3208         }
3209         break;
3210     }
3211 }
3212
3213
3214 /************************************************************************
3215  *                                                                      *
3216  *                      Routines to handle NodeSets                     *
3217  *                                                                      *
3218  ************************************************************************/
3219
3220 /**
3221  * xmlXPathOrderDocElems:
3222  * @doc:  an input document
3223  *
3224  * Call this routine to speed up XPath computation on static documents.
3225  * This stamps all the element nodes with the document order
3226  * Like for line information, the order is kept in the element->content
3227  * field, the value stored is actually - the node number (starting at -1)
3228  * to be able to differentiate from line numbers.
3229  *
3230  * Returns the number of elements found in the document or -1 in case
3231  *    of error.
3232  */
3233 long
3234 xmlXPathOrderDocElems(xmlDocPtr doc) {
3235     long count = 0;
3236     xmlNodePtr cur;
3237
3238     if (doc == NULL)
3239         return(-1);
3240     cur = doc->children;
3241     while (cur != NULL) {
3242         if (cur->type == XML_ELEMENT_NODE) {
3243             cur->content = (void *) (-(++count));
3244             if (cur->children != NULL) {
3245                 cur = cur->children;
3246                 continue;
3247             }
3248         }
3249         if (cur->next != NULL) {
3250             cur = cur->next;
3251             continue;
3252         }
3253         do {
3254             cur = cur->parent;
3255             if (cur == NULL)
3256                 break;
3257             if (cur == (xmlNodePtr) doc) {
3258                 cur = NULL;
3259                 break;
3260             }
3261             if (cur->next != NULL) {
3262                 cur = cur->next;
3263                 break;
3264             }
3265         } while (cur != NULL);
3266     }
3267     return(count);
3268 }
3269
3270 /**
3271  * xmlXPathCmpNodes:
3272  * @node1:  the first node
3273  * @node2:  the second node
3274  *
3275  * Compare two nodes w.r.t document order
3276  *
3277  * Returns -2 in case of error 1 if first point < second point, 0 if
3278  *         it's the same node, -1 otherwise
3279  */
3280 int
3281 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3282     int depth1, depth2;
3283     int attr1 = 0, attr2 = 0;
3284     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3285     xmlNodePtr cur, root;
3286
3287     if ((node1 == NULL) || (node2 == NULL))
3288         return(-2);
3289     /*
3290      * a couple of optimizations which will avoid computations in most cases
3291      */
3292     if (node1 == node2)         /* trivial case */
3293         return(0);
3294     if (node1->type == XML_ATTRIBUTE_NODE) {
3295         attr1 = 1;
3296         attrNode1 = node1;
3297         node1 = node1->parent;
3298     }
3299     if (node2->type == XML_ATTRIBUTE_NODE) {
3300         attr2 = 1;
3301         attrNode2 = node2;
3302         node2 = node2->parent;
3303     }
3304     if (node1 == node2) {
3305         if (attr1 == attr2) {
3306             /* not required, but we keep attributes in order */
3307             if (attr1 != 0) {
3308                 cur = attrNode2->prev;
3309                 while (cur != NULL) {
3310                     if (cur == attrNode1)
3311                         return (1);
3312                     cur = cur->prev;
3313                 }
3314                 return (-1);
3315             }
3316             return(0);
3317         }
3318         if (attr2 == 1)
3319             return(1);
3320         return(-1);
3321     }
3322     if ((node1->type == XML_NAMESPACE_DECL) ||
3323         (node2->type == XML_NAMESPACE_DECL))
3324         return(1);
3325     if (node1 == node2->prev)
3326         return(1);
3327     if (node1 == node2->next)
3328         return(-1);
3329
3330     /*
3331      * Speedup using document order if availble.
3332      */
3333     if ((node1->type == XML_ELEMENT_NODE) &&
3334         (node2->type == XML_ELEMENT_NODE) &&
3335         (0 > (long) node1->content) &&
3336         (0 > (long) node2->content) &&
3337         (node1->doc == node2->doc)) {
3338         long l1, l2;
3339
3340         l1 = -((long) node1->content);
3341         l2 = -((long) node2->content);
3342         if (l1 < l2)
3343             return(1);
3344         if (l1 > l2)
3345             return(-1);
3346     }
3347
3348     /*
3349      * compute depth to root
3350      */
3351     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3352         if (cur->parent == node1)
3353             return(1);
3354         depth2++;
3355     }
3356     root = cur;
3357     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3358         if (cur->parent == node2)
3359             return(-1);
3360         depth1++;
3361     }
3362     /*
3363      * Distinct document (or distinct entities :-( ) case.
3364      */
3365     if (root != cur) {
3366         return(-2);
3367     }
3368     /*
3369      * get the nearest common ancestor.
3370      */
3371     while (depth1 > depth2) {
3372         depth1--;
3373         node1 = node1->parent;
3374     }
3375     while (depth2 > depth1) {
3376         depth2--;
3377         node2 = node2->parent;
3378     }
3379     while (node1->parent != node2->parent) {
3380         node1 = node1->parent;
3381         node2 = node2->parent;
3382         /* should not happen but just in case ... */
3383         if ((node1 == NULL) || (node2 == NULL))
3384             return(-2);
3385     }
3386     /*
3387      * Find who's first.
3388      */
3389     if (node1 == node2->prev)
3390         return(1);
3391     if (node1 == node2->next)
3392         return(-1);
3393     /*
3394      * Speedup using document order if availble.
3395      */
3396     if ((node1->type == XML_ELEMENT_NODE) &&
3397         (node2->type == XML_ELEMENT_NODE) &&
3398         (0 > (long) node1->content) &&
3399         (0 > (long) node2->content) &&
3400         (node1->doc == node2->doc)) {
3401         long l1, l2;
3402
3403         l1 = -((long) node1->content);
3404         l2 = -((long) node2->content);
3405         if (l1 < l2)
3406             return(1);
3407         if (l1 > l2)
3408             return(-1);
3409     }
3410
3411     for (cur = node1->next;cur != NULL;cur = cur->next)
3412         if (cur == node2)
3413             return(1);
3414     return(-1); /* assume there is no sibling list corruption */
3415 }
3416
3417 /**
3418  * xmlXPathNodeSetSort:
3419  * @set:  the node set
3420  *
3421  * Sort the node set in document order
3422  */
3423 void
3424 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3425 #ifndef WITH_TIM_SORT
3426     int i, j, incr, len;
3427     xmlNodePtr tmp;
3428 #endif
3429
3430     if (set == NULL)
3431         return;
3432
3433 #ifndef WITH_TIM_SORT
3434     /*
3435      * Use the old Shell's sort implementation to sort the node-set
3436      * Timsort ought to be quite faster
3437      */
3438     len = set->nodeNr;
3439     for (incr = len / 2; incr > 0; incr /= 2) {
3440         for (i = incr; i < len; i++) {
3441             j = i - incr;
3442             while (j >= 0) {
3443 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3444                 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3445                         set->nodeTab[j + incr]) == -1)
3446 #else
3447                 if (xmlXPathCmpNodes(set->nodeTab[j],
3448                         set->nodeTab[j + incr]) == -1)
3449 #endif
3450                 {
3451                     tmp = set->nodeTab[j];
3452                     set->nodeTab[j] = set->nodeTab[j + incr];
3453                     set->nodeTab[j + incr] = tmp;
3454                     j -= incr;
3455                 } else
3456                     break;
3457             }
3458         }
3459     }
3460 #else /* WITH_TIM_SORT */
3461     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3462 #endif /* WITH_TIM_SORT */
3463 }
3464
3465 #define XML_NODESET_DEFAULT     10
3466 /**
3467  * xmlXPathNodeSetDupNs:
3468  * @node:  the parent node of the namespace XPath node
3469  * @ns:  the libxml namespace declaration node.
3470  *
3471  * Namespace node in libxml don't match the XPath semantic. In a node set
3472  * the namespace nodes are duplicated and the next pointer is set to the
3473  * parent node in the XPath semantic.
3474  *
3475  * Returns the newly created object.
3476  */
3477 static xmlNodePtr
3478 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3479     xmlNsPtr cur;
3480
3481     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3482         return(NULL);
3483     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3484         return((xmlNodePtr) ns);
3485
3486     /*
3487      * Allocate a new Namespace and fill the fields.
3488      */
3489     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3490     if (cur == NULL) {
3491         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3492         return(NULL);
3493     }
3494     memset(cur, 0, sizeof(xmlNs));
3495     cur->type = XML_NAMESPACE_DECL;
3496     if (ns->href != NULL)
3497         cur->href = xmlStrdup(ns->href);
3498     if (ns->prefix != NULL)
3499         cur->prefix = xmlStrdup(ns->prefix);
3500     cur->next = (xmlNsPtr) node;
3501     return((xmlNodePtr) cur);
3502 }
3503
3504 /**
3505  * xmlXPathNodeSetFreeNs:
3506  * @ns:  the XPath namespace node found in a nodeset.
3507  *
3508  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3509  * the namespace nodes are duplicated and the next pointer is set to the
3510  * parent node in the XPath semantic. Check if such a node needs to be freed
3511  */
3512 void
3513 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3514     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3515         return;
3516
3517     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3518         if (ns->href != NULL)
3519             xmlFree((xmlChar *)ns->href);
3520         if (ns->prefix != NULL)
3521             xmlFree((xmlChar *)ns->prefix);
3522         xmlFree(ns);
3523     }
3524 }
3525
3526 /**
3527  * xmlXPathNodeSetCreate:
3528  * @val:  an initial xmlNodePtr, or NULL
3529  *
3530  * Create a new xmlNodeSetPtr of type double and of value @val
3531  *
3532  * Returns the newly created object.
3533  */
3534 xmlNodeSetPtr
3535 xmlXPathNodeSetCreate(xmlNodePtr val) {
3536     xmlNodeSetPtr ret;
3537
3538     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3539     if (ret == NULL) {
3540         xmlXPathErrMemory(NULL, "creating nodeset\n");
3541         return(NULL);
3542     }
3543     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3544     if (val != NULL) {
3545         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3546                                              sizeof(xmlNodePtr));
3547         if (ret->nodeTab == NULL) {
3548             xmlXPathErrMemory(NULL, "creating nodeset\n");
3549             xmlFree(ret);
3550             return(NULL);
3551         }
3552         memset(ret->nodeTab, 0 ,
3553                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3554         ret->nodeMax = XML_NODESET_DEFAULT;
3555         if (val->type == XML_NAMESPACE_DECL) {
3556             xmlNsPtr ns = (xmlNsPtr) val;
3557
3558             ret->nodeTab[ret->nodeNr++] =
3559                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3560         } else
3561             ret->nodeTab[ret->nodeNr++] = val;
3562     }
3563     return(ret);
3564 }
3565
3566 /**
3567  * xmlXPathNodeSetCreateSize:
3568  * @size:  the initial size of the set
3569  *
3570  * Create a new xmlNodeSetPtr of type double and of value @val
3571  *
3572  * Returns the newly created object.
3573  */
3574 static xmlNodeSetPtr
3575 xmlXPathNodeSetCreateSize(int size) {
3576     xmlNodeSetPtr ret;
3577
3578     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3579     if (ret == NULL) {
3580         xmlXPathErrMemory(NULL, "creating nodeset\n");
3581         return(NULL);
3582     }
3583     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3584     if (size < XML_NODESET_DEFAULT)
3585         size = XML_NODESET_DEFAULT;
3586     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3587     if (ret->nodeTab == NULL) {
3588         xmlXPathErrMemory(NULL, "creating nodeset\n");
3589         xmlFree(ret);
3590         return(NULL);
3591     }
3592     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3593     ret->nodeMax = size;
3594     return(ret);
3595 }
3596
3597 /**
3598  * xmlXPathNodeSetContains:
3599  * @cur:  the node-set
3600  * @val:  the node
3601  *
3602  * checks whether @cur contains @val
3603  *
3604  * Returns true (1) if @cur contains @val, false (0) otherwise
3605  */
3606 int
3607 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3608     int i;
3609
3610     if ((cur == NULL) || (val == NULL)) return(0);
3611     if (val->type == XML_NAMESPACE_DECL) {
3612         for (i = 0; i < cur->nodeNr; i++) {
3613             if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3614                 xmlNsPtr ns1, ns2;
3615
3616                 ns1 = (xmlNsPtr) val;
3617                 ns2 = (xmlNsPtr) cur->nodeTab[i];
3618                 if (ns1 == ns2)
3619                     return(1);
3620                 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3621                     (xmlStrEqual(ns1->prefix, ns2->prefix)))
3622                     return(1);
3623             }
3624         }
3625     } else {
3626         for (i = 0; i < cur->nodeNr; i++) {
3627             if (cur->nodeTab[i] == val)
3628                 return(1);
3629         }
3630     }
3631     return(0);
3632 }
3633
3634 /**
3635  * xmlXPathNodeSetAddNs:
3636  * @cur:  the initial node set
3637  * @node:  the hosting node
3638  * @ns:  a the namespace node
3639  *
3640  * add a new namespace node to an existing NodeSet
3641  *
3642  * Returns 0 in case of success and -1 in case of error
3643  */
3644 int
3645 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3646     int i;
3647
3648
3649     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3650         (ns->type != XML_NAMESPACE_DECL) ||
3651         (node->type != XML_ELEMENT_NODE))
3652         return(-1);
3653
3654     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3655     /*
3656      * prevent duplicates
3657      */
3658     for (i = 0;i < cur->nodeNr;i++) {
3659         if ((cur->nodeTab[i] != NULL) &&
3660             (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3661             (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3662             (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3663             return(0);
3664     }
3665
3666     /*
3667      * grow the nodeTab if needed
3668      */
3669     if (cur->nodeMax == 0) {
3670         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3671                                              sizeof(xmlNodePtr));
3672         if (cur->nodeTab == NULL) {
3673             xmlXPathErrMemory(NULL, "growing nodeset\n");
3674             return(-1);
3675         }
3676         memset(cur->nodeTab, 0 ,
3677                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3678         cur->nodeMax = XML_NODESET_DEFAULT;
3679     } else if (cur->nodeNr == cur->nodeMax) {
3680         xmlNodePtr *temp;
3681
3682         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3683             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3684             return(-1);
3685         }
3686         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3687                                       sizeof(xmlNodePtr));
3688         if (temp == NULL) {
3689             xmlXPathErrMemory(NULL, "growing nodeset\n");
3690             return(-1);
3691         }
3692         cur->nodeMax *= 2;
3693         cur->nodeTab = temp;
3694     }
3695     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3696     return(0);
3697 }
3698
3699 /**
3700  * xmlXPathNodeSetAdd:
3701  * @cur:  the initial node set
3702  * @val:  a new xmlNodePtr
3703  *
3704  * add a new xmlNodePtr to an existing NodeSet
3705  *
3706  * Returns 0 in case of success, and -1 in case of error
3707  */
3708 int
3709 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3710     int i;
3711
3712     if ((cur == NULL) || (val == NULL)) return(-1);
3713
3714     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3715     /*
3716      * prevent duplicates
3717      */
3718     for (i = 0;i < cur->nodeNr;i++)
3719         if (cur->nodeTab[i] == val) return(0);
3720
3721     /*
3722      * grow the nodeTab if needed
3723      */
3724     if (cur->nodeMax == 0) {
3725         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3726                                              sizeof(xmlNodePtr));
3727         if (cur->nodeTab == NULL) {
3728             xmlXPathErrMemory(NULL, "growing nodeset\n");
3729             return(-1);
3730         }
3731         memset(cur->nodeTab, 0 ,
3732                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3733         cur->nodeMax = XML_NODESET_DEFAULT;
3734     } else if (cur->nodeNr == cur->nodeMax) {
3735         xmlNodePtr *temp;
3736
3737         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3738             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3739             return(-1);
3740         }
3741         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3742                                       sizeof(xmlNodePtr));
3743         if (temp == NULL) {
3744             xmlXPathErrMemory(NULL, "growing nodeset\n");
3745             return(-1);
3746         }
3747         cur->nodeMax *= 2;
3748         cur->nodeTab = temp;
3749     }
3750     if (val->type == XML_NAMESPACE_DECL) {
3751         xmlNsPtr ns = (xmlNsPtr) val;
3752
3753         cur->nodeTab[cur->nodeNr++] =
3754             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3755     } else
3756         cur->nodeTab[cur->nodeNr++] = val;
3757     return(0);
3758 }
3759
3760 /**
3761  * xmlXPathNodeSetAddUnique:
3762  * @cur:  the initial node set
3763  * @val:  a new xmlNodePtr
3764  *
3765  * add a new xmlNodePtr to an existing NodeSet, optimized version
3766  * when we are sure the node is not already in the set.
3767  *
3768  * Returns 0 in case of success and -1 in case of failure
3769  */
3770 int
3771 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3772     if ((cur == NULL) || (val == NULL)) return(-1);
3773
3774     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3775     /*
3776      * grow the nodeTab if needed
3777      */
3778     if (cur->nodeMax == 0) {
3779         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3780                                              sizeof(xmlNodePtr));
3781         if (cur->nodeTab == NULL) {
3782             xmlXPathErrMemory(NULL, "growing nodeset\n");
3783             return(-1);
3784         }
3785         memset(cur->nodeTab, 0 ,
3786                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3787         cur->nodeMax = XML_NODESET_DEFAULT;
3788     } else if (cur->nodeNr == cur->nodeMax) {
3789         xmlNodePtr *temp;
3790
3791         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3792             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3793             return(-1);
3794         }
3795         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3796                                       sizeof(xmlNodePtr));
3797         if (temp == NULL) {
3798             xmlXPathErrMemory(NULL, "growing nodeset\n");
3799             return(-1);
3800         }
3801         cur->nodeTab = temp;
3802         cur->nodeMax *= 2;
3803     }
3804     if (val->type == XML_NAMESPACE_DECL) {
3805         xmlNsPtr ns = (xmlNsPtr) val;
3806
3807         cur->nodeTab[cur->nodeNr++] =
3808             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3809     } else
3810         cur->nodeTab[cur->nodeNr++] = val;
3811     return(0);
3812 }
3813
3814 /**
3815  * xmlXPathNodeSetMerge:
3816  * @val1:  the first NodeSet or NULL
3817  * @val2:  the second NodeSet
3818  *
3819  * Merges two nodesets, all nodes from @val2 are added to @val1
3820  * if @val1 is NULL, a new set is created and copied from @val2
3821  *
3822  * Returns @val1 once extended or NULL in case of error.
3823  */
3824 xmlNodeSetPtr
3825 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3826     int i, j, initNr, skip;
3827     xmlNodePtr n1, n2;
3828
3829     if (val2 == NULL) return(val1);
3830     if (val1 == NULL) {
3831         val1 = xmlXPathNodeSetCreate(NULL);
3832     if (val1 == NULL)
3833         return (NULL);
3834 #if 0
3835         /*
3836         * TODO: The optimization won't work in every case, since
3837         *  those nasty namespace nodes need to be added with
3838         *  xmlXPathNodeSetDupNs() to the set; thus a pure
3839         *  memcpy is not possible.
3840         *  If there was a flag on the nodesetval, indicating that
3841         *  some temporary nodes are in, that would be helpfull.
3842         */
3843         /*
3844         * Optimization: Create an equally sized node-set
3845         * and memcpy the content.
3846         */
3847         val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3848         if (val1 == NULL)
3849             return(NULL);
3850         if (val2->nodeNr != 0) {
3851             if (val2->nodeNr == 1)
3852                 *(val1->nodeTab) = *(val2->nodeTab);
3853             else {
3854                 memcpy(val1->nodeTab, val2->nodeTab,
3855                     val2->nodeNr * sizeof(xmlNodePtr));
3856             }
3857             val1->nodeNr = val2->nodeNr;
3858         }
3859         return(val1);
3860 #endif
3861     }
3862
3863     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3864     initNr = val1->nodeNr;
3865
3866     for (i = 0;i < val2->nodeNr;i++) {
3867         n2 = val2->nodeTab[i];
3868         /*
3869          * check against duplicates
3870          */
3871         skip = 0;
3872         for (j = 0; j < initNr; j++) {
3873             n1 = val1->nodeTab[j];
3874             if (n1 == n2) {
3875                 skip = 1;
3876                 break;
3877             } else if ((n1->type == XML_NAMESPACE_DECL) &&
3878                        (n2->type == XML_NAMESPACE_DECL)) {
3879                 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3880                     (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3881                         ((xmlNsPtr) n2)->prefix)))
3882                 {
3883                     skip = 1;
3884                     break;
3885                 }
3886             }
3887         }
3888         if (skip)
3889             continue;
3890
3891         /*
3892          * grow the nodeTab if needed
3893          */
3894         if (val1->nodeMax == 0) {
3895             val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3896                                                     sizeof(xmlNodePtr));
3897             if (val1->nodeTab == NULL) {
3898                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3899                 return(NULL);
3900             }
3901             memset(val1->nodeTab, 0 ,
3902                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3903             val1->nodeMax = XML_NODESET_DEFAULT;
3904         } else if (val1->nodeNr == val1->nodeMax) {
3905             xmlNodePtr *temp;
3906
3907             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3908                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3909                 return(NULL);
3910             }
3911             temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3912                                              sizeof(xmlNodePtr));
3913             if (temp == NULL) {
3914                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3915                 return(NULL);
3916             }
3917             val1->nodeTab = temp;
3918             val1->nodeMax *= 2;
3919         }
3920         if (n2->type == XML_NAMESPACE_DECL) {
3921             xmlNsPtr ns = (xmlNsPtr) n2;
3922
3923             val1->nodeTab[val1->nodeNr++] =
3924                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3925         } else
3926             val1->nodeTab[val1->nodeNr++] = n2;
3927     }
3928
3929     return(val1);
3930 }
3931
3932
3933 /**
3934  * xmlXPathNodeSetMergeAndClear:
3935  * @set1:  the first NodeSet or NULL
3936  * @set2:  the second NodeSet
3937  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3938  *
3939  * Merges two nodesets, all nodes from @set2 are added to @set1
3940  * if @set1 is NULL, a new set is created and copied from @set2.
3941  * Checks for duplicate nodes. Clears set2.
3942  *
3943  * Returns @set1 once extended or NULL in case of error.
3944  */
3945 static xmlNodeSetPtr
3946 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3947                              int hasNullEntries)
3948 {
3949     if ((set1 == NULL) && (hasNullEntries == 0)) {
3950         /*
3951         * Note that doing a memcpy of the list, namespace nodes are
3952         * just assigned to set1, since set2 is cleared anyway.
3953         */
3954         set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3955         if (set1 == NULL)
3956             return(NULL);
3957         if (set2->nodeNr != 0) {
3958             memcpy(set1->nodeTab, set2->nodeTab,
3959                 set2->nodeNr * sizeof(xmlNodePtr));
3960             set1->nodeNr = set2->nodeNr;
3961         }
3962     } else {
3963         int i, j, initNbSet1;
3964         xmlNodePtr n1, n2;
3965
3966         if (set1 == NULL)
3967             set1 = xmlXPathNodeSetCreate(NULL);
3968         if (set1 == NULL)
3969             return (NULL);
3970
3971         initNbSet1 = set1->nodeNr;
3972         for (i = 0;i < set2->nodeNr;i++) {
3973             n2 = set2->nodeTab[i];
3974             /*
3975             * Skip NULLed entries.
3976             */
3977             if (n2 == NULL)
3978                 continue;
3979             /*
3980             * Skip duplicates.
3981             */
3982             for (j = 0; j < initNbSet1; j++) {
3983                 n1 = set1->nodeTab[j];
3984                 if (n1 == n2) {
3985                     goto skip_node;
3986                 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3987                     (n2->type == XML_NAMESPACE_DECL))
3988                 {
3989                     if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3990                         (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3991                         ((xmlNsPtr) n2)->prefix)))
3992                     {
3993                         /*
3994                         * Free the namespace node.
3995                         */
3996                         set2->nodeTab[i] = NULL;
3997                         xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3998                         goto skip_node;
3999                     }
4000                 }
4001             }
4002             /*
4003             * grow the nodeTab if needed
4004             */
4005             if (set1->nodeMax == 0) {
4006                 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4007                     XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4008                 if (set1->nodeTab == NULL) {
4009                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4010                     return(NULL);
4011                 }
4012                 memset(set1->nodeTab, 0,
4013                     XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4014                 set1->nodeMax = XML_NODESET_DEFAULT;
4015             } else if (set1->nodeNr >= set1->nodeMax) {
4016                 xmlNodePtr *temp;
4017
4018                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4019                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4020                     return(NULL);
4021                 }
4022                 temp = (xmlNodePtr *) xmlRealloc(
4023                     set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4024                 if (temp == NULL) {
4025                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4026                     return(NULL);
4027                 }
4028                 set1->nodeTab = temp;
4029                 set1->nodeMax *= 2;
4030             }
4031             set1->nodeTab[set1->nodeNr++] = n2;
4032 skip_node:
4033             {}
4034         }
4035     }
4036     set2->nodeNr = 0;
4037     return(set1);
4038 }
4039
4040 /**
4041  * xmlXPathNodeSetMergeAndClearNoDupls:
4042  * @set1:  the first NodeSet or NULL
4043  * @set2:  the second NodeSet
4044  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4045  *
4046  * Merges two nodesets, all nodes from @set2 are added to @set1
4047  * if @set1 is NULL, a new set is created and copied from @set2.
4048  * Doesn't chack for duplicate nodes. Clears set2.
4049  *
4050  * Returns @set1 once extended or NULL in case of error.
4051  */
4052 static xmlNodeSetPtr
4053 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4054                                     int hasNullEntries)
4055 {
4056     if (set2 == NULL)
4057         return(set1);
4058     if ((set1 == NULL) && (hasNullEntries == 0)) {
4059         /*
4060         * Note that doing a memcpy of the list, namespace nodes are
4061         * just assigned to set1, since set2 is cleared anyway.
4062         */
4063         set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4064         if (set1 == NULL)
4065             return(NULL);
4066         if (set2->nodeNr != 0) {
4067             memcpy(set1->nodeTab, set2->nodeTab,
4068                 set2->nodeNr * sizeof(xmlNodePtr));
4069             set1->nodeNr = set2->nodeNr;
4070         }
4071     } else {
4072         int i;
4073         xmlNodePtr n2;
4074
4075         if (set1 == NULL)
4076             set1 = xmlXPathNodeSetCreate(NULL);
4077         if (set1 == NULL)
4078             return (NULL);
4079
4080         for (i = 0;i < set2->nodeNr;i++) {
4081             n2 = set2->nodeTab[i];
4082             /*
4083             * Skip NULLed entries.
4084             */
4085             if (n2 == NULL)
4086                 continue;
4087             if (set1->nodeMax == 0) {
4088                 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4089                     XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4090                 if (set1->nodeTab == NULL) {
4091                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4092                     return(NULL);
4093                 }
4094                 memset(set1->nodeTab, 0,
4095                     XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4096                 set1->nodeMax = XML_NODESET_DEFAULT;
4097             } else if (set1->nodeNr >= set1->nodeMax) {
4098                 xmlNodePtr *temp;
4099
4100                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4101                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4102                     return(NULL);
4103                 }
4104                 temp = (xmlNodePtr *) xmlRealloc(
4105                     set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4106                 if (temp == NULL) {
4107                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4108                     return(NULL);
4109                 }
4110                 set1->nodeTab = temp;
4111                 set1->nodeMax *= 2;
4112             }
4113             set1->nodeTab[set1->nodeNr++] = n2;
4114         }
4115     }
4116     set2->nodeNr = 0;
4117     return(set1);
4118 }
4119
4120 /**
4121  * xmlXPathNodeSetDel:
4122  * @cur:  the initial node set
4123  * @val:  an xmlNodePtr
4124  *
4125  * Removes an xmlNodePtr from an existing NodeSet
4126  */
4127 void
4128 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4129     int i;
4130
4131     if (cur == NULL) return;
4132     if (val == NULL) return;
4133
4134     /*
4135      * find node in nodeTab
4136      */
4137     for (i = 0;i < cur->nodeNr;i++)
4138         if (cur->nodeTab[i] == val) break;
4139
4140     if (i >= cur->nodeNr) {     /* not found */
4141 #ifdef DEBUG
4142         xmlGenericError(xmlGenericErrorContext,
4143                 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4144                 val->name);
4145 #endif
4146         return;
4147     }
4148     if ((cur->nodeTab[i] != NULL) &&
4149         (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4150         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4151     cur->nodeNr--;
4152     for (;i < cur->nodeNr;i++)
4153         cur->nodeTab[i] = cur->nodeTab[i + 1];
4154     cur->nodeTab[cur->nodeNr] = NULL;
4155 }
4156
4157 /**
4158  * xmlXPathNodeSetRemove:
4159  * @cur:  the initial node set
4160  * @val:  the index to remove
4161  *
4162  * Removes an entry from an existing NodeSet list.
4163  */
4164 void
4165 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4166     if (cur == NULL) return;
4167     if (val >= cur->nodeNr) return;
4168     if ((cur->nodeTab[val] != NULL) &&
4169         (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4170         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4171     cur->nodeNr--;
4172     for (;val < cur->nodeNr;val++)
4173         cur->nodeTab[val] = cur->nodeTab[val + 1];
4174     cur->nodeTab[cur->nodeNr] = NULL;
4175 }
4176
4177 /**
4178  * xmlXPathFreeNodeSet:
4179  * @obj:  the xmlNodeSetPtr to free
4180  *
4181  * Free the NodeSet compound (not the actual nodes !).
4182  */
4183 void
4184 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4185     if (obj == NULL) return;
4186     if (obj->nodeTab != NULL) {
4187         int i;
4188
4189         /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4190         for (i = 0;i < obj->nodeNr;i++)
4191             if ((obj->nodeTab[i] != NULL) &&
4192                 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4193                 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4194         xmlFree(obj->nodeTab);
4195     }
4196     xmlFree(obj);
4197 }
4198
4199 /**
4200  * xmlXPathNodeSetClearFromPos:
4201  * @set: the node set to be cleared
4202  * @pos: the start position to clear from
4203  *
4204  * Clears the list from temporary XPath objects (e.g. namespace nodes
4205  * are feed) starting with the entry at @pos, but does *not* free the list
4206  * itself. Sets the length of the list to @pos.
4207  */
4208 static void
4209 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4210 {
4211     if ((set == NULL) || (pos >= set->nodeNr))
4212         return;
4213     else if ((hasNsNodes)) {
4214         int i;
4215         xmlNodePtr node;
4216
4217         for (i = pos; i < set->nodeNr; i++) {
4218             node = set->nodeTab[i];
4219             if ((node != NULL) &&
4220                 (node->type == XML_NAMESPACE_DECL))
4221                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4222         }
4223     }
4224     set->nodeNr = pos;
4225 }
4226
4227 /**
4228  * xmlXPathNodeSetClear:
4229  * @set:  the node set to clear
4230  *
4231  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4232  * are feed), but does *not* free the list itself. Sets the length of the
4233  * list to 0.
4234  */
4235 static void
4236 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4237 {
4238     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4239 }
4240
4241 /**
4242  * xmlXPathNodeSetKeepLast:
4243  * @set: the node set to be cleared
4244  *
4245  * Move the last node to the first position and clear temporary XPath objects
4246  * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4247  * to 1.
4248  */
4249 static void
4250 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4251 {
4252     int i;
4253     xmlNodePtr node;
4254
4255     if ((set == NULL) || (set->nodeNr <= 1))
4256         return;
4257     for (i = 0; i < set->nodeNr - 1; i++) {
4258         node = set->nodeTab[i];
4259         if ((node != NULL) &&
4260             (node->type == XML_NAMESPACE_DECL))
4261             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4262     }
4263     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4264     set->nodeNr = 1;
4265 }
4266
4267 /**
4268  * xmlXPathFreeValueTree:
4269  * @obj:  the xmlNodeSetPtr to free
4270  *
4271  * Free the NodeSet compound and the actual tree, this is different
4272  * from xmlXPathFreeNodeSet()
4273  */
4274 static void
4275 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4276     int i;
4277
4278     if (obj == NULL) return;
4279
4280     if (obj->nodeTab != NULL) {
4281         for (i = 0;i < obj->nodeNr;i++) {
4282             if (obj->nodeTab[i] != NULL) {
4283                 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4284                     xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4285                 } else {
4286                     xmlFreeNodeList(obj->nodeTab[i]);
4287                 }
4288             }
4289         }
4290         xmlFree(obj->nodeTab);
4291     }
4292     xmlFree(obj);
4293 }
4294
4295 #if defined(DEBUG) || defined(DEBUG_STEP)
4296 /**
4297  * xmlGenericErrorContextNodeSet:
4298  * @output:  a FILE * for the output
4299  * @obj:  the xmlNodeSetPtr to display
4300  *
4301  * Quick display of a NodeSet
4302  */
4303 void
4304 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4305     int i;
4306
4307     if (output == NULL) output = xmlGenericErrorContext;
4308     if (obj == NULL)  {
4309         fprintf(output, "NodeSet == NULL !\n");
4310         return;
4311     }
4312     if (obj->nodeNr == 0) {
4313         fprintf(output, "NodeSet is empty\n");
4314         return;
4315     }
4316     if (obj->nodeTab == NULL) {
4317         fprintf(output, " nodeTab == NULL !\n");
4318         return;
4319     }
4320     for (i = 0; i < obj->nodeNr; i++) {
4321         if (obj->nodeTab[i] == NULL) {
4322             fprintf(output, " NULL !\n");
4323             return;
4324         }
4325         if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4326             (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4327             fprintf(output, " /");
4328         else if (obj->nodeTab[i]->name == NULL)
4329             fprintf(output, " noname!");
4330         else fprintf(output, " %s", obj->nodeTab[i]->name);
4331     }
4332     fprintf(output, "\n");
4333 }
4334 #endif
4335
4336 /**
4337  * xmlXPathNewNodeSet:
4338  * @val:  the NodePtr value
4339  *
4340  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4341  * it with the single Node @val
4342  *
4343  * Returns the newly created object.
4344  */
4345 xmlXPathObjectPtr
4346 xmlXPathNewNodeSet(xmlNodePtr val) {
4347     xmlXPathObjectPtr ret;
4348
4349     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4350     if (ret == NULL) {
4351         xmlXPathErrMemory(NULL, "creating nodeset\n");
4352         return(NULL);
4353     }
4354     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4355     ret->type = XPATH_NODESET;
4356     ret->boolval = 0;
4357     ret->nodesetval = xmlXPathNodeSetCreate(val);
4358     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4359 #ifdef XP_DEBUG_OBJ_USAGE
4360     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4361 #endif
4362     return(ret);
4363 }
4364
4365 /**
4366  * xmlXPathNewValueTree:
4367  * @val:  the NodePtr value
4368  *
4369  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4370  * it with the tree root @val
4371  *
4372  * Returns the newly created object.
4373  */
4374 xmlXPathObjectPtr
4375 xmlXPathNewValueTree(xmlNodePtr val) {
4376     xmlXPathObjectPtr ret;
4377
4378     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4379     if (ret == NULL) {
4380         xmlXPathErrMemory(NULL, "creating result value tree\n");
4381         return(NULL);
4382     }
4383     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4384     ret->type = XPATH_XSLT_TREE;
4385     ret->boolval = 1;
4386     ret->user = (void *) val;
4387     ret->nodesetval = xmlXPathNodeSetCreate(val);
4388 #ifdef XP_DEBUG_OBJ_USAGE
4389     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4390 #endif
4391     return(ret);
4392 }
4393
4394 /**
4395  * xmlXPathNewNodeSetList:
4396  * @val:  an existing NodeSet
4397  *
4398  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4399  * it with the Nodeset @val
4400  *
4401  * Returns the newly created object.
4402  */
4403 xmlXPathObjectPtr
4404 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4405 {
4406     xmlXPathObjectPtr ret;
4407     int i;
4408
4409     if (val == NULL)
4410         ret = NULL;
4411     else if (val->nodeTab == NULL)
4412         ret = xmlXPathNewNodeSet(NULL);
4413     else {
4414         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4415         if (ret) {
4416             for (i = 1; i < val->nodeNr; ++i) {
4417                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4418                     < 0) break;
4419             }
4420         }
4421     }
4422
4423     return (ret);
4424 }
4425
4426 /**
4427  * xmlXPathWrapNodeSet:
4428  * @val:  the NodePtr value
4429  *
4430  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4431  *
4432  * Returns the newly created object.
4433  */
4434 xmlXPathObjectPtr
4435 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4436     xmlXPathObjectPtr ret;
4437
4438     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4439     if (ret == NULL) {
4440         xmlXPathErrMemory(NULL, "creating node set object\n");
4441         return(NULL);
4442     }
4443     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4444     ret->type = XPATH_NODESET;
4445     ret->nodesetval = val;
4446 #ifdef XP_DEBUG_OBJ_USAGE
4447     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4448 #endif
4449     return(ret);
4450 }
4451
4452 /**
4453  * xmlXPathFreeNodeSetList:
4454  * @obj:  an existing NodeSetList object
4455  *
4456  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4457  * the list contrary to xmlXPathFreeObject().
4458  */
4459 void
4460 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4461     if (obj == NULL) return;
4462 #ifdef XP_DEBUG_OBJ_USAGE
4463     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4464 #endif
4465     xmlFree(obj);
4466 }
4467
4468 /**
4469  * xmlXPathDifference:
4470  * @nodes1:  a node-set
4471  * @nodes2:  a node-set
4472  *
4473  * Implements the EXSLT - Sets difference() function:
4474  *    node-set set:difference (node-set, node-set)
4475  *
4476  * Returns the difference between the two node sets, or nodes1 if
4477  *         nodes2 is empty
4478  */
4479 xmlNodeSetPtr
4480 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4481     xmlNodeSetPtr ret;
4482     int i, l1;
4483     xmlNodePtr cur;
4484
4485     if (xmlXPathNodeSetIsEmpty(nodes2))
4486         return(nodes1);
4487
4488     ret = xmlXPathNodeSetCreate(NULL);
4489     if (xmlXPathNodeSetIsEmpty(nodes1))
4490         return(ret);
4491
4492     l1 = xmlXPathNodeSetGetLength(nodes1);
4493
4494     for (i = 0; i < l1; i++) {
4495         cur = xmlXPathNodeSetItem(nodes1, i);
4496         if (!xmlXPathNodeSetContains(nodes2, cur)) {
4497             if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4498                 break;
4499         }
4500     }
4501     return(ret);
4502 }
4503
4504 /**
4505  * xmlXPathIntersection:
4506  * @nodes1:  a node-set
4507  * @nodes2:  a node-set
4508  *
4509  * Implements the EXSLT - Sets intersection() function:
4510  *    node-set set:intersection (node-set, node-set)
4511  *
4512  * Returns a node set comprising the nodes that are within both the
4513  *         node sets passed as arguments
4514  */
4515 xmlNodeSetPtr
4516 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4517     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4518     int i, l1;
4519     xmlNodePtr cur;
4520
4521     if (ret == NULL)
4522         return(ret);
4523     if (xmlXPathNodeSetIsEmpty(nodes1))
4524         return(ret);
4525     if (xmlXPathNodeSetIsEmpty(nodes2))
4526         return(ret);
4527
4528     l1 = xmlXPathNodeSetGetLength(nodes1);
4529
4530     for (i = 0; i < l1; i++) {
4531         cur = xmlXPathNodeSetItem(nodes1, i);
4532         if (xmlXPathNodeSetContains(nodes2, cur)) {
4533             if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4534                 break;
4535         }
4536     }
4537     return(ret);
4538 }
4539
4540 /**
4541  * xmlXPathDistinctSorted:
4542  * @nodes:  a node-set, sorted by document order
4543  *
4544  * Implements the EXSLT - Sets distinct() function:
4545  *    node-set set:distinct (node-set)
4546  *
4547  * Returns a subset of the nodes contained in @nodes, or @nodes if
4548  *         it is empty
4549  */
4550 xmlNodeSetPtr
4551 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4552     xmlNodeSetPtr ret;
4553     xmlHashTablePtr hash;
4554     int i, l;
4555     xmlChar * strval;
4556     xmlNodePtr cur;
4557
4558     if (xmlXPathNodeSetIsEmpty(nodes))
4559         return(nodes);
4560
4561     ret = xmlXPathNodeSetCreate(NULL);
4562     if (ret == NULL)
4563         return(ret);
4564     l = xmlXPathNodeSetGetLength(nodes);
4565     hash = xmlHashCreate (l);
4566     for (i = 0; i < l; i++) {
4567         cur = xmlXPathNodeSetItem(nodes, i);
4568         strval = xmlXPathCastNodeToString(cur);
4569         if (xmlHashLookup(hash, strval) == NULL) {
4570             xmlHashAddEntry(hash, strval, strval);
4571             if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4572                 break;
4573         } else {
4574             xmlFree(strval);
4575         }
4576     }
4577     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4578     return(ret);
4579 }
4580
4581 /**
4582  * xmlXPathDistinct:
4583  * @nodes:  a node-set
4584  *
4585  * Implements the EXSLT - Sets distinct() function:
4586  *    node-set set:distinct (node-set)
4587  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4588  * is called with the sorted node-set
4589  *
4590  * Returns a subset of the nodes contained in @nodes, or @nodes if
4591  *         it is empty
4592  */
4593 xmlNodeSetPtr
4594 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4595     if (xmlXPathNodeSetIsEmpty(nodes))
4596         return(nodes);
4597
4598     xmlXPathNodeSetSort(nodes);
4599     return(xmlXPathDistinctSorted(nodes));
4600 }
4601
4602 /**
4603  * xmlXPathHasSameNodes:
4604  * @nodes1:  a node-set
4605  * @nodes2:  a node-set
4606  *
4607  * Implements the EXSLT - Sets has-same-nodes function:
4608  *    boolean set:has-same-node(node-set, node-set)
4609  *
4610  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4611  *         otherwise
4612  */
4613 int
4614 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4615     int i, l;
4616     xmlNodePtr cur;
4617
4618     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4619         xmlXPathNodeSetIsEmpty(nodes2))
4620         return(0);
4621
4622     l = xmlXPathNodeSetGetLength(nodes1);
4623     for (i = 0; i < l; i++) {
4624         cur = xmlXPathNodeSetItem(nodes1, i);
4625         if (xmlXPathNodeSetContains(nodes2, cur))
4626             return(1);
4627     }
4628     return(0);
4629 }
4630
4631 /**
4632  * xmlXPathNodeLeadingSorted:
4633  * @nodes: a node-set, sorted by document order
4634  * @node: a node
4635  *
4636  * Implements the EXSLT - Sets leading() function:
4637  *    node-set set:leading (node-set, node-set)
4638  *
4639  * Returns the nodes in @nodes that precede @node in document order,
4640  *         @nodes if @node is NULL or an empty node-set if @nodes
4641  *         doesn't contain @node
4642  */
4643 xmlNodeSetPtr
4644 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4645     int i, l;
4646     xmlNodePtr cur;
4647     xmlNodeSetPtr ret;
4648
4649     if (node == NULL)
4650         return(nodes);
4651
4652     ret = xmlXPathNodeSetCreate(NULL);
4653     if (ret == NULL)
4654         return(ret);
4655     if (xmlXPathNodeSetIsEmpty(nodes) ||
4656         (!xmlXPathNodeSetContains(nodes, node)))
4657         return(ret);
4658
4659     l = xmlXPathNodeSetGetLength(nodes);
4660     for (i = 0; i < l; i++) {
4661         cur = xmlXPathNodeSetItem(nodes, i);
4662         if (cur == node)
4663             break;
4664         if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4665             break;
4666     }
4667     return(ret);
4668 }
4669
4670 /**
4671  * xmlXPathNodeLeading:
4672  * @nodes:  a node-set
4673  * @node:  a node
4674  *
4675  * Implements the EXSLT - Sets leading() function:
4676  *    node-set set:leading (node-set, node-set)
4677  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4678  * is called.
4679  *
4680  * Returns the nodes in @nodes that precede @node in document order,
4681  *         @nodes if @node is NULL or an empty node-set if @nodes
4682  *         doesn't contain @node
4683  */
4684 xmlNodeSetPtr
4685 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4686     xmlXPathNodeSetSort(nodes);
4687     return(xmlXPathNodeLeadingSorted(nodes, node));
4688 }
4689
4690 /**
4691  * xmlXPathLeadingSorted:
4692  * @nodes1:  a node-set, sorted by document order
4693  * @nodes2:  a node-set, sorted by document order
4694  *
4695  * Implements the EXSLT - Sets leading() function:
4696  *    node-set set:leading (node-set, node-set)
4697  *
4698  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4699  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4700  *         an empty node-set if @nodes1 doesn't contain @nodes2
4701  */
4702 xmlNodeSetPtr
4703 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4704     if (xmlXPathNodeSetIsEmpty(nodes2))
4705         return(nodes1);
4706     return(xmlXPathNodeLeadingSorted(nodes1,
4707                                      xmlXPathNodeSetItem(nodes2, 1)));
4708 }
4709
4710 /**
4711  * xmlXPathLeading:
4712  * @nodes1:  a node-set
4713  * @nodes2:  a node-set
4714  *
4715  * Implements the EXSLT - Sets leading() function:
4716  *    node-set set:leading (node-set, node-set)
4717  * @nodes1 and @nodes2 are sorted by document order, then
4718  * #exslSetsLeadingSorted is called.
4719  *
4720  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4721  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4722  *         an empty node-set if @nodes1 doesn't contain @nodes2
4723  */
4724 xmlNodeSetPtr
4725 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4726     if (xmlXPathNodeSetIsEmpty(nodes2))
4727         return(nodes1);
4728     if (xmlXPathNodeSetIsEmpty(nodes1))
4729         return(xmlXPathNodeSetCreate(NULL));
4730     xmlXPathNodeSetSort(nodes1);
4731     xmlXPathNodeSetSort(nodes2);
4732     return(xmlXPathNodeLeadingSorted(nodes1,
4733                                      xmlXPathNodeSetItem(nodes2, 1)));
4734 }
4735
4736 /**
4737  * xmlXPathNodeTrailingSorted:
4738  * @nodes: a node-set, sorted by document order
4739  * @node: a node
4740  *
4741  * Implements the EXSLT - Sets trailing() function:
4742  *    node-set set:trailing (node-set, node-set)
4743  *
4744  * Returns the nodes in @nodes that follow @node in document order,
4745  *         @nodes if @node is NULL or an empty node-set if @nodes
4746  *         doesn't contain @node
4747  */
4748 xmlNodeSetPtr
4749 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4750     int i, l;
4751     xmlNodePtr cur;
4752     xmlNodeSetPtr ret;
4753
4754     if (node == NULL)
4755         return(nodes);
4756
4757     ret = xmlXPathNodeSetCreate(NULL);
4758     if (ret == NULL)
4759         return(ret);
4760     if (xmlXPathNodeSetIsEmpty(nodes) ||
4761         (!xmlXPathNodeSetContains(nodes, node)))
4762         return(ret);
4763
4764     l = xmlXPathNodeSetGetLength(nodes);
4765     for (i = l - 1; i >= 0; i--) {
4766         cur = xmlXPathNodeSetItem(nodes, i);
4767         if (cur == node)
4768             break;
4769         if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4770             break;
4771     }
4772     xmlXPathNodeSetSort(ret);   /* bug 413451 */
4773     return(ret);
4774 }
4775
4776 /**
4777  * xmlXPathNodeTrailing:
4778  * @nodes:  a node-set
4779  * @node:  a node
4780  *
4781  * Implements the EXSLT - Sets trailing() function:
4782  *    node-set set:trailing (node-set, node-set)
4783  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4784  * is called.
4785  *
4786  * Returns the nodes in @nodes that follow @node in document order,
4787  *         @nodes if @node is NULL or an empty node-set if @nodes
4788  *         doesn't contain @node
4789  */
4790 xmlNodeSetPtr
4791 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4792     xmlXPathNodeSetSort(nodes);
4793     return(xmlXPathNodeTrailingSorted(nodes, node));
4794 }
4795
4796 /**
4797  * xmlXPathTrailingSorted:
4798  * @nodes1:  a node-set, sorted by document order
4799  * @nodes2:  a node-set, sorted by document order
4800  *
4801  * Implements the EXSLT - Sets trailing() function:
4802  *    node-set set:trailing (node-set, node-set)
4803  *
4804  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4805  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4806  *         an empty node-set if @nodes1 doesn't contain @nodes2
4807  */
4808 xmlNodeSetPtr
4809 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4810     if (xmlXPathNodeSetIsEmpty(nodes2))
4811         return(nodes1);
4812     return(xmlXPathNodeTrailingSorted(nodes1,
4813                                       xmlXPathNodeSetItem(nodes2, 0)));
4814 }
4815
4816 /**
4817  * xmlXPathTrailing:
4818  * @nodes1:  a node-set
4819  * @nodes2:  a node-set
4820  *
4821  * Implements the EXSLT - Sets trailing() function:
4822  *    node-set set:trailing (node-set, node-set)
4823  * @nodes1 and @nodes2 are sorted by document order, then
4824  * #xmlXPathTrailingSorted is called.
4825  *
4826  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4827  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4828  *         an empty node-set if @nodes1 doesn't contain @nodes2
4829  */
4830 xmlNodeSetPtr
4831 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4832     if (xmlXPathNodeSetIsEmpty(nodes2))
4833         return(nodes1);
4834     if (xmlXPathNodeSetIsEmpty(nodes1))
4835         return(xmlXPathNodeSetCreate(NULL));
4836     xmlXPathNodeSetSort(nodes1);
4837     xmlXPathNodeSetSort(nodes2);
4838     return(xmlXPathNodeTrailingSorted(nodes1,
4839                                       xmlXPathNodeSetItem(nodes2, 0)));
4840 }
4841
4842 /************************************************************************
4843  *                                                                      *
4844  *              Routines to handle extra functions                      *
4845  *                                                                      *
4846  ************************************************************************/
4847
4848 /**
4849  * xmlXPathRegisterFunc:
4850  * @ctxt:  the XPath context
4851  * @name:  the function name
4852  * @f:  the function implementation or NULL
4853  *
4854  * Register a new function. If @f is NULL it unregisters the function
4855  *
4856  * Returns 0 in case of success, -1 in case of error
4857  */
4858 int
4859 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4860                      xmlXPathFunction f) {
4861     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4862 }
4863
4864 /**
4865  * xmlXPathRegisterFuncNS:
4866  * @ctxt:  the XPath context
4867  * @name:  the function name
4868  * @ns_uri:  the function namespace URI
4869  * @f:  the function implementation or NULL
4870  *
4871  * Register a new function. If @f is NULL it unregisters the function
4872  *
4873  * Returns 0 in case of success, -1 in case of error
4874  */
4875 int
4876 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4877                        const xmlChar *ns_uri, xmlXPathFunction f) {
4878     if (ctxt == NULL)
4879         return(-1);
4880     if (name == NULL)
4881         return(-1);
4882
4883     if (ctxt->funcHash == NULL)
4884         ctxt->funcHash = xmlHashCreate(0);
4885     if (ctxt->funcHash == NULL)
4886         return(-1);
4887     if (f == NULL)
4888         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4889     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4890 }
4891
4892 /**
4893  * xmlXPathRegisterFuncLookup:
4894  * @ctxt:  the XPath context
4895  * @f:  the lookup function
4896  * @funcCtxt:  the lookup data
4897  *
4898  * Registers an external mechanism to do function lookup.
4899  */
4900 void
4901 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4902                             xmlXPathFuncLookupFunc f,
4903                             void *funcCtxt) {
4904     if (ctxt == NULL)
4905         return;
4906     ctxt->funcLookupFunc = f;
4907     ctxt->funcLookupData = funcCtxt;
4908 }
4909
4910 /**
4911  * xmlXPathFunctionLookup:
4912  * @ctxt:  the XPath context
4913  * @name:  the function name
4914  *
4915  * Search in the Function array of the context for the given
4916  * function.
4917  *
4918  * Returns the xmlXPathFunction or NULL if not found
4919  */
4920 xmlXPathFunction
4921 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4922     if (ctxt == NULL)
4923         return (NULL);
4924
4925     if (ctxt->funcLookupFunc != NULL) {
4926         xmlXPathFunction ret;
4927         xmlXPathFuncLookupFunc f;
4928
4929         f = ctxt->funcLookupFunc;
4930         ret = f(ctxt->funcLookupData, name, NULL);
4931         if (ret != NULL)
4932             return(ret);
4933     }
4934     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4935 }
4936
4937 /**
4938  * xmlXPathFunctionLookupNS:
4939  * @ctxt:  the XPath context
4940  * @name:  the function name
4941  * @ns_uri:  the function namespace URI
4942  *
4943  * Search in the Function array of the context for the given
4944  * function.
4945  *
4946  * Returns the xmlXPathFunction or NULL if not found
4947  */
4948 xmlXPathFunction
4949 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4950                          const xmlChar *ns_uri) {
4951     xmlXPathFunction ret;
4952
4953     if (ctxt == NULL)
4954         return(NULL);
4955     if (name == NULL)
4956         return(NULL);
4957
4958     if (ctxt->funcLookupFunc != NULL) {
4959         xmlXPathFuncLookupFunc f;
4960
4961         f = ctxt->funcLookupFunc;
4962         ret = f(ctxt->funcLookupData, name, ns_uri);
4963         if (ret != NULL)
4964             return(ret);
4965     }
4966
4967     if (ctxt->funcHash == NULL)
4968         return(NULL);
4969
4970     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4971     return(ret);
4972 }
4973
4974 /**
4975  * xmlXPathRegisteredFuncsCleanup:
4976  * @ctxt:  the XPath context
4977  *
4978  * Cleanup the XPath context data associated to registered functions
4979  */
4980 void
4981 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4982     if (ctxt == NULL)
4983         return;
4984
4985     xmlHashFree(ctxt->funcHash, NULL);
4986     ctxt->funcHash = NULL;
4987 }
4988
4989 /************************************************************************
4990  *                                                                      *
4991  *                      Routines to handle Variables                    *
4992  *                                                                      *
4993  ************************************************************************/
4994
4995 /**
4996  * xmlXPathRegisterVariable:
4997  * @ctxt:  the XPath context
4998  * @name:  the variable name
4999  * @value:  the variable value or NULL
5000  *
5001  * Register a new variable value. If @value is NULL it unregisters
5002  * the variable
5003  *
5004  * Returns 0 in case of success, -1 in case of error
5005  */
5006 int
5007 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5008                          xmlXPathObjectPtr value) {
5009     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5010 }
5011
5012 /**
5013  * xmlXPathRegisterVariableNS:
5014  * @ctxt:  the XPath context
5015  * @name:  the variable name
5016  * @ns_uri:  the variable namespace URI
5017  * @value:  the variable value or NULL
5018  *
5019  * Register a new variable value. If @value is NULL it unregisters
5020  * the variable
5021  *
5022  * Returns 0 in case of success, -1 in case of error
5023  */
5024 int
5025 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5026                            const xmlChar *ns_uri,
5027                            xmlXPathObjectPtr value) {
5028     if (ctxt == NULL)
5029         return(-1);
5030     if (name == NULL)
5031         return(-1);
5032
5033     if (ctxt->varHash == NULL)
5034         ctxt->varHash = xmlHashCreate(0);
5035     if (ctxt->varHash == NULL)
5036         return(-1);
5037     if (value == NULL)
5038         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5039                                    (xmlHashDeallocator)xmlXPathFreeObject));
5040     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5041                                (void *) value,
5042                                (xmlHashDeallocator)xmlXPathFreeObject));
5043 }
5044
5045 /**
5046  * xmlXPathRegisterVariableLookup:
5047  * @ctxt:  the XPath context
5048  * @f:  the lookup function
5049  * @data:  the lookup data
5050  *
5051  * register an external mechanism to do variable lookup
5052  */
5053 void
5054 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5055          xmlXPathVariableLookupFunc f, void *data) {
5056     if (ctxt == NULL)
5057         return;
5058     ctxt->varLookupFunc = f;
5059     ctxt->varLookupData = data;
5060 }
5061
5062 /**
5063  * xmlXPathVariableLookup:
5064  * @ctxt:  the XPath context
5065  * @name:  the variable name
5066  *
5067  * Search in the Variable array of the context for the given
5068  * variable value.
5069  *
5070  * Returns a copy of the value or NULL if not found
5071  */
5072 xmlXPathObjectPtr
5073 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5074     if (ctxt == NULL)
5075         return(NULL);
5076
5077     if (ctxt->varLookupFunc != NULL) {
5078         xmlXPathObjectPtr ret;
5079
5080         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5081                 (ctxt->varLookupData, name, NULL);
5082         return(ret);
5083     }
5084     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5085 }
5086
5087 /**
5088  * xmlXPathVariableLookupNS:
5089  * @ctxt:  the XPath context
5090  * @name:  the variable name
5091  * @ns_uri:  the variable namespace URI
5092  *
5093  * Search in the Variable array of the context for the given
5094  * variable value.
5095  *
5096  * Returns the a copy of the value or NULL if not found
5097  */
5098 xmlXPathObjectPtr
5099 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5100                          const xmlChar *ns_uri) {
5101     if (ctxt == NULL)
5102         return(NULL);
5103
5104     if (ctxt->varLookupFunc != NULL) {
5105         xmlXPathObjectPtr ret;
5106
5107         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5108                 (ctxt->varLookupData, name, ns_uri);
5109         if (ret != NULL) return(ret);
5110     }
5111
5112     if (ctxt->varHash == NULL)
5113         return(NULL);
5114     if (name == NULL)
5115         return(NULL);
5116
5117     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5118                 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5119 }
5120
5121 /**
5122  * xmlXPathRegisteredVariablesCleanup:
5123  * @ctxt:  the XPath context
5124  *
5125  * Cleanup the XPath context data associated to registered variables
5126  */
5127 void
5128 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5129     if (ctxt == NULL)
5130         return;
5131
5132     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5133     ctxt->varHash = NULL;
5134 }
5135
5136 /**
5137  * xmlXPathRegisterNs:
5138  * @ctxt:  the XPath context
5139  * @prefix:  the namespace prefix cannot be NULL or empty string
5140  * @ns_uri:  the namespace name
5141  *
5142  * Register a new namespace. If @ns_uri is NULL it unregisters
5143  * the namespace
5144  *
5145  * Returns 0 in case of success, -1 in case of error
5146  */
5147 int
5148 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5149                            const xmlChar *ns_uri) {
5150     if (ctxt == NULL)
5151         return(-1);
5152     if (prefix == NULL)
5153         return(-1);
5154     if (prefix[0] == 0)
5155         return(-1);
5156
5157     if (ctxt->nsHash == NULL)
5158         ctxt->nsHash = xmlHashCreate(10);
5159     if (ctxt->nsHash == NULL)
5160         return(-1);
5161     if (ns_uri == NULL)
5162         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5163                                   (xmlHashDeallocator)xmlFree));
5164     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5165                               (xmlHashDeallocator)xmlFree));
5166 }
5167
5168 /**
5169  * xmlXPathNsLookup:
5170  * @ctxt:  the XPath context
5171  * @prefix:  the namespace prefix value
5172  *
5173  * Search in the namespace declaration array of the context for the given
5174  * namespace name associated to the given prefix
5175  *
5176  * Returns the value or NULL if not found
5177  */
5178 const xmlChar *
5179 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5180     if (ctxt == NULL)
5181         return(NULL);
5182     if (prefix == NULL)
5183         return(NULL);
5184
5185 #ifdef XML_XML_NAMESPACE
5186     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5187         return(XML_XML_NAMESPACE);
5188 #endif
5189
5190     if (ctxt->namespaces != NULL) {
5191         int i;
5192
5193         for (i = 0;i < ctxt->nsNr;i++) {
5194             if ((ctxt->namespaces[i] != NULL) &&
5195                 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5196                 return(ctxt->namespaces[i]->href);
5197         }
5198     }
5199
5200     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5201 }
5202
5203 /**
5204  * xmlXPathRegisteredNsCleanup:
5205  * @ctxt:  the XPath context
5206  *
5207  * Cleanup the XPath context data associated to registered variables
5208  */
5209 void
5210 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5211     if (ctxt == NULL)
5212         return;
5213
5214     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5215     ctxt->nsHash = NULL;
5216 }
5217
5218 /************************************************************************
5219  *                                                                      *
5220  *                      Routines to handle Values                       *
5221  *                                                                      *
5222  ************************************************************************/
5223
5224 /* Allocations are terrible, one needs to optimize all this !!! */
5225
5226 /**
5227  * xmlXPathNewFloat:
5228  * @val:  the double value
5229  *
5230  * Create a new xmlXPathObjectPtr of type double and of value @val
5231  *
5232  * Returns the newly created object.
5233  */
5234 xmlXPathObjectPtr
5235 xmlXPathNewFloat(double val) {
5236     xmlXPathObjectPtr ret;
5237
5238     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5239     if (ret == NULL) {
5240         xmlXPathErrMemory(NULL, "creating float object\n");
5241         return(NULL);
5242     }
5243     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5244     ret->type = XPATH_NUMBER;
5245     ret->floatval = val;
5246 #ifdef XP_DEBUG_OBJ_USAGE
5247     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5248 #endif
5249     return(ret);
5250 }
5251
5252 /**
5253  * xmlXPathNewBoolean:
5254  * @val:  the boolean value
5255  *
5256  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5257  *
5258  * Returns the newly created object.
5259  */
5260 xmlXPathObjectPtr
5261 xmlXPathNewBoolean(int val) {
5262     xmlXPathObjectPtr ret;
5263
5264     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5265     if (ret == NULL) {
5266         xmlXPathErrMemory(NULL, "creating boolean object\n");
5267         return(NULL);
5268     }
5269     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5270     ret->type = XPATH_BOOLEAN;
5271     ret->boolval = (val != 0);
5272 #ifdef XP_DEBUG_OBJ_USAGE
5273     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5274 #endif
5275     return(ret);
5276 }
5277
5278 /**
5279  * xmlXPathNewString:
5280  * @val:  the xmlChar * value
5281  *
5282  * Create a new xmlXPathObjectPtr of type string and of value @val
5283  *
5284  * Returns the newly created object.
5285  */
5286 xmlXPathObjectPtr
5287 xmlXPathNewString(const xmlChar *val) {
5288     xmlXPathObjectPtr ret;
5289
5290     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5291     if (ret == NULL) {
5292         xmlXPathErrMemory(NULL, "creating string object\n");
5293         return(NULL);
5294     }
5295     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5296     ret->type = XPATH_STRING;
5297     if (val != NULL)
5298         ret->stringval = xmlStrdup(val);
5299     else
5300         ret->stringval = xmlStrdup((const xmlChar *)"");
5301 #ifdef XP_DEBUG_OBJ_USAGE
5302     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5303 #endif
5304     return(ret);
5305 }
5306
5307 /**
5308  * xmlXPathWrapString:
5309  * @val:  the xmlChar * value
5310  *
5311  * Wraps the @val string into an XPath object.
5312  *
5313  * Returns the newly created object.
5314  */
5315 xmlXPathObjectPtr
5316 xmlXPathWrapString (xmlChar *val) {
5317     xmlXPathObjectPtr ret;
5318
5319     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5320     if (ret == NULL) {
5321         xmlXPathErrMemory(NULL, "creating string object\n");
5322         return(NULL);
5323     }
5324     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5325     ret->type = XPATH_STRING;
5326     ret->stringval = val;
5327 #ifdef XP_DEBUG_OBJ_USAGE
5328     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5329 #endif
5330     return(ret);
5331 }
5332
5333 /**
5334  * xmlXPathNewCString:
5335  * @val:  the char * value
5336  *
5337  * Create a new xmlXPathObjectPtr of type string and of value @val
5338  *
5339  * Returns the newly created object.
5340  */
5341 xmlXPathObjectPtr
5342 xmlXPathNewCString(const char *val) {
5343     xmlXPathObjectPtr ret;
5344
5345     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5346     if (ret == NULL) {
5347         xmlXPathErrMemory(NULL, "creating string object\n");
5348         return(NULL);
5349     }
5350     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5351     ret->type = XPATH_STRING;
5352     ret->stringval = xmlStrdup(BAD_CAST val);
5353 #ifdef XP_DEBUG_OBJ_USAGE
5354     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5355 #endif
5356     return(ret);
5357 }
5358
5359 /**
5360  * xmlXPathWrapCString:
5361  * @val:  the char * value
5362  *
5363  * Wraps a string into an XPath object.
5364  *
5365  * Returns the newly created object.
5366  */
5367 xmlXPathObjectPtr
5368 xmlXPathWrapCString (char * val) {
5369     return(xmlXPathWrapString((xmlChar *)(val)));
5370 }
5371
5372 /**
5373  * xmlXPathWrapExternal:
5374  * @val:  the user data
5375  *
5376  * Wraps the @val data into an XPath object.
5377  *
5378  * Returns the newly created object.
5379  */
5380 xmlXPathObjectPtr
5381 xmlXPathWrapExternal (void *val) {
5382     xmlXPathObjectPtr ret;
5383
5384     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5385     if (ret == NULL) {
5386         xmlXPathErrMemory(NULL, "creating user object\n");
5387         return(NULL);
5388     }
5389     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5390     ret->type = XPATH_USERS;
5391     ret->user = val;
5392 #ifdef XP_DEBUG_OBJ_USAGE
5393     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5394 #endif
5395     return(ret);
5396 }
5397
5398 /**
5399  * xmlXPathObjectCopy:
5400  * @val:  the original object
5401  *
5402  * allocate a new copy of a given object
5403  *
5404  * Returns the newly created object.
5405  */
5406 xmlXPathObjectPtr
5407 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5408     xmlXPathObjectPtr ret;
5409
5410     if (val == NULL)
5411         return(NULL);
5412
5413     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5414     if (ret == NULL) {
5415         xmlXPathErrMemory(NULL, "copying object\n");
5416         return(NULL);
5417     }
5418     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5419 #ifdef XP_DEBUG_OBJ_USAGE
5420     xmlXPathDebugObjUsageRequested(NULL, val->type);
5421 #endif
5422     switch (val->type) {
5423         case XPATH_BOOLEAN:
5424         case XPATH_NUMBER:
5425         case XPATH_POINT:
5426         case XPATH_RANGE:
5427             break;
5428         case XPATH_STRING:
5429             ret->stringval = xmlStrdup(val->stringval);
5430             break;
5431         case XPATH_XSLT_TREE:
5432 #if 0
5433 /*
5434   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5435   this previous handling is no longer correct, and can cause some serious
5436   problems (ref. bug 145547)
5437 */
5438             if ((val->nodesetval != NULL) &&
5439                 (val->nodesetval->nodeTab != NULL)) {
5440                 xmlNodePtr cur, tmp;
5441                 xmlDocPtr top;
5442
5443                 ret->boolval = 1;
5444                 top =  xmlNewDoc(NULL);
5445                 top->name = (char *)
5446                     xmlStrdup(val->nodesetval->nodeTab[0]->name);
5447                 ret->user = top;
5448                 if (top != NULL) {
5449                     top->doc = top;
5450                     cur = val->nodesetval->nodeTab[0]->children;
5451                     while (cur != NULL) {
5452                         tmp = xmlDocCopyNode(cur, top, 1);
5453                         xmlAddChild((xmlNodePtr) top, tmp);
5454                         cur = cur->next;
5455                     }
5456                 }
5457
5458                 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5459             } else
5460                 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5461             /* Deallocate the copied tree value */
5462             break;
5463 #endif
5464         case XPATH_NODESET:
5465             ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5466             /* Do not deallocate the copied tree value */
5467             ret->boolval = 0;
5468             break;
5469         case XPATH_LOCATIONSET:
5470 #ifdef LIBXML_XPTR_ENABLED
5471         {
5472             xmlLocationSetPtr loc = val->user;
5473             ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5474             break;
5475         }
5476 #endif
5477         case XPATH_USERS:
5478             ret->user = val->user;
5479             break;
5480         case XPATH_UNDEFINED:
5481             xmlGenericError(xmlGenericErrorContext,
5482                     "xmlXPathObjectCopy: unsupported type %d\n",
5483                     val->type);
5484             break;
5485     }
5486     return(ret);
5487 }
5488
5489 /**
5490  * xmlXPathFreeObject:
5491  * @obj:  the object to free
5492  *
5493  * Free up an xmlXPathObjectPtr object.
5494  */
5495 void
5496 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5497     if (obj == NULL) return;
5498     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5499         if (obj->boolval) {
5500 #if 0
5501             if (obj->user != NULL) {
5502                 xmlXPathFreeNodeSet(obj->nodesetval);
5503                 xmlFreeNodeList((xmlNodePtr) obj->user);
5504             } else
5505 #endif
5506             obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5507             if (obj->nodesetval != NULL)
5508                 xmlXPathFreeValueTree(obj->nodesetval);
5509         } else {
5510             if (obj->nodesetval != NULL)
5511                 xmlXPathFreeNodeSet(obj->nodesetval);
5512         }
5513 #ifdef LIBXML_XPTR_ENABLED
5514     } else if (obj->type == XPATH_LOCATIONSET) {
5515         if (obj->user != NULL)
5516             xmlXPtrFreeLocationSet(obj->user);
5517 #endif
5518     } else if (obj->type == XPATH_STRING) {
5519         if (obj->stringval != NULL)
5520             xmlFree(obj->stringval);
5521     }
5522 #ifdef XP_DEBUG_OBJ_USAGE
5523     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5524 #endif
5525     xmlFree(obj);
5526 }
5527
5528 /**
5529  * xmlXPathReleaseObject:
5530  * @obj:  the xmlXPathObjectPtr to free or to cache
5531  *
5532  * Depending on the state of the cache this frees the given
5533  * XPath object or stores it in the cache.
5534  */
5535 static void
5536 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5537 {
5538 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5539         sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5540     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5541
5542 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5543
5544     if (obj == NULL)
5545         return;
5546     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5547          xmlXPathFreeObject(obj);
5548     } else {
5549         xmlXPathContextCachePtr cache =
5550             (xmlXPathContextCachePtr) ctxt->cache;
5551
5552         switch (obj->type) {
5553             case XPATH_NODESET:
5554             case XPATH_XSLT_TREE:
5555                 if (obj->nodesetval != NULL) {
5556                     if (obj->boolval) {
5557                         /*
5558                         * It looks like the @boolval is used for
5559                         * evaluation if this an XSLT Result Tree Fragment.
5560                         * TODO: Check if this assumption is correct.
5561                         */
5562                         obj->type = XPATH_XSLT_TREE; /* just for debugging */
5563                         xmlXPathFreeValueTree(obj->nodesetval);
5564                         obj->nodesetval = NULL;
5565                     } else if ((obj->nodesetval->nodeMax <= 40) &&
5566                         (XP_CACHE_WANTS(cache->nodesetObjs,
5567                                         cache->maxNodeset)))
5568                     {
5569                         XP_CACHE_ADD(cache->nodesetObjs, obj);
5570                         goto obj_cached;
5571                     } else {
5572                         xmlXPathFreeNodeSet(obj->nodesetval);
5573                         obj->nodesetval = NULL;
5574                     }
5575                 }
5576                 break;
5577             case XPATH_STRING:
5578                 if (obj->stringval != NULL)
5579                     xmlFree(obj->stringval);
5580
5581                 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5582                     XP_CACHE_ADD(cache->stringObjs, obj);
5583                     goto obj_cached;
5584                 }
5585                 break;
5586             case XPATH_BOOLEAN:
5587                 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5588                     XP_CACHE_ADD(cache->booleanObjs, obj);
5589                     goto obj_cached;
5590                 }
5591                 break;
5592             case XPATH_NUMBER:
5593                 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5594                     XP_CACHE_ADD(cache->numberObjs, obj);
5595                     goto obj_cached;
5596                 }
5597                 break;
5598 #ifdef LIBXML_XPTR_ENABLED
5599             case XPATH_LOCATIONSET:
5600                 if (obj->user != NULL) {
5601                     xmlXPtrFreeLocationSet(obj->user);
5602                 }
5603                 goto free_obj;
5604 #endif
5605             default:
5606                 goto free_obj;
5607         }
5608
5609         /*
5610         * Fallback to adding to the misc-objects slot.
5611         */
5612         if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5613             XP_CACHE_ADD(cache->miscObjs, obj);
5614         } else
5615             goto free_obj;
5616
5617 obj_cached:
5618
5619 #ifdef XP_DEBUG_OBJ_USAGE
5620         xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5621 #endif
5622
5623         if (obj->nodesetval != NULL) {
5624             xmlNodeSetPtr tmpset = obj->nodesetval;
5625
5626             /*
5627             * TODO: Due to those nasty ns-nodes, we need to traverse
5628             *  the list and free the ns-nodes.
5629             * URGENT TODO: Check if it's actually slowing things down.
5630             *  Maybe we shouldn't try to preserve the list.
5631             */
5632             if (tmpset->nodeNr > 1) {
5633                 int i;
5634                 xmlNodePtr node;
5635
5636                 for (i = 0; i < tmpset->nodeNr; i++) {
5637                     node = tmpset->nodeTab[i];
5638                     if ((node != NULL) &&
5639                         (node->type == XML_NAMESPACE_DECL))
5640                     {
5641                         xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5642                     }
5643                 }
5644             } else if (tmpset->nodeNr == 1) {
5645                 if ((tmpset->nodeTab[0] != NULL) &&
5646                     (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5647                     xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5648             }
5649             tmpset->nodeNr = 0;
5650             memset(obj, 0, sizeof(xmlXPathObject));
5651             obj->nodesetval = tmpset;
5652         } else
5653             memset(obj, 0, sizeof(xmlXPathObject));
5654
5655         return;
5656
5657 free_obj:
5658         /*
5659         * Cache is full; free the object.
5660         */
5661         if (obj->nodesetval != NULL)
5662             xmlXPathFreeNodeSet(obj->nodesetval);
5663 #ifdef XP_DEBUG_OBJ_USAGE
5664         xmlXPathDebugObjUsageReleased(NULL, obj->type);
5665 #endif
5666         xmlFree(obj);
5667     }
5668     return;
5669 }
5670
5671
5672 /************************************************************************
5673  *                                                                      *
5674  *                      Type Casting Routines                           *
5675  *                                                                      *
5676  ************************************************************************/
5677
5678 /**
5679  * xmlXPathCastBooleanToString:
5680  * @val:  a boolean
5681  *
5682  * Converts a boolean to its string value.
5683  *
5684  * Returns a newly allocated string.
5685  */
5686 xmlChar *
5687 xmlXPathCastBooleanToString (int val) {
5688     xmlChar *ret;
5689     if (val)
5690         ret = xmlStrdup((const xmlChar *) "true");
5691     else
5692         ret = xmlStrdup((const xmlChar *) "false");
5693     return(ret);
5694 }
5695
5696 /**
5697  * xmlXPathCastNumberToString:
5698  * @val:  a number
5699  *
5700  * Converts a number to its string value.
5701  *
5702  * Returns a newly allocated string.
5703  */
5704 xmlChar *
5705 xmlXPathCastNumberToString (double val) {
5706     xmlChar *ret;
5707     switch (xmlXPathIsInf(val)) {
5708     case 1:
5709         ret = xmlStrdup((const xmlChar *) "Infinity");
5710         break;
5711     case -1:
5712         ret = xmlStrdup((const xmlChar *) "-Infinity");
5713         break;
5714     default:
5715         if (xmlXPathIsNaN(val)) {
5716             ret = xmlStrdup((const xmlChar *) "NaN");
5717         } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5718             ret = xmlStrdup((const xmlChar *) "0");
5719         } else {
5720             /* could be improved */
5721             char buf[100];
5722             xmlXPathFormatNumber(val, buf, 99);
5723             buf[99] = 0;
5724             ret = xmlStrdup((const xmlChar *) buf);
5725         }
5726     }
5727     return(ret);
5728 }
5729
5730 /**
5731  * xmlXPathCastNodeToString:
5732  * @node:  a node
5733  *
5734  * Converts a node to its string value.
5735  *
5736  * Returns a newly allocated string.
5737  */
5738 xmlChar *
5739 xmlXPathCastNodeToString (xmlNodePtr node) {
5740 xmlChar *ret;
5741     if ((ret = xmlNodeGetContent(node)) == NULL)
5742         ret = xmlStrdup((const xmlChar *) "");
5743     return(ret);
5744 }
5745
5746 /**
5747  * xmlXPathCastNodeSetToString:
5748  * @ns:  a node-set
5749  *
5750  * Converts a node-set to its string value.
5751  *
5752  * Returns a newly allocated string.
5753  */
5754 xmlChar *
5755 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5756     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5757         return(xmlStrdup((const xmlChar *) ""));
5758
5759     if (ns->nodeNr > 1)
5760         xmlXPathNodeSetSort(ns);
5761     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5762 }
5763
5764 /**
5765  * xmlXPathCastToString:
5766  * @val:  an XPath object
5767  *
5768  * Converts an existing object to its string() equivalent
5769  *
5770  * Returns the allocated string value of the object, NULL in case of error.
5771  *         It's up to the caller to free the string memory with xmlFree().
5772  */
5773 xmlChar *
5774 xmlXPathCastToString(xmlXPathObjectPtr val) {
5775     xmlChar *ret = NULL;
5776
5777     if (val == NULL)
5778         return(xmlStrdup((const xmlChar *) ""));
5779     switch (val->type) {
5780         case XPATH_UNDEFINED:
5781 #ifdef DEBUG_EXPR
5782             xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5783 #endif
5784             ret = xmlStrdup((const xmlChar *) "");
5785             break;
5786         case XPATH_NODESET:
5787         case XPATH_XSLT_TREE:
5788             ret = xmlXPathCastNodeSetToString(val->nodesetval);
5789             break;
5790         case XPATH_STRING:
5791             return(xmlStrdup(val->stringval));
5792         case XPATH_BOOLEAN:
5793             ret = xmlXPathCastBooleanToString(val->boolval);
5794             break;
5795         case XPATH_NUMBER: {
5796             ret = xmlXPathCastNumberToString(val->floatval);
5797             break;
5798         }
5799         case XPATH_USERS:
5800         case XPATH_POINT:
5801         case XPATH_RANGE:
5802         case XPATH_LOCATIONSET:
5803             TODO
5804             ret = xmlStrdup((const xmlChar *) "");
5805             break;
5806     }
5807     return(ret);
5808 }
5809
5810 /**
5811  * xmlXPathConvertString:
5812  * @val:  an XPath object
5813  *
5814  * Converts an existing object to its string() equivalent
5815  *
5816  * Returns the new object, the old one is freed (or the operation
5817  *         is done directly on @val)
5818  */
5819 xmlXPathObjectPtr
5820 xmlXPathConvertString(xmlXPathObjectPtr val) {
5821     xmlChar *res = NULL;
5822
5823     if (val == NULL)
5824         return(xmlXPathNewCString(""));
5825
5826     switch (val->type) {
5827     case XPATH_UNDEFINED:
5828 #ifdef DEBUG_EXPR
5829         xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5830 #endif
5831         break;
5832     case XPATH_NODESET:
5833     case XPATH_XSLT_TREE:
5834         res = xmlXPathCastNodeSetToString(val->nodesetval);
5835         break;
5836     case XPATH_STRING:
5837         return(val);
5838     case XPATH_BOOLEAN:
5839         res = xmlXPathCastBooleanToString(val->boolval);
5840         break;
5841     case XPATH_NUMBER:
5842         res = xmlXPathCastNumberToString(val->floatval);
5843         break;
5844     case XPATH_USERS:
5845     case XPATH_POINT:
5846     case XPATH_RANGE:
5847     case XPATH_LOCATIONSET:
5848         TODO;
5849         break;
5850     }
5851     xmlXPathFreeObject(val);
5852     if (res == NULL)
5853         return(xmlXPathNewCString(""));
5854     return(xmlXPathWrapString(res));
5855 }
5856
5857 /**
5858  * xmlXPathCastBooleanToNumber:
5859  * @val:  a boolean
5860  *
5861  * Converts a boolean to its number value
5862  *
5863  * Returns the number value
5864  */
5865 double
5866 xmlXPathCastBooleanToNumber(int val) {
5867     if (val)
5868         return(1.0);
5869     return(0.0);
5870 }
5871
5872 /**
5873  * xmlXPathCastStringToNumber:
5874  * @val:  a string
5875  *
5876  * Converts a string to its number value
5877  *
5878  * Returns the number value
5879  */
5880 double
5881 xmlXPathCastStringToNumber(const xmlChar * val) {
5882     return(xmlXPathStringEvalNumber(val));
5883 }
5884
5885 /**
5886  * xmlXPathCastNodeToNumber:
5887  * @node:  a node
5888  *
5889  * Converts a node to its number value
5890  *
5891  * Returns the number value
5892  */
5893 double
5894 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5895     xmlChar *strval;
5896     double ret;
5897
5898     if (node == NULL)
5899         return(xmlXPathNAN);
5900     strval = xmlXPathCastNodeToString(node);
5901     if (strval == NULL)
5902         return(xmlXPathNAN);
5903     ret = xmlXPathCastStringToNumber(strval);
5904     xmlFree(strval);
5905
5906     return(ret);
5907 }
5908
5909 /**
5910  * xmlXPathCastNodeSetToNumber:
5911  * @ns:  a node-set
5912  *
5913  * Converts a node-set to its number value
5914  *
5915  * Returns the number value
5916  */
5917 double
5918 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5919     xmlChar *str;
5920     double ret;
5921
5922     if (ns == NULL)
5923         return(xmlXPathNAN);
5924     str = xmlXPathCastNodeSetToString(ns);
5925     ret = xmlXPathCastStringToNumber(str);
5926     xmlFree(str);
5927     return(ret);
5928 }
5929
5930 /**
5931  * xmlXPathCastToNumber:
5932  * @val:  an XPath object
5933  *
5934  * Converts an XPath object to its number value
5935  *
5936  * Returns the number value
5937  */
5938 double
5939 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5940     double ret = 0.0;
5941
5942     if (val == NULL)
5943         return(xmlXPathNAN);
5944     switch (val->type) {
5945     case XPATH_UNDEFINED:
5946 #ifdef DEGUB_EXPR
5947         xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5948 #endif
5949         ret = xmlXPathNAN;
5950         break;
5951     case XPATH_NODESET:
5952     case XPATH_XSLT_TREE:
5953         ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5954         break;
5955     case XPATH_STRING:
5956         ret = xmlXPathCastStringToNumber(val->stringval);
5957         break;
5958     case XPATH_NUMBER:
5959         ret = val->floatval;
5960         break;
5961     case XPATH_BOOLEAN:
5962         ret = xmlXPathCastBooleanToNumber(val->boolval);
5963         break;
5964     case XPATH_USERS:
5965     case XPATH_POINT:
5966     case XPATH_RANGE:
5967     case XPATH_LOCATIONSET:
5968         TODO;
5969         ret = xmlXPathNAN;
5970         break;
5971     }
5972     return(ret);
5973 }
5974
5975 /**
5976  * xmlXPathConvertNumber:
5977  * @val:  an XPath object
5978  *
5979  * Converts an existing object to its number() equivalent
5980  *
5981  * Returns the new object, the old one is freed (or the operation
5982  *         is done directly on @val)
5983  */
5984 xmlXPathObjectPtr
5985 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5986     xmlXPathObjectPtr ret;
5987
5988     if (val == NULL)
5989         return(xmlXPathNewFloat(0.0));
5990     if (val->type == XPATH_NUMBER)
5991         return(val);
5992     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5993     xmlXPathFreeObject(val);
5994     return(ret);
5995 }
5996
5997 /**
5998  * xmlXPathCastNumberToBoolean:
5999  * @val:  a number
6000  *
6001  * Converts a number to its boolean value
6002  *
6003  * Returns the boolean value
6004  */
6005 int
6006 xmlXPathCastNumberToBoolean (double val) {
6007      if (xmlXPathIsNaN(val) || (val == 0.0))
6008          return(0);
6009      return(1);
6010 }
6011
6012 /**
6013  * xmlXPathCastStringToBoolean:
6014  * @val:  a string
6015  *
6016  * Converts a string to its boolean value
6017  *
6018  * Returns the boolean value
6019  */
6020 int
6021 xmlXPathCastStringToBoolean (const xmlChar *val) {
6022     if ((val == NULL) || (xmlStrlen(val) == 0))
6023         return(0);
6024     return(1);
6025 }
6026
6027 /**
6028  * xmlXPathCastNodeSetToBoolean:
6029  * @ns:  a node-set
6030  *
6031  * Converts a node-set to its boolean value
6032  *
6033  * Returns the boolean value
6034  */
6035 int
6036 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6037     if ((ns == NULL) || (ns->nodeNr == 0))
6038         return(0);
6039     return(1);
6040 }
6041
6042 /**
6043  * xmlXPathCastToBoolean:
6044  * @val:  an XPath object
6045  *
6046  * Converts an XPath object to its boolean value
6047  *
6048  * Returns the boolean value
6049  */
6050 int
6051 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6052     int ret = 0;
6053
6054     if (val == NULL)
6055         return(0);
6056     switch (val->type) {
6057     case XPATH_UNDEFINED:
6058 #ifdef DEBUG_EXPR
6059         xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6060 #endif
6061         ret = 0;
6062         break;
6063     case XPATH_NODESET:
6064     case XPATH_XSLT_TREE:
6065         ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6066         break;
6067     case XPATH_STRING:
6068         ret = xmlXPathCastStringToBoolean(val->stringval);
6069         break;
6070     case XPATH_NUMBER:
6071         ret = xmlXPathCastNumberToBoolean(val->floatval);
6072         break;
6073     case XPATH_BOOLEAN:
6074         ret = val->boolval;
6075         break;
6076     case XPATH_USERS:
6077     case XPATH_POINT:
6078     case XPATH_RANGE:
6079     case XPATH_LOCATIONSET:
6080         TODO;
6081         ret = 0;
6082         break;
6083     }
6084     return(ret);
6085 }
6086
6087
6088 /**
6089  * xmlXPathConvertBoolean:
6090  * @val:  an XPath object
6091  *
6092  * Converts an existing object to its boolean() equivalent
6093  *
6094  * Returns the new object, the old one is freed (or the operation
6095  *         is done directly on @val)
6096  */
6097 xmlXPathObjectPtr
6098 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6099     xmlXPathObjectPtr ret;
6100
6101     if (val == NULL)
6102         return(xmlXPathNewBoolean(0));
6103     if (val->type == XPATH_BOOLEAN)
6104         return(val);
6105     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6106     xmlXPathFreeObject(val);
6107     return(ret);
6108 }
6109
6110 /************************************************************************
6111  *                                                                      *
6112  *              Routines to handle XPath contexts                       *
6113  *                                                                      *
6114  ************************************************************************/
6115
6116 /**
6117  * xmlXPathNewContext:
6118  * @doc:  the XML document
6119  *
6120  * Create a new xmlXPathContext
6121  *
6122  * Returns the xmlXPathContext just allocated. The caller will need to free it.
6123  */
6124 xmlXPathContextPtr
6125 xmlXPathNewContext(xmlDocPtr doc) {
6126     xmlXPathContextPtr ret;
6127
6128     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6129     if (ret == NULL) {
6130         xmlXPathErrMemory(NULL, "creating context\n");
6131         return(NULL);
6132     }
6133     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6134     ret->doc = doc;
6135     ret->node = NULL;
6136
6137     ret->varHash = NULL;
6138
6139     ret->nb_types = 0;
6140     ret->max_types = 0;
6141     ret->types = NULL;
6142
6143     ret->funcHash = xmlHashCreate(0);
6144
6145     ret->nb_axis = 0;
6146     ret->max_axis = 0;
6147     ret->axis = NULL;
6148
6149     ret->nsHash = NULL;
6150     ret->user = NULL;
6151
6152     ret->contextSize = -1;
6153     ret->proximityPosition = -1;
6154
6155 #ifdef XP_DEFAULT_CACHE_ON
6156     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6157         xmlXPathFreeContext(ret);
6158         return(NULL);
6159     }
6160 #endif
6161
6162     xmlXPathRegisterAllFunctions(ret);
6163
6164     return(ret);
6165 }
6166
6167 /**
6168  * xmlXPathFreeContext:
6169  * @ctxt:  the context to free
6170  *
6171  * Free up an xmlXPathContext
6172  */
6173 void
6174 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6175     if (ctxt == NULL) return;
6176
6177     if (ctxt->cache != NULL)
6178         xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6179     xmlXPathRegisteredNsCleanup(ctxt);
6180     xmlXPathRegisteredFuncsCleanup(ctxt);
6181     xmlXPathRegisteredVariablesCleanup(ctxt);
6182     xmlResetError(&ctxt->lastError);
6183     xmlFree(ctxt);
6184 }
6185
6186 /************************************************************************
6187  *                                                                      *
6188  *              Routines to handle XPath parser contexts                *
6189  *                                                                      *
6190  ************************************************************************/
6191
6192 #define CHECK_CTXT(ctxt)                                                \
6193     if (ctxt == NULL) {                                         \
6194         __xmlRaiseError(NULL, NULL, NULL,                               \
6195                 NULL, NULL, XML_FROM_XPATH,                             \
6196                 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6197                 __FILE__, __LINE__,                                     \
6198                 NULL, NULL, NULL, 0, 0,                                 \
6199                 "NULL context pointer\n");                              \
6200         return(NULL);                                                   \
6201     }                                                                   \
6202
6203 #define CHECK_CTXT_NEG(ctxt)                                            \
6204     if (ctxt == NULL) {                                         \
6205         __xmlRaiseError(NULL, NULL, NULL,                               \
6206                 NULL, NULL, XML_FROM_XPATH,                             \
6207                 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6208                 __FILE__, __LINE__,                                     \
6209                 NULL, NULL, NULL, 0, 0,                                 \
6210                 "NULL context pointer\n");                              \
6211         return(-1);                                                     \
6212     }                                                                   \
6213
6214
6215 #define CHECK_CONTEXT(ctxt)                                             \
6216     if ((ctxt == NULL) || (ctxt->doc == NULL) ||                        \
6217         (ctxt->doc->children == NULL)) {                                \
6218         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);    \
6219         return(NULL);                                                   \
6220     }
6221
6222
6223 /**
6224  * xmlXPathNewParserContext:
6225  * @str:  the XPath expression
6226  * @ctxt:  the XPath context
6227  *
6228  * Create a new xmlXPathParserContext
6229  *
6230  * Returns the xmlXPathParserContext just allocated.
6231  */
6232 xmlXPathParserContextPtr
6233 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6234     xmlXPathParserContextPtr ret;
6235
6236     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6237     if (ret == NULL) {
6238         xmlXPathErrMemory(ctxt, "creating parser context\n");
6239         return(NULL);
6240     }
6241     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6242     ret->cur = ret->base = str;
6243     ret->context = ctxt;
6244
6245     ret->comp = xmlXPathNewCompExpr();
6246     if (ret->comp == NULL) {
6247         xmlFree(ret->valueTab);
6248         xmlFree(ret);
6249         return(NULL);
6250     }
6251     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6252         ret->comp->dict = ctxt->dict;
6253         xmlDictReference(ret->comp->dict);
6254     }
6255
6256     return(ret);
6257 }
6258
6259 /**
6260  * xmlXPathCompParserContext:
6261  * @comp:  the XPath compiled expression
6262  * @ctxt:  the XPath context
6263  *
6264  * Create a new xmlXPathParserContext when processing a compiled expression
6265  *
6266  * Returns the xmlXPathParserContext just allocated.
6267  */
6268 static xmlXPathParserContextPtr
6269 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6270     xmlXPathParserContextPtr ret;
6271
6272     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6273     if (ret == NULL) {
6274         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6275         return(NULL);
6276     }
6277     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6278
6279     /* Allocate the value stack */
6280     ret->valueTab = (xmlXPathObjectPtr *)
6281                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6282     if (ret->valueTab == NULL) {
6283         xmlFree(ret);
6284         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6285         return(NULL);
6286     }
6287     ret->valueNr = 0;
6288     ret->valueMax = 10;
6289     ret->value = NULL;
6290     ret->valueFrame = 0;
6291
6292     ret->context = ctxt;
6293     ret->comp = comp;
6294
6295     return(ret);
6296 }
6297
6298 /**
6299  * xmlXPathFreeParserContext:
6300  * @ctxt:  the context to free
6301  *
6302  * Free up an xmlXPathParserContext
6303  */
6304 void
6305 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6306     int i;
6307
6308     if (ctxt->valueTab != NULL) {
6309         for (i = 0; i < ctxt->valueNr; i++) {
6310             if (ctxt->context)
6311                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6312             else
6313                 xmlXPathFreeObject(ctxt->valueTab[i]);
6314         }
6315         xmlFree(ctxt->valueTab);
6316     }
6317     if (ctxt->comp != NULL) {
6318 #ifdef XPATH_STREAMING
6319         if (ctxt->comp->stream != NULL) {
6320             xmlFreePatternList(ctxt->comp->stream);
6321             ctxt->comp->stream = NULL;
6322         }
6323 #endif
6324         xmlXPathFreeCompExpr(ctxt->comp);
6325     }
6326     xmlFree(ctxt);
6327 }
6328
6329 /************************************************************************
6330  *                                                                      *
6331  *              The implicit core function library                      *
6332  *                                                                      *
6333  ************************************************************************/
6334
6335 /**
6336  * xmlXPathNodeValHash:
6337  * @node:  a node pointer
6338  *
6339  * Function computing the beginning of the string value of the node,
6340  * used to speed up comparisons
6341  *
6342  * Returns an int usable as a hash
6343  */
6344 static unsigned int
6345 xmlXPathNodeValHash(xmlNodePtr node) {
6346     int len = 2;
6347     const xmlChar * string = NULL;
6348     xmlNodePtr tmp = NULL;
6349     unsigned int ret = 0;
6350
6351     if (node == NULL)
6352         return(0);
6353
6354     if (node->type == XML_DOCUMENT_NODE) {
6355         tmp = xmlDocGetRootElement((xmlDocPtr) node);
6356         if (tmp == NULL)
6357             node = node->children;
6358         else
6359             node = tmp;
6360
6361         if (node == NULL)
6362             return(0);
6363     }
6364
6365     switch (node->type) {
6366         case XML_COMMENT_NODE:
6367         case XML_PI_NODE:
6368         case XML_CDATA_SECTION_NODE:
6369         case XML_TEXT_NODE:
6370             string = node->content;
6371             if (string == NULL)
6372                 return(0);
6373             if (string[0] == 0)
6374                 return(0);
6375             return(((unsigned int) string[0]) +
6376                    (((unsigned int) string[1]) << 8));
6377         case XML_NAMESPACE_DECL:
6378             string = ((xmlNsPtr)node)->href;
6379             if (string == NULL)
6380                 return(0);
6381             if (string[0] == 0)
6382                 return(0);
6383             return(((unsigned int) string[0]) +
6384                    (((unsigned int) string[1]) << 8));
6385         case XML_ATTRIBUTE_NODE:
6386             tmp = ((xmlAttrPtr) node)->children;
6387             break;
6388         case XML_ELEMENT_NODE:
6389             tmp = node->children;
6390             break;
6391         default:
6392             return(0);
6393     }
6394     while (tmp != NULL) {
6395         switch (tmp->type) {
6396             case XML_COMMENT_NODE:
6397             case XML_PI_NODE:
6398             case XML_CDATA_SECTION_NODE:
6399             case XML_TEXT_NODE:
6400                 string = tmp->content;
6401                 break;
6402             case XML_NAMESPACE_DECL:
6403                 string = ((xmlNsPtr)tmp)->href;
6404                 break;
6405             default:
6406                 break;
6407         }
6408         if ((string != NULL) && (string[0] != 0)) {
6409             if (len == 1) {
6410                 return(ret + (((unsigned int) string[0]) << 8));
6411             }
6412             if (string[1] == 0) {
6413                 len = 1;
6414                 ret = (unsigned int) string[0];
6415             } else {
6416                 return(((unsigned int) string[0]) +
6417                        (((unsigned int) string[1]) << 8));
6418             }
6419         }
6420         /*
6421          * Skip to next node
6422          */
6423         if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6424             if (tmp->children->type != XML_ENTITY_DECL) {
6425                 tmp = tmp->children;
6426                 continue;
6427             }
6428         }
6429         if (tmp == node)
6430             break;
6431
6432         if (tmp->next != NULL) {
6433             tmp = tmp->next;
6434             continue;
6435         }
6436
6437         do {
6438             tmp = tmp->parent;
6439             if (tmp == NULL)
6440                 break;
6441             if (tmp == node) {
6442                 tmp = NULL;
6443                 break;
6444             }
6445             if (tmp->next != NULL) {
6446                 tmp = tmp->next;
6447                 break;
6448             }
6449         } while (tmp != NULL);
6450     }
6451     return(ret);
6452 }
6453
6454 /**
6455  * xmlXPathStringHash:
6456  * @string:  a string
6457  *
6458  * Function computing the beginning of the string value of the node,
6459  * used to speed up comparisons
6460  *
6461  * Returns an int usable as a hash
6462  */
6463 static unsigned int
6464 xmlXPathStringHash(const xmlChar * string) {
6465     if (string == NULL)
6466         return((unsigned int) 0);
6467     if (string[0] == 0)
6468         return(0);
6469     return(((unsigned int) string[0]) +
6470            (((unsigned int) string[1]) << 8));
6471 }
6472
6473 /**
6474  * xmlXPathCompareNodeSetFloat:
6475  * @ctxt:  the XPath Parser context
6476  * @inf:  less than (1) or greater than (0)
6477  * @strict:  is the comparison strict
6478  * @arg:  the node set
6479  * @f:  the value
6480  *
6481  * Implement the compare operation between a nodeset and a number
6482  *     @ns < @val    (1, 1, ...
6483  *     @ns <= @val   (1, 0, ...
6484  *     @ns > @val    (0, 1, ...
6485  *     @ns >= @val   (0, 0, ...
6486  *
6487  * If one object to be compared is a node-set and the other is a number,
6488  * then the comparison will be true if and only if there is a node in the
6489  * node-set such that the result of performing the comparison on the number
6490  * to be compared and on the result of converting the string-value of that
6491  * node to a number using the number function is true.
6492  *
6493  * Returns 0 or 1 depending on the results of the test.
6494  */
6495 static int
6496 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6497                             xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6498     int i, ret = 0;
6499     xmlNodeSetPtr ns;
6500     xmlChar *str2;
6501
6502     if ((f == NULL) || (arg == NULL) ||
6503         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6504         xmlXPathReleaseObject(ctxt->context, arg);
6505         xmlXPathReleaseObject(ctxt->context, f);
6506         return(0);
6507     }
6508     ns = arg->nodesetval;
6509     if (ns != NULL) {
6510         for (i = 0;i < ns->nodeNr;i++) {
6511              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6512              if (str2 != NULL) {
6513                  valuePush(ctxt,
6514                            xmlXPathCacheNewString(ctxt->context, str2));
6515                  xmlFree(str2);
6516                  xmlXPathNumberFunction(ctxt, 1);
6517                  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6518                  ret = xmlXPathCompareValues(ctxt, inf, strict);
6519                  if (ret)
6520                      break;
6521              }
6522         }
6523     }
6524     xmlXPathReleaseObject(ctxt->context, arg);
6525     xmlXPathReleaseObject(ctxt->context, f);
6526     return(ret);
6527 }
6528
6529 /**
6530  * xmlXPathCompareNodeSetString:
6531  * @ctxt:  the XPath Parser context
6532  * @inf:  less than (1) or greater than (0)
6533  * @strict:  is the comparison strict
6534  * @arg:  the node set
6535  * @s:  the value
6536  *
6537  * Implement the compare operation between a nodeset and a string
6538  *     @ns < @val    (1, 1, ...
6539  *     @ns <= @val   (1, 0, ...
6540  *     @ns > @val    (0, 1, ...
6541  *     @ns >= @val   (0, 0, ...
6542  *
6543  * If one object to be compared is a node-set and the other is a string,
6544  * then the comparison will be true if and only if there is a node in
6545  * the node-set such that the result of performing the comparison on the
6546  * string-value of the node and the other string is true.
6547  *
6548  * Returns 0 or 1 depending on the results of the test.
6549  */
6550 static int
6551 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6552                             xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6553     int i, ret = 0;
6554     xmlNodeSetPtr ns;
6555     xmlChar *str2;
6556
6557     if ((s == NULL) || (arg == NULL) ||
6558         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6559         xmlXPathReleaseObject(ctxt->context, arg);
6560         xmlXPathReleaseObject(ctxt->context, s);
6561         return(0);
6562     }
6563     ns = arg->nodesetval;
6564     if (ns != NULL) {
6565         for (i = 0;i < ns->nodeNr;i++) {
6566              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6567              if (str2 != NULL) {
6568                  valuePush(ctxt,
6569                            xmlXPathCacheNewString(ctxt->context, str2));
6570                  xmlFree(str2);
6571                  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6572                  ret = xmlXPathCompareValues(ctxt, inf, strict);
6573                  if (ret)
6574                      break;
6575              }
6576         }
6577     }
6578     xmlXPathReleaseObject(ctxt->context, arg);
6579     xmlXPathReleaseObject(ctxt->context, s);
6580     return(ret);
6581 }
6582
6583 /**
6584  * xmlXPathCompareNodeSets:
6585  * @inf:  less than (1) or greater than (0)
6586  * @strict:  is the comparison strict
6587  * @arg1:  the first node set object
6588  * @arg2:  the second node set object
6589  *
6590  * Implement the compare operation on nodesets:
6591  *
6592  * If both objects to be compared are node-sets, then the comparison
6593  * will be true if and only if there is a node in the first node-set
6594  * and a node in the second node-set such that the result of performing
6595  * the comparison on the string-values of the two nodes is true.
6596  * ....
6597  * When neither object to be compared is a node-set and the operator
6598  * is <=, <, >= or >, then the objects are compared by converting both
6599  * objects to numbers and comparing the numbers according to IEEE 754.
6600  * ....
6601  * The number function converts its argument to a number as follows:
6602  *  - a string that consists of optional whitespace followed by an
6603  *    optional minus sign followed by a Number followed by whitespace
6604  *    is converted to the IEEE 754 number that is nearest (according
6605  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6606  *    represented by the string; any other string is converted to NaN
6607  *
6608  * Conclusion all nodes need to be converted first to their string value
6609  * and then the comparison must be done when possible
6610  */
6611 static int
6612 xmlXPathCompareNodeSets(int inf, int strict,
6613                         xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6614     int i, j, init = 0;
6615     double val1;
6616     double *values2;
6617     int ret = 0;
6618     xmlNodeSetPtr ns1;
6619     xmlNodeSetPtr ns2;
6620
6621     if ((arg1 == NULL) ||
6622         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6623         xmlXPathFreeObject(arg2);
6624         return(0);
6625     }
6626     if ((arg2 == NULL) ||
6627         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6628         xmlXPathFreeObject(arg1);
6629         xmlXPathFreeObject(arg2);
6630         return(0);
6631     }
6632
6633     ns1 = arg1->nodesetval;
6634     ns2 = arg2->nodesetval;
6635
6636     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6637         xmlXPathFreeObject(arg1);
6638         xmlXPathFreeObject(arg2);
6639         return(0);
6640     }
6641     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6642         xmlXPathFreeObject(arg1);
6643         xmlXPathFreeObject(arg2);
6644         return(0);
6645     }
6646
6647     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6648     if (values2 == NULL) {
6649         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6650         xmlXPathFreeObject(arg1);
6651         xmlXPathFreeObject(arg2);
6652         return(0);
6653     }
6654     for (i = 0;i < ns1->nodeNr;i++) {
6655         val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6656         if (xmlXPathIsNaN(val1))
6657             continue;
6658         for (j = 0;j < ns2->nodeNr;j++) {
6659             if (init == 0) {
6660                 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6661             }
6662             if (xmlXPathIsNaN(values2[j]))
6663                 continue;
6664             if (inf && strict)
6665                 ret = (val1 < values2[j]);
6666             else if (inf && !strict)
6667                 ret = (val1 <= values2[j]);
6668             else if (!inf && strict)
6669                 ret = (val1 > values2[j]);
6670             else if (!inf && !strict)
6671                 ret = (val1 >= values2[j]);
6672             if (ret)
6673                 break;
6674         }
6675         if (ret)
6676             break;
6677         init = 1;
6678     }
6679     xmlFree(values2);
6680     xmlXPathFreeObject(arg1);
6681     xmlXPathFreeObject(arg2);
6682     return(ret);
6683 }
6684
6685 /**
6686  * xmlXPathCompareNodeSetValue:
6687  * @ctxt:  the XPath Parser context
6688  * @inf:  less than (1) or greater than (0)
6689  * @strict:  is the comparison strict
6690  * @arg:  the node set
6691  * @val:  the value
6692  *
6693  * Implement the compare operation between a nodeset and a value
6694  *     @ns < @val    (1, 1, ...
6695  *     @ns <= @val   (1, 0, ...
6696  *     @ns > @val    (0, 1, ...
6697  *     @ns >= @val   (0, 0, ...
6698  *
6699  * If one object to be compared is a node-set and the other is a boolean,
6700  * then the comparison will be true if and only if the result of performing
6701  * the comparison on the boolean and on the result of converting
6702  * the node-set to a boolean using the boolean function is true.
6703  *
6704  * Returns 0 or 1 depending on the results of the test.
6705  */
6706 static int
6707 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6708                             xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6709     if ((val == NULL) || (arg == NULL) ||
6710         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6711         return(0);
6712
6713     switch(val->type) {
6714         case XPATH_NUMBER:
6715             return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6716         case XPATH_NODESET:
6717         case XPATH_XSLT_TREE:
6718             return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6719         case XPATH_STRING:
6720             return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6721         case XPATH_BOOLEAN:
6722             valuePush(ctxt, arg);
6723             xmlXPathBooleanFunction(ctxt, 1);
6724             valuePush(ctxt, val);
6725             return(xmlXPathCompareValues(ctxt, inf, strict));
6726         default:
6727             xmlGenericError(xmlGenericErrorContext,
6728                     "xmlXPathCompareNodeSetValue: Can't compare node set "
6729                     "and object of type %d\n",
6730                     val->type);
6731             xmlXPathReleaseObject(ctxt->context, arg);
6732             xmlXPathReleaseObject(ctxt->context, val);
6733             XP_ERROR0(XPATH_INVALID_TYPE);
6734     }
6735     return(0);
6736 }
6737
6738 /**
6739  * xmlXPathEqualNodeSetString:
6740  * @arg:  the nodeset object argument
6741  * @str:  the string to compare to.
6742  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6743  *
6744  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6745  * If one object to be compared is a node-set and the other is a string,
6746  * then the comparison will be true if and only if there is a node in
6747  * the node-set such that the result of performing the comparison on the
6748  * string-value of the node and the other string is true.
6749  *
6750  * Returns 0 or 1 depending on the results of the test.
6751  */
6752 static int
6753 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6754 {
6755     int i;
6756     xmlNodeSetPtr ns;
6757     xmlChar *str2;
6758     unsigned int hash;
6759
6760     if ((str == NULL) || (arg == NULL) ||
6761         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6762         return (0);
6763     ns = arg->nodesetval;
6764     /*
6765      * A NULL nodeset compared with a string is always false
6766      * (since there is no node equal, and no node not equal)
6767      */
6768     if ((ns == NULL) || (ns->nodeNr <= 0) )
6769         return (0);
6770     hash = xmlXPathStringHash(str);
6771     for (i = 0; i < ns->nodeNr; i++) {
6772         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6773             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6774             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6775                 xmlFree(str2);
6776                 if (neq)
6777                     continue;
6778                 return (1);
6779             } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6780                 if (neq)
6781                     continue;
6782                 return (1);
6783             } else if (neq) {
6784                 if (str2 != NULL)
6785                     xmlFree(str2);
6786                 return (1);
6787             }
6788             if (str2 != NULL)
6789                 xmlFree(str2);
6790         } else if (neq)
6791             return (1);
6792     }
6793     return (0);
6794 }
6795
6796 /**
6797  * xmlXPathEqualNodeSetFloat:
6798  * @arg:  the nodeset object argument
6799  * @f:  the float to compare to
6800  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6801  *
6802  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6803  * If one object to be compared is a node-set and the other is a number,
6804  * then the comparison will be true if and only if there is a node in
6805  * the node-set such that the result of performing the comparison on the
6806  * number to be compared and on the result of converting the string-value
6807  * of that node to a number using the number function is true.
6808  *
6809  * Returns 0 or 1 depending on the results of the test.
6810  */
6811 static int
6812 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6813     xmlXPathObjectPtr arg, double f, int neq) {
6814   int i, ret=0;
6815   xmlNodeSetPtr ns;
6816   xmlChar *str2;
6817   xmlXPathObjectPtr val;
6818   double v;
6819
6820     if ((arg == NULL) ||
6821         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6822         return(0);
6823
6824     ns = arg->nodesetval;
6825     if (ns != NULL) {
6826         for (i=0;i<ns->nodeNr;i++) {
6827             str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6828             if (str2 != NULL) {
6829                 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6830                 xmlFree(str2);
6831                 xmlXPathNumberFunction(ctxt, 1);
6832                 val = valuePop(ctxt);
6833                 v = val->floatval;
6834                 xmlXPathReleaseObject(ctxt->context, val);
6835                 if (!xmlXPathIsNaN(v)) {
6836                     if ((!neq) && (v==f)) {
6837                         ret = 1;
6838                         break;
6839                     } else if ((neq) && (v!=f)) {
6840                         ret = 1;
6841                         break;
6842                     }
6843                 } else {        /* NaN is unequal to any value */
6844                     if (neq)
6845                         ret = 1;
6846                 }
6847             }
6848         }
6849     }
6850
6851     return(ret);
6852 }
6853
6854
6855 /**
6856  * xmlXPathEqualNodeSets:
6857  * @arg1:  first nodeset object argument
6858  * @arg2:  second nodeset object argument
6859  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6860  *
6861  * Implement the equal / not equal operation on XPath nodesets:
6862  * @arg1 == @arg2  or  @arg1 != @arg2
6863  * If both objects to be compared are node-sets, then the comparison
6864  * will be true if and only if there is a node in the first node-set and
6865  * a node in the second node-set such that the result of performing the
6866  * comparison on the string-values of the two nodes is true.
6867  *
6868  * (needless to say, this is a costly operation)
6869  *
6870  * Returns 0 or 1 depending on the results of the test.
6871  */
6872 static int
6873 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6874     int i, j;
6875     unsigned int *hashs1;
6876     unsigned int *hashs2;
6877     xmlChar **values1;
6878     xmlChar **values2;
6879     int ret = 0;
6880     xmlNodeSetPtr ns1;
6881     xmlNodeSetPtr ns2;
6882
6883     if ((arg1 == NULL) ||
6884         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6885         return(0);
6886     if ((arg2 == NULL) ||
6887         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6888         return(0);
6889
6890     ns1 = arg1->nodesetval;
6891     ns2 = arg2->nodesetval;
6892
6893     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6894         return(0);
6895     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6896         return(0);
6897
6898     /*
6899      * for equal, check if there is a node pertaining to both sets
6900      */
6901     if (neq == 0)
6902         for (i = 0;i < ns1->nodeNr;i++)
6903             for (j = 0;j < ns2->nodeNr;j++)
6904                 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6905                     return(1);
6906
6907     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6908     if (values1 == NULL) {
6909         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6910         return(0);
6911     }
6912     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6913     if (hashs1 == NULL) {
6914         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6915         xmlFree(values1);
6916         return(0);
6917     }
6918     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6919     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6920     if (values2 == NULL) {
6921         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6922         xmlFree(hashs1);
6923         xmlFree(values1);
6924         return(0);
6925     }
6926     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6927     if (hashs2 == NULL) {
6928         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6929         xmlFree(hashs1);
6930         xmlFree(values1);
6931         xmlFree(values2);
6932         return(0);
6933     }
6934     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6935     for (i = 0;i < ns1->nodeNr;i++) {
6936         hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6937         for (j = 0;j < ns2->nodeNr;j++) {
6938             if (i == 0)
6939                 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6940             if (hashs1[i] != hashs2[j]) {
6941                 if (neq) {
6942                     ret = 1;
6943                     break;
6944                 }
6945             }
6946             else {
6947                 if (values1[i] == NULL)
6948                     values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6949                 if (values2[j] == NULL)
6950                     values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6951                 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6952                 if (ret)
6953                     break;
6954             }
6955         }
6956         if (ret)
6957             break;
6958     }
6959     for (i = 0;i < ns1->nodeNr;i++)
6960         if (values1[i] != NULL)
6961             xmlFree(values1[i]);
6962     for (j = 0;j < ns2->nodeNr;j++)
6963         if (values2[j] != NULL)
6964             xmlFree(values2[j]);
6965     xmlFree(values1);
6966     xmlFree(values2);
6967     xmlFree(hashs1);
6968     xmlFree(hashs2);
6969     return(ret);
6970 }
6971
6972 static int
6973 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6974   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6975     int ret = 0;
6976     /*
6977      *At this point we are assured neither arg1 nor arg2
6978      *is a nodeset, so we can just pick the appropriate routine.
6979      */
6980     switch (arg1->type) {
6981         case XPATH_UNDEFINED:
6982 #ifdef DEBUG_EXPR
6983             xmlGenericError(xmlGenericErrorContext,
6984                     "Equal: undefined\n");
6985 #endif
6986             break;
6987         case XPATH_BOOLEAN:
6988             switch (arg2->type) {
6989                 case XPATH_UNDEFINED:
6990 #ifdef DEBUG_EXPR
6991                     xmlGenericError(xmlGenericErrorContext,
6992                             "Equal: undefined\n");
6993 #endif
6994                     break;
6995                 case XPATH_BOOLEAN:
6996 #ifdef DEBUG_EXPR
6997                     xmlGenericError(xmlGenericErrorContext,
6998                             "Equal: %d boolean %d \n",
6999                             arg1->boolval, arg2->boolval);
7000 #endif
7001                     ret = (arg1->boolval == arg2->boolval);
7002                     break;
7003                 case XPATH_NUMBER:
7004                     ret = (arg1->boolval ==
7005                            xmlXPathCastNumberToBoolean(arg2->floatval));
7006                     break;
7007                 case XPATH_STRING:
7008                     if ((arg2->stringval == NULL) ||
7009                         (arg2->stringval[0] == 0)) ret = 0;
7010                     else
7011                         ret = 1;
7012                     ret = (arg1->boolval == ret);
7013                     break;
7014                 case XPATH_USERS:
7015                 case XPATH_POINT:
7016                 case XPATH_RANGE:
7017                 case XPATH_LOCATIONSET:
7018                     TODO
7019                     break;
7020                 case XPATH_NODESET:
7021                 case XPATH_XSLT_TREE:
7022                     break;
7023             }
7024             break;
7025         case XPATH_NUMBER:
7026             switch (arg2->type) {
7027                 case XPATH_UNDEFINED:
7028 #ifdef DEBUG_EXPR
7029                     xmlGenericError(xmlGenericErrorContext,
7030                             "Equal: undefined\n");
7031 #endif
7032                     break;
7033                 case XPATH_BOOLEAN:
7034                     ret = (arg2->boolval==
7035                            xmlXPathCastNumberToBoolean(arg1->floatval));
7036                     break;
7037                 case XPATH_STRING:
7038                     valuePush(ctxt, arg2);
7039                     xmlXPathNumberFunction(ctxt, 1);
7040                     arg2 = valuePop(ctxt);
7041                     /* no break on purpose */
7042                 case XPATH_NUMBER:
7043                     /* Hand check NaN and Infinity equalities */
7044                     if (xmlXPathIsNaN(arg1->floatval) ||
7045                             xmlXPathIsNaN(arg2->floatval)) {
7046                         ret = 0;
7047                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7048                         if (xmlXPathIsInf(arg2->floatval) == 1)
7049                             ret = 1;
7050                         else
7051                             ret = 0;
7052                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7053                         if (xmlXPathIsInf(arg2->floatval) == -1)
7054                             ret = 1;
7055                         else
7056                             ret = 0;
7057                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7058                         if (xmlXPathIsInf(arg1->floatval) == 1)
7059                             ret = 1;
7060                         else
7061                             ret = 0;
7062                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7063                         if (xmlXPathIsInf(arg1->floatval) == -1)
7064                             ret = 1;
7065                         else
7066                             ret = 0;
7067                     } else {
7068                         ret = (arg1->floatval == arg2->floatval);
7069                     }
7070                     break;
7071                 case XPATH_USERS:
7072                 case XPATH_POINT:
7073                 case XPATH_RANGE:
7074                 case XPATH_LOCATIONSET:
7075                     TODO
7076                     break;
7077                 case XPATH_NODESET:
7078                 case XPATH_XSLT_TREE:
7079                     break;
7080             }
7081             break;
7082         case XPATH_STRING:
7083             switch (arg2->type) {
7084                 case XPATH_UNDEFINED:
7085 #ifdef DEBUG_EXPR
7086                     xmlGenericError(xmlGenericErrorContext,
7087                             "Equal: undefined\n");
7088 #endif
7089                     break;
7090                 case XPATH_BOOLEAN:
7091                     if ((arg1->stringval == NULL) ||
7092                         (arg1->stringval[0] == 0)) ret = 0;
7093                     else
7094                         ret = 1;
7095                     ret = (arg2->boolval == ret);
7096                     break;
7097                 case XPATH_STRING:
7098                     ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7099                     break;
7100                 case XPATH_NUMBER:
7101                     valuePush(ctxt, arg1);
7102                     xmlXPathNumberFunction(ctxt, 1);
7103                     arg1 = valuePop(ctxt);
7104                     /* Hand check NaN and Infinity equalities */
7105                     if (xmlXPathIsNaN(arg1->floatval) ||
7106                             xmlXPathIsNaN(arg2->floatval)) {
7107                         ret = 0;
7108                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7109                         if (xmlXPathIsInf(arg2->floatval) == 1)
7110                             ret = 1;
7111                         else
7112                             ret = 0;
7113                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7114                         if (xmlXPathIsInf(arg2->floatval) == -1)
7115                             ret = 1;
7116                         else
7117                             ret = 0;
7118                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7119                         if (xmlXPathIsInf(arg1->floatval) == 1)
7120                             ret = 1;
7121                         else
7122                             ret = 0;
7123                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7124                         if (xmlXPathIsInf(arg1->floatval) == -1)
7125                             ret = 1;
7126                         else
7127                             ret = 0;
7128                     } else {
7129                         ret = (arg1->floatval == arg2->floatval);
7130                     }
7131                     break;
7132                 case XPATH_USERS:
7133                 case XPATH_POINT:
7134                 case XPATH_RANGE:
7135                 case XPATH_LOCATIONSET:
7136                     TODO
7137                     break;
7138                 case XPATH_NODESET:
7139                 case XPATH_XSLT_TREE:
7140                     break;
7141             }
7142             break;
7143         case XPATH_USERS:
7144         case XPATH_POINT:
7145         case XPATH_RANGE:
7146         case XPATH_LOCATIONSET:
7147             TODO
7148             break;
7149         case XPATH_NODESET:
7150         case XPATH_XSLT_TREE:
7151             break;
7152     }
7153     xmlXPathReleaseObject(ctxt->context, arg1);
7154     xmlXPathReleaseObject(ctxt->context, arg2);
7155     return(ret);
7156 }
7157
7158 /**
7159  * xmlXPathEqualValues:
7160  * @ctxt:  the XPath Parser context
7161  *
7162  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7163  *
7164  * Returns 0 or 1 depending on the results of the test.
7165  */
7166 int
7167 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7168     xmlXPathObjectPtr arg1, arg2, argtmp;
7169     int ret = 0;
7170
7171     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7172     arg2 = valuePop(ctxt);
7173     arg1 = valuePop(ctxt);
7174     if ((arg1 == NULL) || (arg2 == NULL)) {
7175         if (arg1 != NULL)
7176             xmlXPathReleaseObject(ctxt->context, arg1);
7177         else
7178             xmlXPathReleaseObject(ctxt->context, arg2);
7179         XP_ERROR0(XPATH_INVALID_OPERAND);
7180     }
7181
7182     if (arg1 == arg2) {
7183 #ifdef DEBUG_EXPR
7184         xmlGenericError(xmlGenericErrorContext,
7185                 "Equal: by pointer\n");
7186 #endif
7187         xmlXPathFreeObject(arg1);
7188         return(1);
7189     }
7190
7191     /*
7192      *If either argument is a nodeset, it's a 'special case'
7193      */
7194     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7195       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7196         /*
7197          *Hack it to assure arg1 is the nodeset
7198          */
7199         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7200                 argtmp = arg2;
7201                 arg2 = arg1;
7202                 arg1 = argtmp;
7203         }
7204         switch (arg2->type) {
7205             case XPATH_UNDEFINED:
7206 #ifdef DEBUG_EXPR
7207                 xmlGenericError(xmlGenericErrorContext,
7208                         "Equal: undefined\n");
7209 #endif
7210                 break;
7211             case XPATH_NODESET:
7212             case XPATH_XSLT_TREE:
7213                 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7214                 break;
7215             case XPATH_BOOLEAN:
7216                 if ((arg1->nodesetval == NULL) ||
7217                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
7218                 else
7219                     ret = 1;
7220                 ret = (ret == arg2->boolval);
7221                 break;
7222             case XPATH_NUMBER:
7223                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7224                 break;
7225             case XPATH_STRING:
7226                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7227                 break;
7228             case XPATH_USERS:
7229             case XPATH_POINT:
7230             case XPATH_RANGE:
7231             case XPATH_LOCATIONSET:
7232                 TODO
7233                 break;
7234         }
7235         xmlXPathReleaseObject(ctxt->context, arg1);
7236         xmlXPathReleaseObject(ctxt->context, arg2);
7237         return(ret);
7238     }
7239
7240     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7241 }
7242
7243 /**
7244  * xmlXPathNotEqualValues:
7245  * @ctxt:  the XPath Parser context
7246  *
7247  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7248  *
7249  * Returns 0 or 1 depending on the results of the test.
7250  */
7251 int
7252 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7253     xmlXPathObjectPtr arg1, arg2, argtmp;
7254     int ret = 0;
7255
7256     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7257     arg2 = valuePop(ctxt);
7258     arg1 = valuePop(ctxt);
7259     if ((arg1 == NULL) || (arg2 == NULL)) {
7260         if (arg1 != NULL)
7261             xmlXPathReleaseObject(ctxt->context, arg1);
7262         else
7263             xmlXPathReleaseObject(ctxt->context, arg2);
7264         XP_ERROR0(XPATH_INVALID_OPERAND);
7265     }
7266
7267     if (arg1 == arg2) {
7268 #ifdef DEBUG_EXPR
7269         xmlGenericError(xmlGenericErrorContext,
7270                 "NotEqual: by pointer\n");
7271 #endif
7272         xmlXPathReleaseObject(ctxt->context, arg1);
7273         return(0);
7274     }
7275
7276     /*
7277      *If either argument is a nodeset, it's a 'special case'
7278      */
7279     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7280       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7281         /*
7282          *Hack it to assure arg1 is the nodeset
7283          */
7284         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7285                 argtmp = arg2;
7286                 arg2 = arg1;
7287                 arg1 = argtmp;
7288         }
7289         switch (arg2->type) {
7290             case XPATH_UNDEFINED:
7291 #ifdef DEBUG_EXPR
7292                 xmlGenericError(xmlGenericErrorContext,
7293                         "NotEqual: undefined\n");
7294 #endif
7295                 break;
7296             case XPATH_NODESET:
7297             case XPATH_XSLT_TREE:
7298                 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7299                 break;
7300             case XPATH_BOOLEAN:
7301                 if ((arg1->nodesetval == NULL) ||
7302                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
7303                 else
7304                     ret = 1;
7305                 ret = (ret != arg2->boolval);
7306                 break;
7307             case XPATH_NUMBER:
7308                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7309                 break;
7310             case XPATH_STRING:
7311                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7312                 break;
7313             case XPATH_USERS:
7314             case XPATH_POINT:
7315             case XPATH_RANGE:
7316             case XPATH_LOCATIONSET:
7317                 TODO
7318                 break;
7319         }
7320         xmlXPathReleaseObject(ctxt->context, arg1);
7321         xmlXPathReleaseObject(ctxt->context, arg2);
7322         return(ret);
7323     }
7324
7325     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7326 }
7327
7328 /**
7329  * xmlXPathCompareValues:
7330  * @ctxt:  the XPath Parser context
7331  * @inf:  less than (1) or greater than (0)
7332  * @strict:  is the comparison strict
7333  *
7334  * Implement the compare operation on XPath objects:
7335  *     @arg1 < @arg2    (1, 1, ...
7336  *     @arg1 <= @arg2   (1, 0, ...
7337  *     @arg1 > @arg2    (0, 1, ...
7338  *     @arg1 >= @arg2   (0, 0, ...
7339  *
7340  * When neither object to be compared is a node-set and the operator is
7341  * <=, <, >=, >, then the objects are compared by converted both objects
7342  * to numbers and comparing the numbers according to IEEE 754. The <
7343  * comparison will be true if and only if the first number is less than the
7344  * second number. The <= comparison will be true if and only if the first
7345  * number is less than or equal to the second number. The > comparison
7346  * will be true if and only if the first number is greater than the second
7347  * number. The >= comparison will be true if and only if the first number
7348  * is greater than or equal to the second number.
7349  *
7350  * Returns 1 if the comparison succeeded, 0 if it failed
7351  */
7352 int
7353 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7354     int ret = 0, arg1i = 0, arg2i = 0;
7355     xmlXPathObjectPtr arg1, arg2;
7356
7357     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7358     arg2 = valuePop(ctxt);
7359     arg1 = valuePop(ctxt);
7360     if ((arg1 == NULL) || (arg2 == NULL)) {
7361         if (arg1 != NULL)
7362             xmlXPathReleaseObject(ctxt->context, arg1);
7363         else
7364             xmlXPathReleaseObject(ctxt->context, arg2);
7365         XP_ERROR0(XPATH_INVALID_OPERAND);
7366     }
7367
7368     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7369       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7370         /*
7371          * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7372          * are not freed from within this routine; they will be freed from the
7373          * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7374          */
7375         if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7376           ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7377             ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7378         } else {
7379             if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7380                 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7381                                                   arg1, arg2);
7382             } else {
7383                 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7384                                                   arg2, arg1);
7385             }
7386         }
7387         return(ret);
7388     }
7389
7390     if (arg1->type != XPATH_NUMBER) {
7391         valuePush(ctxt, arg1);
7392         xmlXPathNumberFunction(ctxt, 1);
7393         arg1 = valuePop(ctxt);
7394     }
7395     if (arg1->type != XPATH_NUMBER) {
7396         xmlXPathFreeObject(arg1);
7397         xmlXPathFreeObject(arg2);
7398         XP_ERROR0(XPATH_INVALID_OPERAND);
7399     }
7400     if (arg2->type != XPATH_NUMBER) {
7401         valuePush(ctxt, arg2);
7402         xmlXPathNumberFunction(ctxt, 1);
7403         arg2 = valuePop(ctxt);
7404     }
7405     if (arg2->type != XPATH_NUMBER) {
7406         xmlXPathReleaseObject(ctxt->context, arg1);
7407         xmlXPathReleaseObject(ctxt->context, arg2);
7408         XP_ERROR0(XPATH_INVALID_OPERAND);
7409     }
7410     /*
7411      * Add tests for infinity and nan
7412      * => feedback on 3.4 for Inf and NaN
7413      */
7414     /* Hand check NaN and Infinity comparisons */
7415     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7416         ret=0;
7417     } else {
7418         arg1i=xmlXPathIsInf(arg1->floatval);
7419         arg2i=xmlXPathIsInf(arg2->floatval);
7420         if (inf && strict) {
7421             if ((arg1i == -1 && arg2i != -1) ||
7422                 (arg2i == 1 && arg1i != 1)) {
7423                 ret = 1;
7424             } else if (arg1i == 0 && arg2i == 0) {
7425                 ret = (arg1->floatval < arg2->floatval);
7426             } else {
7427                 ret = 0;
7428             }
7429         }
7430         else if (inf && !strict) {
7431             if (arg1i == -1 || arg2i == 1) {
7432                 ret = 1;
7433             } else if (arg1i == 0 && arg2i == 0) {
7434                 ret = (arg1->floatval <= arg2->floatval);
7435             } else {
7436                 ret = 0;
7437             }
7438         }
7439         else if (!inf && strict) {
7440             if ((arg1i == 1 && arg2i != 1) ||
7441                 (arg2i == -1 && arg1i != -1)) {
7442                 ret = 1;
7443             } else if (arg1i == 0 && arg2i == 0) {
7444                 ret = (arg1->floatval > arg2->floatval);
7445             } else {
7446                 ret = 0;
7447             }
7448         }
7449         else if (!inf && !strict) {
7450             if (arg1i == 1 || arg2i == -1) {
7451                 ret = 1;
7452             } else if (arg1i == 0 && arg2i == 0) {
7453                 ret = (arg1->floatval >= arg2->floatval);
7454             } else {
7455                 ret = 0;
7456             }
7457         }
7458     }
7459     xmlXPathReleaseObject(ctxt->context, arg1);
7460     xmlXPathReleaseObject(ctxt->context, arg2);
7461     return(ret);
7462 }
7463
7464 /**
7465  * xmlXPathValueFlipSign:
7466  * @ctxt:  the XPath Parser context
7467  *
7468  * Implement the unary - operation on an XPath object
7469  * The numeric operators convert their operands to numbers as if
7470  * by calling the number function.
7471  */
7472 void
7473 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7474     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7475     CAST_TO_NUMBER;
7476     CHECK_TYPE(XPATH_NUMBER);
7477     if (xmlXPathIsNaN(ctxt->value->floatval))
7478         ctxt->value->floatval=xmlXPathNAN;
7479     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7480         ctxt->value->floatval=xmlXPathNINF;
7481     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7482         ctxt->value->floatval=xmlXPathPINF;
7483     else if (ctxt->value->floatval == 0) {
7484         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7485             ctxt->value->floatval = xmlXPathNZERO;
7486         else
7487             ctxt->value->floatval = 0;
7488     }
7489     else
7490         ctxt->value->floatval = - ctxt->value->floatval;
7491 }
7492
7493 /**
7494  * xmlXPathAddValues:
7495  * @ctxt:  the XPath Parser context
7496  *
7497  * Implement the add operation on XPath objects:
7498  * The numeric operators convert their operands to numbers as if
7499  * by calling the number function.
7500  */
7501 void
7502 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7503     xmlXPathObjectPtr arg;
7504     double val;
7505
7506     arg = valuePop(ctxt);
7507     if (arg == NULL)
7508         XP_ERROR(XPATH_INVALID_OPERAND);
7509     val = xmlXPathCastToNumber(arg);
7510     xmlXPathReleaseObject(ctxt->context, arg);
7511     CAST_TO_NUMBER;
7512     CHECK_TYPE(XPATH_NUMBER);
7513     ctxt->value->floatval += val;
7514 }
7515
7516 /**
7517  * xmlXPathSubValues:
7518  * @ctxt:  the XPath Parser context
7519  *
7520  * Implement the subtraction operation on XPath objects:
7521  * The numeric operators convert their operands to numbers as if
7522  * by calling the number function.
7523  */
7524 void
7525 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7526     xmlXPathObjectPtr arg;
7527     double val;
7528
7529     arg = valuePop(ctxt);
7530     if (arg == NULL)
7531         XP_ERROR(XPATH_INVALID_OPERAND);
7532     val = xmlXPathCastToNumber(arg);
7533     xmlXPathReleaseObject(ctxt->context, arg);
7534     CAST_TO_NUMBER;
7535     CHECK_TYPE(XPATH_NUMBER);
7536     ctxt->value->floatval -= val;
7537 }
7538
7539 /**
7540  * xmlXPathMultValues:
7541  * @ctxt:  the XPath Parser context
7542  *
7543  * Implement the multiply operation on XPath objects:
7544  * The numeric operators convert their operands to numbers as if
7545  * by calling the number function.
7546  */
7547 void
7548 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7549     xmlXPathObjectPtr arg;
7550     double val;
7551
7552     arg = valuePop(ctxt);
7553     if (arg == NULL)
7554         XP_ERROR(XPATH_INVALID_OPERAND);
7555     val = xmlXPathCastToNumber(arg);
7556     xmlXPathReleaseObject(ctxt->context, arg);
7557     CAST_TO_NUMBER;
7558     CHECK_TYPE(XPATH_NUMBER);
7559     ctxt->value->floatval *= val;
7560 }
7561
7562 /**
7563  * xmlXPathDivValues:
7564  * @ctxt:  the XPath Parser context
7565  *
7566  * Implement the div operation on XPath objects @arg1 / @arg2:
7567  * The numeric operators convert their operands to numbers as if
7568  * by calling the number function.
7569  */
7570 void
7571 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7572     xmlXPathObjectPtr arg;
7573     double val;
7574
7575     arg = valuePop(ctxt);
7576     if (arg == NULL)
7577         XP_ERROR(XPATH_INVALID_OPERAND);
7578     val = xmlXPathCastToNumber(arg);
7579     xmlXPathReleaseObject(ctxt->context, arg);
7580     CAST_TO_NUMBER;
7581     CHECK_TYPE(XPATH_NUMBER);
7582     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7583         ctxt->value->floatval = xmlXPathNAN;
7584     else if (val == 0 && xmlXPathGetSign(val) != 0) {
7585         if (ctxt->value->floatval == 0)
7586             ctxt->value->floatval = xmlXPathNAN;
7587         else if (ctxt->value->floatval > 0)
7588             ctxt->value->floatval = xmlXPathNINF;
7589         else if (ctxt->value->floatval < 0)
7590             ctxt->value->floatval = xmlXPathPINF;
7591     }
7592     else if (val == 0) {
7593         if (ctxt->value->floatval == 0)
7594             ctxt->value->floatval = xmlXPathNAN;
7595         else if (ctxt->value->floatval > 0)
7596             ctxt->value->floatval = xmlXPathPINF;
7597         else if (ctxt->value->floatval < 0)
7598             ctxt->value->floatval = xmlXPathNINF;
7599     } else
7600         ctxt->value->floatval /= val;
7601 }
7602
7603 /**
7604  * xmlXPathModValues:
7605  * @ctxt:  the XPath Parser context
7606  *
7607  * Implement the mod operation on XPath objects: @arg1 / @arg2
7608  * The numeric operators convert their operands to numbers as if
7609  * by calling the number function.
7610  */
7611 void
7612 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7613     xmlXPathObjectPtr arg;
7614     double arg1, arg2;
7615
7616     arg = valuePop(ctxt);
7617     if (arg == NULL)
7618         XP_ERROR(XPATH_INVALID_OPERAND);
7619     arg2 = xmlXPathCastToNumber(arg);
7620     xmlXPathReleaseObject(ctxt->context, arg);
7621     CAST_TO_NUMBER;
7622     CHECK_TYPE(XPATH_NUMBER);
7623     arg1 = ctxt->value->floatval;
7624     if (arg2 == 0)
7625         ctxt->value->floatval = xmlXPathNAN;
7626     else {
7627         ctxt->value->floatval = fmod(arg1, arg2);
7628     }
7629 }
7630
7631 /************************************************************************
7632  *                                                                      *
7633  *              The traversal functions                                 *
7634  *                                                                      *
7635  ************************************************************************/
7636
7637 /*
7638  * A traversal function enumerates nodes along an axis.
7639  * Initially it must be called with NULL, and it indicates
7640  * termination on the axis by returning NULL.
7641  */
7642 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7643                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7644
7645 /*
7646  * xmlXPathTraversalFunctionExt:
7647  * A traversal function enumerates nodes along an axis.
7648  * Initially it must be called with NULL, and it indicates
7649  * termination on the axis by returning NULL.
7650  * The context node of the traversal is specified via @contextNode.
7651  */
7652 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7653                     (xmlNodePtr cur, xmlNodePtr contextNode);
7654
7655 /*
7656  * xmlXPathNodeSetMergeFunction:
7657  * Used for merging node sets in xmlXPathCollectAndTest().
7658  */
7659 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7660                     (xmlNodeSetPtr, xmlNodeSetPtr, int);
7661
7662
7663 /**
7664  * xmlXPathNextSelf:
7665  * @ctxt:  the XPath Parser context
7666  * @cur:  the current node in the traversal
7667  *
7668  * Traversal function for the "self" direction
7669  * The self axis contains just the context node itself
7670  *
7671  * Returns the next element following that axis
7672  */
7673 xmlNodePtr
7674 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7675     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7676     if (cur == NULL)
7677         return(ctxt->context->node);
7678     return(NULL);
7679 }
7680
7681 /**
7682  * xmlXPathNextChild:
7683  * @ctxt:  the XPath Parser context
7684  * @cur:  the current node in the traversal
7685  *
7686  * Traversal function for the "child" direction
7687  * The child axis contains the children of the context node in document order.
7688  *
7689  * Returns the next element following that axis
7690  */
7691 xmlNodePtr
7692 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7693     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7694     if (cur == NULL) {
7695         if (ctxt->context->node == NULL) return(NULL);
7696         switch (ctxt->context->node->type) {
7697             case XML_ELEMENT_NODE:
7698             case XML_TEXT_NODE:
7699             case XML_CDATA_SECTION_NODE:
7700             case XML_ENTITY_REF_NODE:
7701             case XML_ENTITY_NODE:
7702             case XML_PI_NODE:
7703             case XML_COMMENT_NODE:
7704             case XML_NOTATION_NODE:
7705             case XML_DTD_NODE:
7706                 return(ctxt->context->node->children);
7707             case XML_DOCUMENT_NODE:
7708             case XML_DOCUMENT_TYPE_NODE:
7709             case XML_DOCUMENT_FRAG_NODE:
7710             case XML_HTML_DOCUMENT_NODE:
7711 #ifdef LIBXML_DOCB_ENABLED
7712             case XML_DOCB_DOCUMENT_NODE:
7713 #endif
7714                 return(((xmlDocPtr) ctxt->context->node)->children);
7715             case XML_ELEMENT_DECL:
7716             case XML_ATTRIBUTE_DECL:
7717             case XML_ENTITY_DECL:
7718             case XML_ATTRIBUTE_NODE:
7719             case XML_NAMESPACE_DECL:
7720             case XML_XINCLUDE_START:
7721             case XML_XINCLUDE_END:
7722                 return(NULL);
7723         }
7724         return(NULL);
7725     }
7726     if ((cur->type == XML_DOCUMENT_NODE) ||
7727         (cur->type == XML_HTML_DOCUMENT_NODE))
7728         return(NULL);
7729     return(cur->next);
7730 }
7731
7732 /**
7733  * xmlXPathNextChildElement:
7734  * @ctxt:  the XPath Parser context
7735  * @cur:  the current node in the traversal
7736  *
7737  * Traversal function for the "child" direction and nodes of type element.
7738  * The child axis contains the children of the context node in document order.
7739  *
7740  * Returns the next element following that axis
7741  */
7742 static xmlNodePtr
7743 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7744     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7745     if (cur == NULL) {
7746         cur = ctxt->context->node;
7747         if (cur == NULL) return(NULL);
7748         /*
7749         * Get the first element child.
7750         */
7751         switch (cur->type) {
7752             case XML_ELEMENT_NODE:
7753             case XML_DOCUMENT_FRAG_NODE:
7754             case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7755             case XML_ENTITY_NODE:
7756                 cur = cur->children;
7757                 if (cur != NULL) {
7758                     if (cur->type == XML_ELEMENT_NODE)
7759                         return(cur);
7760                     do {
7761                         cur = cur->next;
7762                     } while ((cur != NULL) &&
7763                         (cur->type != XML_ELEMENT_NODE));
7764                     return(cur);
7765                 }
7766                 return(NULL);
7767             case XML_DOCUMENT_NODE:
7768             case XML_HTML_DOCUMENT_NODE:
7769 #ifdef LIBXML_DOCB_ENABLED
7770             case XML_DOCB_DOCUMENT_NODE:
7771 #endif
7772                 return(xmlDocGetRootElement((xmlDocPtr) cur));
7773             default:
7774                 return(NULL);
7775         }
7776         return(NULL);
7777     }
7778     /*
7779     * Get the next sibling element node.
7780     */
7781     switch (cur->type) {
7782         case XML_ELEMENT_NODE:
7783         case XML_TEXT_NODE:
7784         case XML_ENTITY_REF_NODE:
7785         case XML_ENTITY_NODE:
7786         case XML_CDATA_SECTION_NODE:
7787         case XML_PI_NODE:
7788         case XML_COMMENT_NODE:
7789         case XML_XINCLUDE_END:
7790             break;
7791         /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7792         default:
7793             return(NULL);
7794     }
7795     if (cur->next != NULL) {
7796         if (cur->next->type == XML_ELEMENT_NODE)
7797             return(cur->next);
7798         cur = cur->next;
7799         do {
7800             cur = cur->next;
7801         } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7802         return(cur);
7803     }
7804     return(NULL);
7805 }
7806
7807 #if 0
7808 /**
7809  * xmlXPathNextDescendantOrSelfElemParent:
7810  * @ctxt:  the XPath Parser context
7811  * @cur:  the current node in the traversal
7812  *
7813  * Traversal function for the "descendant-or-self" axis.
7814  * Additionally it returns only nodes which can be parents of
7815  * element nodes.
7816  *
7817  *
7818  * Returns the next element following that axis
7819  */
7820 static xmlNodePtr
7821 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7822                                        xmlNodePtr contextNode)
7823 {
7824     if (cur == NULL) {
7825         if (contextNode == NULL)
7826             return(NULL);
7827         switch (contextNode->type) {
7828             case XML_ELEMENT_NODE:
7829             case XML_XINCLUDE_START:
7830             case XML_DOCUMENT_FRAG_NODE:
7831             case XML_DOCUMENT_NODE:
7832 #ifdef LIBXML_DOCB_ENABLED
7833             case XML_DOCB_DOCUMENT_NODE:
7834 #endif
7835             case XML_HTML_DOCUMENT_NODE:
7836                 return(contextNode);
7837             default:
7838                 return(NULL);
7839         }
7840         return(NULL);
7841     } else {
7842         xmlNodePtr start = cur;
7843
7844         while (cur != NULL) {
7845             switch (cur->type) {
7846                 case XML_ELEMENT_NODE:
7847                 /* TODO: OK to have XInclude here? */
7848                 case XML_XINCLUDE_START:
7849                 case XML_DOCUMENT_FRAG_NODE:
7850                     if (cur != start)
7851                         return(cur);
7852                     if (cur->children != NULL) {
7853                         cur = cur->children;
7854                         continue;
7855                     }
7856                     break;
7857                 /* Not sure if we need those here. */
7858                 case XML_DOCUMENT_NODE:
7859 #ifdef LIBXML_DOCB_ENABLED
7860                 case XML_DOCB_DOCUMENT_NODE:
7861 #endif
7862                 case XML_HTML_DOCUMENT_NODE:
7863                     if (cur != start)
7864                         return(cur);
7865                     return(xmlDocGetRootElement((xmlDocPtr) cur));
7866                 default:
7867                     break;
7868             }
7869
7870 next_sibling:
7871             if ((cur == NULL) || (cur == contextNode))
7872                 return(NULL);
7873             if (cur->next != NULL) {
7874                 cur = cur->next;
7875             } else {
7876                 cur = cur->parent;
7877                 goto next_sibling;
7878             }
7879         }
7880     }
7881     return(NULL);
7882 }
7883 #endif
7884
7885 /**
7886  * xmlXPathNextDescendant:
7887  * @ctxt:  the XPath Parser context
7888  * @cur:  the current node in the traversal
7889  *
7890  * Traversal function for the "descendant" direction
7891  * the descendant axis contains the descendants of the context node in document
7892  * order; a descendant is a child or a child of a child and so on.
7893  *
7894  * Returns the next element following that axis
7895  */
7896 xmlNodePtr
7897 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7898     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7899     if (cur == NULL) {
7900         if (ctxt->context->node == NULL)
7901             return(NULL);
7902         if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7903             (ctxt->context->node->type == XML_NAMESPACE_DECL))
7904             return(NULL);
7905
7906         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7907             return(ctxt->context->doc->children);
7908         return(ctxt->context->node->children);
7909     }
7910
7911     if (cur->type == XML_NAMESPACE_DECL)
7912         return(NULL);
7913     if (cur->children != NULL) {
7914         /*
7915          * Do not descend on entities declarations
7916          */
7917         if (cur->children->type != XML_ENTITY_DECL) {
7918             cur = cur->children;
7919             /*
7920              * Skip DTDs
7921              */
7922             if (cur->type != XML_DTD_NODE)
7923                 return(cur);
7924         }
7925     }
7926
7927     if (cur == ctxt->context->node) return(NULL);
7928
7929     while (cur->next != NULL) {
7930         cur = cur->next;
7931         if ((cur->type != XML_ENTITY_DECL) &&
7932             (cur->type != XML_DTD_NODE))
7933             return(cur);
7934     }
7935
7936     do {
7937         cur = cur->parent;
7938         if (cur == NULL) break;
7939         if (cur == ctxt->context->node) return(NULL);
7940         if (cur->next != NULL) {
7941             cur = cur->next;
7942             return(cur);
7943         }
7944     } while (cur != NULL);
7945     return(cur);
7946 }
7947
7948 /**
7949  * xmlXPathNextDescendantOrSelf:
7950  * @ctxt:  the XPath Parser context
7951  * @cur:  the current node in the traversal
7952  *
7953  * Traversal function for the "descendant-or-self" direction
7954  * the descendant-or-self axis contains the context node and the descendants
7955  * of the context node in document order; thus the context node is the first
7956  * node on the axis, and the first child of the context node is the second node
7957  * on the axis
7958  *
7959  * Returns the next element following that axis
7960  */
7961 xmlNodePtr
7962 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7963     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7964     if (cur == NULL)
7965         return(ctxt->context->node);
7966
7967     if (ctxt->context->node == NULL)
7968         return(NULL);
7969     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7970         (ctxt->context->node->type == XML_NAMESPACE_DECL))
7971         return(NULL);
7972
7973     return(xmlXPathNextDescendant(ctxt, cur));
7974 }
7975
7976 /**
7977  * xmlXPathNextParent:
7978  * @ctxt:  the XPath Parser context
7979  * @cur:  the current node in the traversal
7980  *
7981  * Traversal function for the "parent" direction
7982  * The parent axis contains the parent of the context node, if there is one.
7983  *
7984  * Returns the next element following that axis
7985  */
7986 xmlNodePtr
7987 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7988     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7989     /*
7990      * the parent of an attribute or namespace node is the element
7991      * to which the attribute or namespace node is attached
7992      * Namespace handling !!!
7993      */
7994     if (cur == NULL) {
7995         if (ctxt->context->node == NULL) return(NULL);
7996         switch (ctxt->context->node->type) {
7997             case XML_ELEMENT_NODE:
7998             case XML_TEXT_NODE:
7999             case XML_CDATA_SECTION_NODE:
8000             case XML_ENTITY_REF_NODE:
8001             case XML_ENTITY_NODE:
8002             case XML_PI_NODE:
8003             case XML_COMMENT_NODE:
8004             case XML_NOTATION_NODE:
8005             case XML_DTD_NODE:
8006             case XML_ELEMENT_DECL:
8007             case XML_ATTRIBUTE_DECL:
8008             case XML_XINCLUDE_START:
8009             case XML_XINCLUDE_END:
8010             case XML_ENTITY_DECL:
8011                 if (ctxt->context->node->parent == NULL)
8012                     return((xmlNodePtr) ctxt->context->doc);
8013                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8014                     ((ctxt->context->node->parent->name[0] == ' ') ||
8015                      (xmlStrEqual(ctxt->context->node->parent->name,
8016                                  BAD_CAST "fake node libxslt"))))
8017                     return(NULL);
8018                 return(ctxt->context->node->parent);
8019             case XML_ATTRIBUTE_NODE: {
8020                 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8021
8022                 return(att->parent);
8023             }
8024             case XML_DOCUMENT_NODE:
8025             case XML_DOCUMENT_TYPE_NODE:
8026             case XML_DOCUMENT_FRAG_NODE:
8027             case XML_HTML_DOCUMENT_NODE:
8028 #ifdef LIBXML_DOCB_ENABLED
8029             case XML_DOCB_DOCUMENT_NODE:
8030 #endif
8031                 return(NULL);
8032             case XML_NAMESPACE_DECL: {
8033                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8034
8035                 if ((ns->next != NULL) &&
8036                     (ns->next->type != XML_NAMESPACE_DECL))
8037                     return((xmlNodePtr) ns->next);
8038                 return(NULL);
8039             }
8040         }
8041     }
8042     return(NULL);
8043 }
8044
8045 /**
8046  * xmlXPathNextAncestor:
8047  * @ctxt:  the XPath Parser context
8048  * @cur:  the current node in the traversal
8049  *
8050  * Traversal function for the "ancestor" direction
8051  * the ancestor axis contains the ancestors of the context node; the ancestors
8052  * of the context node consist of the parent of context node and the parent's
8053  * parent and so on; the nodes are ordered in reverse document order; thus the
8054  * parent is the first node on the axis, and the parent's parent is the second
8055  * node on the axis
8056  *
8057  * Returns the next element following that axis
8058  */
8059 xmlNodePtr
8060 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8061     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8062     /*
8063      * the parent of an attribute or namespace node is the element
8064      * to which the attribute or namespace node is attached
8065      * !!!!!!!!!!!!!
8066      */
8067     if (cur == NULL) {
8068         if (ctxt->context->node == NULL) return(NULL);
8069         switch (ctxt->context->node->type) {
8070             case XML_ELEMENT_NODE:
8071             case XML_TEXT_NODE:
8072             case XML_CDATA_SECTION_NODE:
8073             case XML_ENTITY_REF_NODE:
8074             case XML_ENTITY_NODE:
8075             case XML_PI_NODE:
8076             case XML_COMMENT_NODE:
8077             case XML_DTD_NODE:
8078             case XML_ELEMENT_DECL:
8079             case XML_ATTRIBUTE_DECL:
8080             case XML_ENTITY_DECL:
8081             case XML_NOTATION_NODE:
8082             case XML_XINCLUDE_START:
8083             case XML_XINCLUDE_END:
8084                 if (ctxt->context->node->parent == NULL)
8085                     return((xmlNodePtr) ctxt->context->doc);
8086                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8087                     ((ctxt->context->node->parent->name[0] == ' ') ||
8088                      (xmlStrEqual(ctxt->context->node->parent->name,
8089                                  BAD_CAST "fake node libxslt"))))
8090                     return(NULL);
8091                 return(ctxt->context->node->parent);
8092             case XML_ATTRIBUTE_NODE: {
8093                 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8094
8095                 return(tmp->parent);
8096             }
8097             case XML_DOCUMENT_NODE:
8098             case XML_DOCUMENT_TYPE_NODE:
8099             case XML_DOCUMENT_FRAG_NODE:
8100             case XML_HTML_DOCUMENT_NODE:
8101 #ifdef LIBXML_DOCB_ENABLED
8102             case XML_DOCB_DOCUMENT_NODE:
8103 #endif
8104                 return(NULL);
8105             case XML_NAMESPACE_DECL: {
8106                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8107
8108                 if ((ns->next != NULL) &&
8109                     (ns->next->type != XML_NAMESPACE_DECL))
8110                     return((xmlNodePtr) ns->next);
8111                 /* Bad, how did that namespace end up here ? */
8112                 return(NULL);
8113             }
8114         }
8115         return(NULL);
8116     }
8117     if (cur == ctxt->context->doc->children)
8118         return((xmlNodePtr) ctxt->context->doc);
8119     if (cur == (xmlNodePtr) ctxt->context->doc)
8120         return(NULL);
8121     switch (cur->type) {
8122         case XML_ELEMENT_NODE:
8123         case XML_TEXT_NODE:
8124         case XML_CDATA_SECTION_NODE:
8125         case XML_ENTITY_REF_NODE:
8126         case XML_ENTITY_NODE:
8127         case XML_PI_NODE:
8128         case XML_COMMENT_NODE:
8129         case XML_NOTATION_NODE:
8130         case XML_DTD_NODE:
8131         case XML_ELEMENT_DECL:
8132         case XML_ATTRIBUTE_DECL:
8133         case XML_ENTITY_DECL:
8134         case XML_XINCLUDE_START:
8135         case XML_XINCLUDE_END:
8136             if (cur->parent == NULL)
8137                 return(NULL);
8138             if ((cur->parent->type == XML_ELEMENT_NODE) &&
8139                 ((cur->parent->name[0] == ' ') ||
8140                  (xmlStrEqual(cur->parent->name,
8141                               BAD_CAST "fake node libxslt"))))
8142                 return(NULL);
8143             return(cur->parent);
8144         case XML_ATTRIBUTE_NODE: {
8145             xmlAttrPtr att = (xmlAttrPtr) cur;
8146
8147             return(att->parent);
8148         }
8149         case XML_NAMESPACE_DECL: {
8150             xmlNsPtr ns = (xmlNsPtr) cur;
8151
8152             if ((ns->next != NULL) &&
8153                 (ns->next->type != XML_NAMESPACE_DECL))
8154                 return((xmlNodePtr) ns->next);
8155             /* Bad, how did that namespace end up here ? */
8156             return(NULL);
8157         }
8158         case XML_DOCUMENT_NODE:
8159         case XML_DOCUMENT_TYPE_NODE:
8160         case XML_DOCUMENT_FRAG_NODE:
8161         case XML_HTML_DOCUMENT_NODE:
8162 #ifdef LIBXML_DOCB_ENABLED
8163         case XML_DOCB_DOCUMENT_NODE:
8164 #endif
8165             return(NULL);
8166     }
8167     return(NULL);
8168 }
8169
8170 /**
8171  * xmlXPathNextAncestorOrSelf:
8172  * @ctxt:  the XPath Parser context
8173  * @cur:  the current node in the traversal
8174  *
8175  * Traversal function for the "ancestor-or-self" direction
8176  * he ancestor-or-self axis contains the context node and ancestors of
8177  * the context node in reverse document order; thus the context node is
8178  * the first node on the axis, and the context node's parent the second;
8179  * parent here is defined the same as with the parent axis.
8180  *
8181  * Returns the next element following that axis
8182  */
8183 xmlNodePtr
8184 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8185     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8186     if (cur == NULL)
8187         return(ctxt->context->node);
8188     return(xmlXPathNextAncestor(ctxt, cur));
8189 }
8190
8191 /**
8192  * xmlXPathNextFollowingSibling:
8193  * @ctxt:  the XPath Parser context
8194  * @cur:  the current node in the traversal
8195  *
8196  * Traversal function for the "following-sibling" direction
8197  * The following-sibling axis contains the following siblings of the context
8198  * node in document order.
8199  *
8200  * Returns the next element following that axis
8201  */
8202 xmlNodePtr
8203 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8204     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8205     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8206         (ctxt->context->node->type == XML_NAMESPACE_DECL))
8207         return(NULL);
8208     if (cur == (xmlNodePtr) ctxt->context->doc)
8209         return(NULL);
8210     if (cur == NULL)
8211         return(ctxt->context->node->next);
8212     return(cur->next);
8213 }
8214
8215 /**
8216  * xmlXPathNextPrecedingSibling:
8217  * @ctxt:  the XPath Parser context
8218  * @cur:  the current node in the traversal
8219  *
8220  * Traversal function for the "preceding-sibling" direction
8221  * The preceding-sibling axis contains the preceding siblings of the context
8222  * node in reverse document order; the first preceding sibling is first on the
8223  * axis; the sibling preceding that node is the second on the axis and so on.
8224  *
8225  * Returns the next element following that axis
8226  */
8227 xmlNodePtr
8228 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8229     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8230     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8231         (ctxt->context->node->type == XML_NAMESPACE_DECL))
8232         return(NULL);
8233     if (cur == (xmlNodePtr) ctxt->context->doc)
8234         return(NULL);
8235     if (cur == NULL)
8236         return(ctxt->context->node->prev);
8237     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8238         cur = cur->prev;
8239         if (cur == NULL)
8240             return(ctxt->context->node->prev);
8241     }
8242     return(cur->prev);
8243 }
8244
8245 /**
8246  * xmlXPathNextFollowing:
8247  * @ctxt:  the XPath Parser context
8248  * @cur:  the current node in the traversal
8249  *
8250  * Traversal function for the "following" direction
8251  * The following axis contains all nodes in the same document as the context
8252  * node that are after the context node in document order, excluding any
8253  * descendants and excluding attribute nodes and namespace nodes; the nodes
8254  * are ordered in document order
8255  *
8256  * Returns the next element following that axis
8257  */
8258 xmlNodePtr
8259 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8260     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8261     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8262         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8263         return(cur->children);
8264
8265     if (cur == NULL) {
8266         cur = ctxt->context->node;
8267         if (cur->type == XML_ATTRIBUTE_NODE) {
8268             cur = cur->parent;
8269         } else if (cur->type == XML_NAMESPACE_DECL) {
8270             xmlNsPtr ns = (xmlNsPtr) cur;
8271
8272             if ((ns->next == NULL) ||
8273                 (ns->next->type == XML_NAMESPACE_DECL))
8274                 return (NULL);
8275             cur = (xmlNodePtr) ns->next;
8276         }
8277     }
8278     if (cur == NULL) return(NULL) ; /* ERROR */
8279     if (cur->next != NULL) return(cur->next) ;
8280     do {
8281         cur = cur->parent;
8282         if (cur == NULL) break;
8283         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8284         if (cur->next != NULL) return(cur->next);
8285     } while (cur != NULL);
8286     return(cur);
8287 }
8288
8289 /*
8290  * xmlXPathIsAncestor:
8291  * @ancestor:  the ancestor node
8292  * @node:  the current node
8293  *
8294  * Check that @ancestor is a @node's ancestor
8295  *
8296  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8297  */
8298 static int
8299 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8300     if ((ancestor == NULL) || (node == NULL)) return(0);
8301     if (node->type == XML_NAMESPACE_DECL)
8302         return(0);
8303     if (ancestor->type == XML_NAMESPACE_DECL)
8304         return(0);
8305     /* nodes need to be in the same document */
8306     if (ancestor->doc != node->doc) return(0);
8307     /* avoid searching if ancestor or node is the root node */
8308     if (ancestor == (xmlNodePtr) node->doc) return(1);
8309     if (node == (xmlNodePtr) ancestor->doc) return(0);
8310     while (node->parent != NULL) {
8311         if (node->parent == ancestor)
8312             return(1);
8313         node = node->parent;
8314     }
8315     return(0);
8316 }
8317
8318 /**
8319  * xmlXPathNextPreceding:
8320  * @ctxt:  the XPath Parser context
8321  * @cur:  the current node in the traversal
8322  *
8323  * Traversal function for the "preceding" direction
8324  * the preceding axis contains all nodes in the same document as the context
8325  * node that are before the context node in document order, excluding any
8326  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8327  * ordered in reverse document order
8328  *
8329  * Returns the next element following that axis
8330  */
8331 xmlNodePtr
8332 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8333 {
8334     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8335     if (cur == NULL) {
8336         cur = ctxt->context->node;
8337         if (cur->type == XML_ATTRIBUTE_NODE) {
8338             cur = cur->parent;
8339         } else if (cur->type == XML_NAMESPACE_DECL) {
8340             xmlNsPtr ns = (xmlNsPtr) cur;
8341
8342             if ((ns->next == NULL) ||
8343                 (ns->next->type == XML_NAMESPACE_DECL))
8344                 return (NULL);
8345             cur = (xmlNodePtr) ns->next;
8346         }
8347     }
8348     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8349         return (NULL);
8350     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8351         cur = cur->prev;
8352     do {
8353         if (cur->prev != NULL) {
8354             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8355             return (cur);
8356         }
8357
8358         cur = cur->parent;
8359         if (cur == NULL)
8360             return (NULL);
8361         if (cur == ctxt->context->doc->children)
8362             return (NULL);
8363     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8364     return (cur);
8365 }
8366
8367 /**
8368  * xmlXPathNextPrecedingInternal:
8369  * @ctxt:  the XPath Parser context
8370  * @cur:  the current node in the traversal
8371  *
8372  * Traversal function for the "preceding" direction
8373  * the preceding axis contains all nodes in the same document as the context
8374  * node that are before the context node in document order, excluding any
8375  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8376  * ordered in reverse document order
8377  * This is a faster implementation but internal only since it requires a
8378  * state kept in the parser context: ctxt->ancestor.
8379  *
8380  * Returns the next element following that axis
8381  */
8382 static xmlNodePtr
8383 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8384                               xmlNodePtr cur)
8385 {
8386     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8387     if (cur == NULL) {
8388         cur = ctxt->context->node;
8389         if (cur == NULL)
8390             return (NULL);
8391         if (cur->type == XML_ATTRIBUTE_NODE) {
8392             cur = cur->parent;
8393         } else if (cur->type == XML_NAMESPACE_DECL) {
8394             xmlNsPtr ns = (xmlNsPtr) cur;
8395
8396             if ((ns->next == NULL) ||
8397                 (ns->next->type == XML_NAMESPACE_DECL))
8398                 return (NULL);
8399             cur = (xmlNodePtr) ns->next;
8400         }
8401         ctxt->ancestor = cur->parent;
8402     }
8403     if (cur->type == XML_NAMESPACE_DECL)
8404         return(NULL);
8405     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8406         cur = cur->prev;
8407     while (cur->prev == NULL) {
8408         cur = cur->parent;
8409         if (cur == NULL)
8410             return (NULL);
8411         if (cur == ctxt->context->doc->children)
8412             return (NULL);
8413         if (cur != ctxt->ancestor)
8414             return (cur);
8415         ctxt->ancestor = cur->parent;
8416     }
8417     cur = cur->prev;
8418     while (cur->last != NULL)
8419         cur = cur->last;
8420     return (cur);
8421 }
8422
8423 /**
8424  * xmlXPathNextNamespace:
8425  * @ctxt:  the XPath Parser context
8426  * @cur:  the current attribute in the traversal
8427  *
8428  * Traversal function for the "namespace" direction
8429  * the namespace axis contains the namespace nodes of the context node;
8430  * the order of nodes on this axis is implementation-defined; the axis will
8431  * be empty unless the context node is an element
8432  *
8433  * We keep the XML namespace node at the end of the list.
8434  *
8435  * Returns the next element following that axis
8436  */
8437 xmlNodePtr
8438 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8439     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8440     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8441     if (cur == NULL) {
8442         if (ctxt->context->tmpNsList != NULL)
8443             xmlFree(ctxt->context->tmpNsList);
8444         ctxt->context->tmpNsList =
8445             xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8446         ctxt->context->tmpNsNr = 0;
8447         if (ctxt->context->tmpNsList != NULL) {
8448             while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8449                 ctxt->context->tmpNsNr++;
8450             }
8451         }
8452         return((xmlNodePtr) xmlXPathXMLNamespace);
8453     }
8454     if (ctxt->context->tmpNsNr > 0) {
8455         return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8456     } else {
8457         if (ctxt->context->tmpNsList != NULL)
8458             xmlFree(ctxt->context->tmpNsList);
8459         ctxt->context->tmpNsList = NULL;
8460         return(NULL);
8461     }
8462 }
8463
8464 /**
8465  * xmlXPathNextAttribute:
8466  * @ctxt:  the XPath Parser context
8467  * @cur:  the current attribute in the traversal
8468  *
8469  * Traversal function for the "attribute" direction
8470  * TODO: support DTD inherited default attributes
8471  *
8472  * Returns the next element following that axis
8473  */
8474 xmlNodePtr
8475 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8476     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8477     if (ctxt->context->node == NULL)
8478         return(NULL);
8479     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8480         return(NULL);
8481     if (cur == NULL) {
8482         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8483             return(NULL);
8484         return((xmlNodePtr)ctxt->context->node->properties);
8485     }
8486     return((xmlNodePtr)cur->next);
8487 }
8488
8489 /************************************************************************
8490  *                                                                      *
8491  *              NodeTest Functions                                      *
8492  *                                                                      *
8493  ************************************************************************/
8494
8495 #define IS_FUNCTION                     200
8496
8497
8498 /************************************************************************
8499  *                                                                      *
8500  *              Implicit tree core function library                     *
8501  *                                                                      *
8502  ************************************************************************/
8503
8504 /**
8505  * xmlXPathRoot:
8506  * @ctxt:  the XPath Parser context
8507  *
8508  * Initialize the context to the root of the document
8509  */
8510 void
8511 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8512     if ((ctxt == NULL) || (ctxt->context == NULL))
8513         return;
8514     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8515     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8516         ctxt->context->node));
8517 }
8518
8519 /************************************************************************
8520  *                                                                      *
8521  *              The explicit core function library                      *
8522  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8523  *                                                                      *
8524  ************************************************************************/
8525
8526
8527 /**
8528  * xmlXPathLastFunction:
8529  * @ctxt:  the XPath Parser context
8530  * @nargs:  the number of arguments
8531  *
8532  * Implement the last() XPath function
8533  *    number last()
8534  * The last function returns the number of nodes in the context node list.
8535  */
8536 void
8537 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8538     CHECK_ARITY(0);
8539     if (ctxt->context->contextSize >= 0) {
8540         valuePush(ctxt,
8541             xmlXPathCacheNewFloat(ctxt->context,
8542                 (double) ctxt->context->contextSize));
8543 #ifdef DEBUG_EXPR
8544         xmlGenericError(xmlGenericErrorContext,
8545                 "last() : %d\n", ctxt->context->contextSize);
8546 #endif
8547     } else {
8548         XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8549     }
8550 }
8551
8552 /**
8553  * xmlXPathPositionFunction:
8554  * @ctxt:  the XPath Parser context
8555  * @nargs:  the number of arguments
8556  *
8557  * Implement the position() XPath function
8558  *    number position()
8559  * The position function returns the position of the context node in the
8560  * context node list. The first position is 1, and so the last position
8561  * will be equal to last().
8562  */
8563 void
8564 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8565     CHECK_ARITY(0);
8566     if (ctxt->context->proximityPosition >= 0) {
8567         valuePush(ctxt,
8568               xmlXPathCacheNewFloat(ctxt->context,
8569                 (double) ctxt->context->proximityPosition));
8570 #ifdef DEBUG_EXPR
8571         xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8572                 ctxt->context->proximityPosition);
8573 #endif
8574     } else {
8575         XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8576     }
8577 }
8578
8579 /**
8580  * xmlXPathCountFunction:
8581  * @ctxt:  the XPath Parser context
8582  * @nargs:  the number of arguments
8583  *
8584  * Implement the count() XPath function
8585  *    number count(node-set)
8586  */
8587 void
8588 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8589     xmlXPathObjectPtr cur;
8590
8591     CHECK_ARITY(1);
8592     if ((ctxt->value == NULL) ||
8593         ((ctxt->value->type != XPATH_NODESET) &&
8594          (ctxt->value->type != XPATH_XSLT_TREE)))
8595         XP_ERROR(XPATH_INVALID_TYPE);
8596     cur = valuePop(ctxt);
8597
8598     if ((cur == NULL) || (cur->nodesetval == NULL))
8599         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8600     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8601         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8602             (double) cur->nodesetval->nodeNr));
8603     } else {
8604         if ((cur->nodesetval->nodeNr != 1) ||
8605             (cur->nodesetval->nodeTab == NULL)) {
8606             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8607         } else {
8608             xmlNodePtr tmp;
8609             int i = 0;
8610
8611             tmp = cur->nodesetval->nodeTab[0];
8612             if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8613                 tmp = tmp->children;
8614                 while (tmp != NULL) {
8615                     tmp = tmp->next;
8616                     i++;
8617                 }
8618             }
8619             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8620         }
8621     }
8622     xmlXPathReleaseObject(ctxt->context, cur);
8623 }
8624
8625 /**
8626  * xmlXPathGetElementsByIds:
8627  * @doc:  the document
8628  * @ids:  a whitespace separated list of IDs
8629  *
8630  * Selects elements by their unique ID.
8631  *
8632  * Returns a node-set of selected elements.
8633  */
8634 static xmlNodeSetPtr
8635 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8636     xmlNodeSetPtr ret;
8637     const xmlChar *cur = ids;
8638     xmlChar *ID;
8639     xmlAttrPtr attr;
8640     xmlNodePtr elem = NULL;
8641
8642     if (ids == NULL) return(NULL);
8643
8644     ret = xmlXPathNodeSetCreate(NULL);
8645     if (ret == NULL)
8646         return(ret);
8647
8648     while (IS_BLANK_CH(*cur)) cur++;
8649     while (*cur != 0) {
8650         while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8651             cur++;
8652
8653         ID = xmlStrndup(ids, cur - ids);
8654         if (ID != NULL) {
8655             /*
8656              * We used to check the fact that the value passed
8657              * was an NCName, but this generated much troubles for
8658              * me and Aleksey Sanin, people blatantly violated that
8659              * constaint, like Visa3D spec.
8660              * if (xmlValidateNCName(ID, 1) == 0)
8661              */
8662             attr = xmlGetID(doc, ID);
8663             if (attr != NULL) {
8664                 if (attr->type == XML_ATTRIBUTE_NODE)
8665                     elem = attr->parent;
8666                 else if (attr->type == XML_ELEMENT_NODE)
8667                     elem = (xmlNodePtr) attr;
8668                 else
8669                     elem = NULL;
8670                 if (elem != NULL)
8671                     xmlXPathNodeSetAdd(ret, elem);
8672             }
8673             xmlFree(ID);
8674         }
8675
8676         while (IS_BLANK_CH(*cur)) cur++;
8677         ids = cur;
8678     }
8679     return(ret);
8680 }
8681
8682 /**
8683  * xmlXPathIdFunction:
8684  * @ctxt:  the XPath Parser context
8685  * @nargs:  the number of arguments
8686  *
8687  * Implement the id() XPath function
8688  *    node-set id(object)
8689  * The id function selects elements by their unique ID
8690  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8691  * then the result is the union of the result of applying id to the
8692  * string value of each of the nodes in the argument node-set. When the
8693  * argument to id is of any other type, the argument is converted to a
8694  * string as if by a call to the string function; the string is split
8695  * into a whitespace-separated list of tokens (whitespace is any sequence
8696  * of characters matching the production S); the result is a node-set
8697  * containing the elements in the same document as the context node that
8698  * have a unique ID equal to any of the tokens in the list.
8699  */
8700 void
8701 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8702     xmlChar *tokens;
8703     xmlNodeSetPtr ret;
8704     xmlXPathObjectPtr obj;
8705
8706     CHECK_ARITY(1);
8707     obj = valuePop(ctxt);
8708     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8709     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8710         xmlNodeSetPtr ns;
8711         int i;
8712
8713         ret = xmlXPathNodeSetCreate(NULL);
8714         /*
8715          * FIXME -- in an out-of-memory condition this will behave badly.
8716          * The solution is not clear -- we already popped an item from
8717          * ctxt, so the object is in a corrupt state.
8718          */
8719
8720         if (obj->nodesetval != NULL) {
8721             for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8722                 tokens =
8723                     xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8724                 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8725                 ret = xmlXPathNodeSetMerge(ret, ns);
8726                 xmlXPathFreeNodeSet(ns);
8727                 if (tokens != NULL)
8728                     xmlFree(tokens);
8729             }
8730         }
8731         xmlXPathReleaseObject(ctxt->context, obj);
8732         valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8733         return;
8734     }
8735     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8736     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8737     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8738     xmlXPathReleaseObject(ctxt->context, obj);
8739     return;
8740 }
8741
8742 /**
8743  * xmlXPathLocalNameFunction:
8744  * @ctxt:  the XPath Parser context
8745  * @nargs:  the number of arguments
8746  *
8747  * Implement the local-name() XPath function
8748  *    string local-name(node-set?)
8749  * The local-name function returns a string containing the local part
8750  * of the name of the node in the argument node-set that is first in
8751  * document order. If the node-set is empty or the first node has no
8752  * name, an empty string is returned. If the argument is omitted it
8753  * defaults to the context node.
8754  */
8755 void
8756 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8757     xmlXPathObjectPtr cur;
8758
8759     if (ctxt == NULL) return;
8760
8761     if (nargs == 0) {
8762         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8763             ctxt->context->node));
8764         nargs = 1;
8765     }
8766
8767     CHECK_ARITY(1);
8768     if ((ctxt->value == NULL) ||
8769         ((ctxt->value->type != XPATH_NODESET) &&
8770          (ctxt->value->type != XPATH_XSLT_TREE)))
8771         XP_ERROR(XPATH_INVALID_TYPE);
8772     cur = valuePop(ctxt);
8773
8774     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8775         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8776     } else {
8777         int i = 0; /* Should be first in document order !!!!! */
8778         switch (cur->nodesetval->nodeTab[i]->type) {
8779         case XML_ELEMENT_NODE:
8780         case XML_ATTRIBUTE_NODE:
8781         case XML_PI_NODE:
8782             if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8783                 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8784             else
8785                 valuePush(ctxt,
8786                       xmlXPathCacheNewString(ctxt->context,
8787                         cur->nodesetval->nodeTab[i]->name));
8788             break;
8789         case XML_NAMESPACE_DECL:
8790             valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8791                         ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8792             break;
8793         default:
8794             valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8795         }
8796     }
8797     xmlXPathReleaseObject(ctxt->context, cur);
8798 }
8799
8800 /**
8801  * xmlXPathNamespaceURIFunction:
8802  * @ctxt:  the XPath Parser context
8803  * @nargs:  the number of arguments
8804  *
8805  * Implement the namespace-uri() XPath function
8806  *    string namespace-uri(node-set?)
8807  * The namespace-uri function returns a string containing the
8808  * namespace URI of the expanded name of the node in the argument
8809  * node-set that is first in document order. If the node-set is empty,
8810  * the first node has no name, or the expanded name has no namespace
8811  * URI, an empty string is returned. If the argument is omitted it
8812  * defaults to the context node.
8813  */
8814 void
8815 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8816     xmlXPathObjectPtr cur;
8817
8818     if (ctxt == NULL) return;
8819
8820     if (nargs == 0) {
8821         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8822             ctxt->context->node));
8823         nargs = 1;
8824     }
8825     CHECK_ARITY(1);
8826     if ((ctxt->value == NULL) ||
8827         ((ctxt->value->type != XPATH_NODESET) &&
8828          (ctxt->value->type != XPATH_XSLT_TREE)))
8829         XP_ERROR(XPATH_INVALID_TYPE);
8830     cur = valuePop(ctxt);
8831
8832     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8833         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8834     } else {
8835         int i = 0; /* Should be first in document order !!!!! */
8836         switch (cur->nodesetval->nodeTab[i]->type) {
8837         case XML_ELEMENT_NODE:
8838         case XML_ATTRIBUTE_NODE:
8839             if (cur->nodesetval->nodeTab[i]->ns == NULL)
8840                 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8841             else
8842                 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8843                           cur->nodesetval->nodeTab[i]->ns->href));
8844             break;
8845         default:
8846             valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8847         }
8848     }
8849     xmlXPathReleaseObject(ctxt->context, cur);
8850 }
8851
8852 /**
8853  * xmlXPathNameFunction:
8854  * @ctxt:  the XPath Parser context
8855  * @nargs:  the number of arguments
8856  *
8857  * Implement the name() XPath function
8858  *    string name(node-set?)
8859  * The name function returns a string containing a QName representing
8860  * the name of the node in the argument node-set that is first in document
8861  * order. The QName must represent the name with respect to the namespace
8862  * declarations in effect on the node whose name is being represented.
8863  * Typically, this will be the form in which the name occurred in the XML
8864  * source. This need not be the case if there are namespace declarations
8865  * in effect on the node that associate multiple prefixes with the same
8866  * namespace. However, an implementation may include information about
8867  * the original prefix in its representation of nodes; in this case, an
8868  * implementation can ensure that the returned string is always the same
8869  * as the QName used in the XML source. If the argument it omitted it
8870  * defaults to the context node.
8871  * Libxml keep the original prefix so the "real qualified name" used is
8872  * returned.
8873  */
8874 static void
8875 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8876 {
8877     xmlXPathObjectPtr cur;
8878
8879     if (nargs == 0) {
8880         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8881             ctxt->context->node));
8882         nargs = 1;
8883     }
8884
8885     CHECK_ARITY(1);
8886     if ((ctxt->value == NULL) ||
8887         ((ctxt->value->type != XPATH_NODESET) &&
8888          (ctxt->value->type != XPATH_XSLT_TREE)))
8889         XP_ERROR(XPATH_INVALID_TYPE);
8890     cur = valuePop(ctxt);
8891
8892     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8893         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8894     } else {
8895         int i = 0;              /* Should be first in document order !!!!! */
8896
8897         switch (cur->nodesetval->nodeTab[i]->type) {
8898             case XML_ELEMENT_NODE:
8899             case XML_ATTRIBUTE_NODE:
8900                 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8901                     valuePush(ctxt,
8902                         xmlXPathCacheNewCString(ctxt->context, ""));
8903                 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8904                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8905                     valuePush(ctxt,
8906                         xmlXPathCacheNewString(ctxt->context,
8907                             cur->nodesetval->nodeTab[i]->name));
8908                 } else {
8909                     xmlChar *fullname;
8910
8911                     fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8912                                      cur->nodesetval->nodeTab[i]->ns->prefix,
8913                                      NULL, 0);
8914                     if (fullname == cur->nodesetval->nodeTab[i]->name)
8915                         fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8916                     if (fullname == NULL) {
8917                         XP_ERROR(XPATH_MEMORY_ERROR);
8918                     }
8919                     valuePush(ctxt, xmlXPathCacheWrapString(
8920                         ctxt->context, fullname));
8921                 }
8922                 break;
8923             default:
8924                 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8925                     cur->nodesetval->nodeTab[i]));
8926                 xmlXPathLocalNameFunction(ctxt, 1);
8927         }
8928     }
8929     xmlXPathReleaseObject(ctxt->context, cur);
8930 }
8931
8932
8933 /**
8934  * xmlXPathStringFunction:
8935  * @ctxt:  the XPath Parser context
8936  * @nargs:  the number of arguments
8937  *
8938  * Implement the string() XPath function
8939  *    string string(object?)
8940  * The string function converts an object to a string as follows:
8941  *    - A node-set is converted to a string by returning the value of
8942  *      the node in the node-set that is first in document order.
8943  *      If the node-set is empty, an empty string is returned.
8944  *    - A number is converted to a string as follows
8945  *      + NaN is converted to the string NaN
8946  *      + positive zero is converted to the string 0
8947  *      + negative zero is converted to the string 0
8948  *      + positive infinity is converted to the string Infinity
8949  *      + negative infinity is converted to the string -Infinity
8950  *      + if the number is an integer, the number is represented in
8951  *        decimal form as a Number with no decimal point and no leading
8952  *        zeros, preceded by a minus sign (-) if the number is negative
8953  *      + otherwise, the number is represented in decimal form as a
8954  *        Number including a decimal point with at least one digit
8955  *        before the decimal point and at least one digit after the
8956  *        decimal point, preceded by a minus sign (-) if the number
8957  *        is negative; there must be no leading zeros before the decimal
8958  *        point apart possibly from the one required digit immediately
8959  *        before the decimal point; beyond the one required digit
8960  *        after the decimal point there must be as many, but only as
8961  *        many, more digits as are needed to uniquely distinguish the
8962  *        number from all other IEEE 754 numeric values.
8963  *    - The boolean false value is converted to the string false.
8964  *      The boolean true value is converted to the string true.
8965  *
8966  * If the argument is omitted, it defaults to a node-set with the
8967  * context node as its only member.
8968  */
8969 void
8970 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8971     xmlXPathObjectPtr cur;
8972
8973     if (ctxt == NULL) return;
8974     if (nargs == 0) {
8975     valuePush(ctxt,
8976         xmlXPathCacheWrapString(ctxt->context,
8977             xmlXPathCastNodeToString(ctxt->context->node)));
8978         return;
8979     }
8980
8981     CHECK_ARITY(1);
8982     cur = valuePop(ctxt);
8983     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8984     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8985 }
8986
8987 /**
8988  * xmlXPathStringLengthFunction:
8989  * @ctxt:  the XPath Parser context
8990  * @nargs:  the number of arguments
8991  *
8992  * Implement the string-length() XPath function
8993  *    number string-length(string?)
8994  * The string-length returns the number of characters in the string
8995  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8996  * the context node converted to a string, in other words the value
8997  * of the context node.
8998  */
8999 void
9000 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9001     xmlXPathObjectPtr cur;
9002
9003     if (nargs == 0) {
9004         if ((ctxt == NULL) || (ctxt->context == NULL))
9005             return;
9006         if (ctxt->context->node == NULL) {
9007             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
9008         } else {
9009             xmlChar *content;
9010
9011             content = xmlXPathCastNodeToString(ctxt->context->node);
9012             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9013                 xmlUTF8Strlen(content)));
9014             xmlFree(content);
9015         }
9016         return;
9017     }
9018     CHECK_ARITY(1);
9019     CAST_TO_STRING;
9020     CHECK_TYPE(XPATH_STRING);
9021     cur = valuePop(ctxt);
9022     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9023         xmlUTF8Strlen(cur->stringval)));
9024     xmlXPathReleaseObject(ctxt->context, cur);
9025 }
9026
9027 /**
9028  * xmlXPathConcatFunction:
9029  * @ctxt:  the XPath Parser context
9030  * @nargs:  the number of arguments
9031  *
9032  * Implement the concat() XPath function
9033  *    string concat(string, string, string*)
9034  * The concat function returns the concatenation of its arguments.
9035  */
9036 void
9037 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9038     xmlXPathObjectPtr cur, newobj;
9039     xmlChar *tmp;
9040
9041     if (ctxt == NULL) return;
9042     if (nargs < 2) {
9043         CHECK_ARITY(2);
9044     }
9045
9046     CAST_TO_STRING;
9047     cur = valuePop(ctxt);
9048     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9049         xmlXPathReleaseObject(ctxt->context, cur);
9050         return;
9051     }
9052     nargs--;
9053
9054     while (nargs > 0) {
9055         CAST_TO_STRING;
9056         newobj = valuePop(ctxt);
9057         if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9058             xmlXPathReleaseObject(ctxt->context, newobj);
9059             xmlXPathReleaseObject(ctxt->context, cur);
9060             XP_ERROR(XPATH_INVALID_TYPE);
9061         }
9062         tmp = xmlStrcat(newobj->stringval, cur->stringval);
9063         newobj->stringval = cur->stringval;
9064         cur->stringval = tmp;
9065         xmlXPathReleaseObject(ctxt->context, newobj);
9066         nargs--;
9067     }
9068     valuePush(ctxt, cur);
9069 }
9070
9071 /**
9072  * xmlXPathContainsFunction:
9073  * @ctxt:  the XPath Parser context
9074  * @nargs:  the number of arguments
9075  *
9076  * Implement the contains() XPath function
9077  *    boolean contains(string, string)
9078  * The contains function returns true if the first argument string
9079  * contains the second argument string, and otherwise returns false.
9080  */
9081 void
9082 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9083     xmlXPathObjectPtr hay, needle;
9084
9085     CHECK_ARITY(2);
9086     CAST_TO_STRING;
9087     CHECK_TYPE(XPATH_STRING);
9088     needle = valuePop(ctxt);
9089     CAST_TO_STRING;
9090     hay = valuePop(ctxt);
9091
9092     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9093         xmlXPathReleaseObject(ctxt->context, hay);
9094         xmlXPathReleaseObject(ctxt->context, needle);
9095         XP_ERROR(XPATH_INVALID_TYPE);
9096     }
9097     if (xmlStrstr(hay->stringval, needle->stringval))
9098         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9099     else
9100         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9101     xmlXPathReleaseObject(ctxt->context, hay);
9102     xmlXPathReleaseObject(ctxt->context, needle);
9103 }
9104
9105 /**
9106  * xmlXPathStartsWithFunction:
9107  * @ctxt:  the XPath Parser context
9108  * @nargs:  the number of arguments
9109  *
9110  * Implement the starts-with() XPath function
9111  *    boolean starts-with(string, string)
9112  * The starts-with function returns true if the first argument string
9113  * starts with the second argument string, and otherwise returns false.
9114  */
9115 void
9116 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9117     xmlXPathObjectPtr hay, needle;
9118     int n;
9119
9120     CHECK_ARITY(2);
9121     CAST_TO_STRING;
9122     CHECK_TYPE(XPATH_STRING);
9123     needle = valuePop(ctxt);
9124     CAST_TO_STRING;
9125     hay = valuePop(ctxt);
9126
9127     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9128         xmlXPathReleaseObject(ctxt->context, hay);
9129         xmlXPathReleaseObject(ctxt->context, needle);
9130         XP_ERROR(XPATH_INVALID_TYPE);
9131     }
9132     n = xmlStrlen(needle->stringval);
9133     if (xmlStrncmp(hay->stringval, needle->stringval, n))
9134         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9135     else
9136         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9137     xmlXPathReleaseObject(ctxt->context, hay);
9138     xmlXPathReleaseObject(ctxt->context, needle);
9139 }
9140
9141 /**
9142  * xmlXPathSubstringFunction:
9143  * @ctxt:  the XPath Parser context
9144  * @nargs:  the number of arguments
9145  *
9146  * Implement the substring() XPath function
9147  *    string substring(string, number, number?)
9148  * The substring function returns the substring of the first argument
9149  * starting at the position specified in the second argument with
9150  * length specified in the third argument. For example,
9151  * substring("12345",2,3) returns "234". If the third argument is not
9152  * specified, it returns the substring starting at the position specified
9153  * in the second argument and continuing to the end of the string. For
9154  * example, substring("12345",2) returns "2345".  More precisely, each
9155  * character in the string (see [3.6 Strings]) is considered to have a
9156  * numeric position: the position of the first character is 1, the position
9157  * of the second character is 2 and so on. The returned substring contains
9158  * those characters for which the position of the character is greater than
9159  * or equal to the second argument and, if the third argument is specified,
9160  * less than the sum of the second and third arguments; the comparisons
9161  * and addition used for the above follow the standard IEEE 754 rules. Thus:
9162  *  - substring("12345", 1.5, 2.6) returns "234"
9163  *  - substring("12345", 0, 3) returns "12"
9164  *  - substring("12345", 0 div 0, 3) returns ""
9165  *  - substring("12345", 1, 0 div 0) returns ""
9166  *  - substring("12345", -42, 1 div 0) returns "12345"
9167  *  - substring("12345", -1 div 0, 1 div 0) returns ""
9168  */
9169 void
9170 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9171     xmlXPathObjectPtr str, start, len;
9172     double le=0, in;
9173     int i, l, m;
9174     xmlChar *ret;
9175
9176     if (nargs < 2) {
9177         CHECK_ARITY(2);
9178     }
9179     if (nargs > 3) {
9180         CHECK_ARITY(3);
9181     }
9182     /*
9183      * take care of possible last (position) argument
9184     */
9185     if (nargs == 3) {
9186         CAST_TO_NUMBER;
9187         CHECK_TYPE(XPATH_NUMBER);
9188         len = valuePop(ctxt);
9189         le = len->floatval;
9190         xmlXPathReleaseObject(ctxt->context, len);
9191     }
9192
9193     CAST_TO_NUMBER;
9194     CHECK_TYPE(XPATH_NUMBER);
9195     start = valuePop(ctxt);
9196     in = start->floatval;
9197     xmlXPathReleaseObject(ctxt->context, start);
9198     CAST_TO_STRING;
9199     CHECK_TYPE(XPATH_STRING);
9200     str = valuePop(ctxt);
9201     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9202
9203     /*
9204      * If last pos not present, calculate last position
9205     */
9206     if (nargs != 3) {
9207         le = (double)m;
9208         if (in < 1.0)
9209             in = 1.0;
9210     }
9211
9212     /* Need to check for the special cases where either
9213      * the index is NaN, the length is NaN, or both
9214      * arguments are infinity (relying on Inf + -Inf = NaN)
9215      */
9216     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9217         /*
9218          * To meet the requirements of the spec, the arguments
9219          * must be converted to integer format before
9220          * initial index calculations are done
9221          *
9222          * First we go to integer form, rounding up
9223          * and checking for special cases
9224          */
9225         i = (int) in;
9226         if (((double)i)+0.5 <= in) i++;
9227
9228         if (xmlXPathIsInf(le) == 1) {
9229             l = m;
9230             if (i < 1)
9231                 i = 1;
9232         }
9233         else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9234             l = 0;
9235         else {
9236             l = (int) le;
9237             if (((double)l)+0.5 <= le) l++;
9238         }
9239
9240         /* Now we normalize inidices */
9241         i -= 1;
9242         l += i;
9243         if (i < 0)
9244             i = 0;
9245         if (l > m)
9246             l = m;
9247
9248         /* number of chars to copy */
9249         l -= i;
9250
9251         ret = xmlUTF8Strsub(str->stringval, i, l);
9252     }
9253     else {
9254         ret = NULL;
9255     }
9256     if (ret == NULL)
9257         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9258     else {
9259         valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9260         xmlFree(ret);
9261     }
9262     xmlXPathReleaseObject(ctxt->context, str);
9263 }
9264
9265 /**
9266  * xmlXPathSubstringBeforeFunction:
9267  * @ctxt:  the XPath Parser context
9268  * @nargs:  the number of arguments
9269  *
9270  * Implement the substring-before() XPath function
9271  *    string substring-before(string, string)
9272  * The substring-before function returns the substring of the first
9273  * argument string that precedes the first occurrence of the second
9274  * argument string in the first argument string, or the empty string
9275  * if the first argument string does not contain the second argument
9276  * string. For example, substring-before("1999/04/01","/") returns 1999.
9277  */
9278 void
9279 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9280   xmlXPathObjectPtr str;
9281   xmlXPathObjectPtr find;
9282   xmlBufPtr target;
9283   const xmlChar *point;
9284   int offset;
9285
9286   CHECK_ARITY(2);
9287   CAST_TO_STRING;
9288   find = valuePop(ctxt);
9289   CAST_TO_STRING;
9290   str = valuePop(ctxt);
9291
9292   target = xmlBufCreate();
9293   if (target) {
9294     point = xmlStrstr(str->stringval, find->stringval);
9295     if (point) {
9296       offset = (int)(point - str->stringval);
9297       xmlBufAdd(target, str->stringval, offset);
9298     }
9299     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9300         xmlBufContent(target)));
9301     xmlBufFree(target);
9302   }
9303   xmlXPathReleaseObject(ctxt->context, str);
9304   xmlXPathReleaseObject(ctxt->context, find);
9305 }
9306
9307 /**
9308  * xmlXPathSubstringAfterFunction:
9309  * @ctxt:  the XPath Parser context
9310  * @nargs:  the number of arguments
9311  *
9312  * Implement the substring-after() XPath function
9313  *    string substring-after(string, string)
9314  * The substring-after function returns the substring of the first
9315  * argument string that follows the first occurrence of the second
9316  * argument string in the first argument string, or the empty stringi
9317  * if the first argument string does not contain the second argument
9318  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9319  * and substring-after("1999/04/01","19") returns 99/04/01.
9320  */
9321 void
9322 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9323   xmlXPathObjectPtr str;
9324   xmlXPathObjectPtr find;
9325   xmlBufPtr target;
9326   const xmlChar *point;
9327   int offset;
9328
9329   CHECK_ARITY(2);
9330   CAST_TO_STRING;
9331   find = valuePop(ctxt);
9332   CAST_TO_STRING;
9333   str = valuePop(ctxt);
9334
9335   target = xmlBufCreate();
9336   if (target) {
9337     point = xmlStrstr(str->stringval, find->stringval);
9338     if (point) {
9339       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9340       xmlBufAdd(target, &str->stringval[offset],
9341                    xmlStrlen(str->stringval) - offset);
9342     }
9343     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9344         xmlBufContent(target)));
9345     xmlBufFree(target);
9346   }
9347   xmlXPathReleaseObject(ctxt->context, str);
9348   xmlXPathReleaseObject(ctxt->context, find);
9349 }
9350
9351 /**
9352  * xmlXPathNormalizeFunction:
9353  * @ctxt:  the XPath Parser context
9354  * @nargs:  the number of arguments
9355  *
9356  * Implement the normalize-space() XPath function
9357  *    string normalize-space(string?)
9358  * The normalize-space function returns the argument string with white
9359  * space normalized by stripping leading and trailing whitespace
9360  * and replacing sequences of whitespace characters by a single
9361  * space. Whitespace characters are the same allowed by the S production
9362  * in XML. If the argument is omitted, it defaults to the context
9363  * node converted to a string, in other words the value of the context node.
9364  */
9365 void
9366 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9367   xmlXPathObjectPtr obj = NULL;
9368   xmlChar *source = NULL;
9369   xmlBufPtr target;
9370   xmlChar blank;
9371
9372   if (ctxt == NULL) return;
9373   if (nargs == 0) {
9374     /* Use current context node */
9375       valuePush(ctxt,
9376           xmlXPathCacheWrapString(ctxt->context,
9377             xmlXPathCastNodeToString(ctxt->context->node)));
9378     nargs = 1;
9379   }
9380
9381   CHECK_ARITY(1);
9382   CAST_TO_STRING;
9383   CHECK_TYPE(XPATH_STRING);
9384   obj = valuePop(ctxt);
9385   source = obj->stringval;
9386
9387   target = xmlBufCreate();
9388   if (target && source) {
9389
9390     /* Skip leading whitespaces */
9391     while (IS_BLANK_CH(*source))
9392       source++;
9393
9394     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9395     blank = 0;
9396     while (*source) {
9397       if (IS_BLANK_CH(*source)) {
9398         blank = 0x20;
9399       } else {
9400         if (blank) {
9401           xmlBufAdd(target, &blank, 1);
9402           blank = 0;
9403         }
9404         xmlBufAdd(target, source, 1);
9405       }
9406       source++;
9407     }
9408     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9409         xmlBufContent(target)));
9410     xmlBufFree(target);
9411   }
9412   xmlXPathReleaseObject(ctxt->context, obj);
9413 }
9414
9415 /**
9416  * xmlXPathTranslateFunction:
9417  * @ctxt:  the XPath Parser context
9418  * @nargs:  the number of arguments
9419  *
9420  * Implement the translate() XPath function
9421  *    string translate(string, string, string)
9422  * The translate function returns the first argument string with
9423  * occurrences of characters in the second argument string replaced
9424  * by the character at the corresponding position in the third argument
9425  * string. For example, translate("bar","abc","ABC") returns the string
9426  * BAr. If there is a character in the second argument string with no
9427  * character at a corresponding position in the third argument string
9428  * (because the second argument string is longer than the third argument
9429  * string), then occurrences of that character in the first argument
9430  * string are removed. For example, translate("--aaa--","abc-","ABC")
9431  * returns "AAA". If a character occurs more than once in second
9432  * argument string, then the first occurrence determines the replacement
9433  * character. If the third argument string is longer than the second
9434  * argument string, then excess characters are ignored.
9435  */
9436 void
9437 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9438     xmlXPathObjectPtr str;
9439     xmlXPathObjectPtr from;
9440     xmlXPathObjectPtr to;
9441     xmlBufPtr target;
9442     int offset, max;
9443     xmlChar ch;
9444     const xmlChar *point;
9445     xmlChar *cptr;
9446
9447     CHECK_ARITY(3);
9448
9449     CAST_TO_STRING;
9450     to = valuePop(ctxt);
9451     CAST_TO_STRING;
9452     from = valuePop(ctxt);
9453     CAST_TO_STRING;
9454     str = valuePop(ctxt);
9455
9456     target = xmlBufCreate();
9457     if (target) {
9458         max = xmlUTF8Strlen(to->stringval);
9459         for (cptr = str->stringval; (ch=*cptr); ) {
9460             offset = xmlUTF8Strloc(from->stringval, cptr);
9461             if (offset >= 0) {
9462                 if (offset < max) {
9463                     point = xmlUTF8Strpos(to->stringval, offset);
9464                     if (point)
9465                         xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9466                 }
9467             } else
9468                 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9469
9470             /* Step to next character in input */
9471             cptr++;
9472             if ( ch & 0x80 ) {
9473                 /* if not simple ascii, verify proper format */
9474                 if ( (ch & 0xc0) != 0xc0 ) {
9475                     xmlGenericError(xmlGenericErrorContext,
9476                         "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9477                     /* not asserting an XPath error is probably better */
9478                     break;
9479                 }
9480                 /* then skip over remaining bytes for this char */
9481                 while ( (ch <<= 1) & 0x80 )
9482                     if ( (*cptr++ & 0xc0) != 0x80 ) {
9483                         xmlGenericError(xmlGenericErrorContext,
9484                             "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9485                         /* not asserting an XPath error is probably better */
9486                         break;
9487                     }
9488                 if (ch & 0x80) /* must have had error encountered */
9489                     break;
9490             }
9491         }
9492     }
9493     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9494         xmlBufContent(target)));
9495     xmlBufFree(target);
9496     xmlXPathReleaseObject(ctxt->context, str);
9497     xmlXPathReleaseObject(ctxt->context, from);
9498     xmlXPathReleaseObject(ctxt->context, to);
9499 }
9500
9501 /**
9502  * xmlXPathBooleanFunction:
9503  * @ctxt:  the XPath Parser context
9504  * @nargs:  the number of arguments
9505  *
9506  * Implement the boolean() XPath function
9507  *    boolean boolean(object)
9508  * The boolean function converts its argument to a boolean as follows:
9509  *    - a number is true if and only if it is neither positive or
9510  *      negative zero nor NaN
9511  *    - a node-set is true if and only if it is non-empty
9512  *    - a string is true if and only if its length is non-zero
9513  */
9514 void
9515 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9516     xmlXPathObjectPtr cur;
9517
9518     CHECK_ARITY(1);
9519     cur = valuePop(ctxt);
9520     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9521     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9522     valuePush(ctxt, cur);
9523 }
9524
9525 /**
9526  * xmlXPathNotFunction:
9527  * @ctxt:  the XPath Parser context
9528  * @nargs:  the number of arguments
9529  *
9530  * Implement the not() XPath function
9531  *    boolean not(boolean)
9532  * The not function returns true if its argument is false,
9533  * and false otherwise.
9534  */
9535 void
9536 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9537     CHECK_ARITY(1);
9538     CAST_TO_BOOLEAN;
9539     CHECK_TYPE(XPATH_BOOLEAN);
9540     ctxt->value->boolval = ! ctxt->value->boolval;
9541 }
9542
9543 /**
9544  * xmlXPathTrueFunction:
9545  * @ctxt:  the XPath Parser context
9546  * @nargs:  the number of arguments
9547  *
9548  * Implement the true() XPath function
9549  *    boolean true()
9550  */
9551 void
9552 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9553     CHECK_ARITY(0);
9554     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9555 }
9556
9557 /**
9558  * xmlXPathFalseFunction:
9559  * @ctxt:  the XPath Parser context
9560  * @nargs:  the number of arguments
9561  *
9562  * Implement the false() XPath function
9563  *    boolean false()
9564  */
9565 void
9566 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9567     CHECK_ARITY(0);
9568     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9569 }
9570
9571 /**
9572  * xmlXPathLangFunction:
9573  * @ctxt:  the XPath Parser context
9574  * @nargs:  the number of arguments
9575  *
9576  * Implement the lang() XPath function
9577  *    boolean lang(string)
9578  * The lang function returns true or false depending on whether the
9579  * language of the context node as specified by xml:lang attributes
9580  * is the same as or is a sublanguage of the language specified by
9581  * the argument string. The language of the context node is determined
9582  * by the value of the xml:lang attribute on the context node, or, if
9583  * the context node has no xml:lang attribute, by the value of the
9584  * xml:lang attribute on the nearest ancestor of the context node that
9585  * has an xml:lang attribute. If there is no such attribute, then lang
9586  * returns false. If there is such an attribute, then lang returns
9587  * true if the attribute value is equal to the argument ignoring case,
9588  * or if there is some suffix starting with - such that the attribute
9589  * value is equal to the argument ignoring that suffix of the attribute
9590  * value and ignoring case.
9591  */
9592 void
9593 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9594     xmlXPathObjectPtr val = NULL;
9595     const xmlChar *theLang = NULL;
9596     const xmlChar *lang;
9597     int ret = 0;
9598     int i;
9599
9600     CHECK_ARITY(1);
9601     CAST_TO_STRING;
9602     CHECK_TYPE(XPATH_STRING);
9603     val = valuePop(ctxt);
9604     lang = val->stringval;
9605     theLang = xmlNodeGetLang(ctxt->context->node);
9606     if ((theLang != NULL) && (lang != NULL)) {
9607         for (i = 0;lang[i] != 0;i++)
9608             if (toupper(lang[i]) != toupper(theLang[i]))
9609                 goto not_equal;
9610         if ((theLang[i] == 0) || (theLang[i] == '-'))
9611             ret = 1;
9612     }
9613 not_equal:
9614     if (theLang != NULL)
9615         xmlFree((void *)theLang);
9616
9617     xmlXPathReleaseObject(ctxt->context, val);
9618     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9619 }
9620
9621 /**
9622  * xmlXPathNumberFunction:
9623  * @ctxt:  the XPath Parser context
9624  * @nargs:  the number of arguments
9625  *
9626  * Implement the number() XPath function
9627  *    number number(object?)
9628  */
9629 void
9630 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9631     xmlXPathObjectPtr cur;
9632     double res;
9633
9634     if (ctxt == NULL) return;
9635     if (nargs == 0) {
9636         if (ctxt->context->node == NULL) {
9637             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9638         } else {
9639             xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9640
9641             res = xmlXPathStringEvalNumber(content);
9642             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9643             xmlFree(content);
9644         }
9645         return;
9646     }
9647
9648     CHECK_ARITY(1);
9649     cur = valuePop(ctxt);
9650     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9651 }
9652
9653 /**
9654  * xmlXPathSumFunction:
9655  * @ctxt:  the XPath Parser context
9656  * @nargs:  the number of arguments
9657  *
9658  * Implement the sum() XPath function
9659  *    number sum(node-set)
9660  * The sum function returns the sum of the values of the nodes in
9661  * the argument node-set.
9662  */
9663 void
9664 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9665     xmlXPathObjectPtr cur;
9666     int i;
9667     double res = 0.0;
9668
9669     CHECK_ARITY(1);
9670     if ((ctxt->value == NULL) ||
9671         ((ctxt->value->type != XPATH_NODESET) &&
9672          (ctxt->value->type != XPATH_XSLT_TREE)))
9673         XP_ERROR(XPATH_INVALID_TYPE);
9674     cur = valuePop(ctxt);
9675
9676     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9677         for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9678             res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9679         }
9680     }
9681     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9682     xmlXPathReleaseObject(ctxt->context, cur);
9683 }
9684
9685 /**
9686  * xmlXPathFloorFunction:
9687  * @ctxt:  the XPath Parser context
9688  * @nargs:  the number of arguments
9689  *
9690  * Implement the floor() XPath function
9691  *    number floor(number)
9692  * The floor function returns the largest (closest to positive infinity)
9693  * number that is not greater than the argument and that is an integer.
9694  */
9695 void
9696 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9697     CHECK_ARITY(1);
9698     CAST_TO_NUMBER;
9699     CHECK_TYPE(XPATH_NUMBER);
9700
9701     ctxt->value->floatval = floor(ctxt->value->floatval);
9702 }
9703
9704 /**
9705  * xmlXPathCeilingFunction:
9706  * @ctxt:  the XPath Parser context
9707  * @nargs:  the number of arguments
9708  *
9709  * Implement the ceiling() XPath function
9710  *    number ceiling(number)
9711  * The ceiling function returns the smallest (closest to negative infinity)
9712  * number that is not less than the argument and that is an integer.
9713  */
9714 void
9715 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9716     CHECK_ARITY(1);
9717     CAST_TO_NUMBER;
9718     CHECK_TYPE(XPATH_NUMBER);
9719
9720     ctxt->value->floatval = ceil(ctxt->value->floatval);
9721 }
9722
9723 /**
9724  * xmlXPathRoundFunction:
9725  * @ctxt:  the XPath Parser context
9726  * @nargs:  the number of arguments
9727  *
9728  * Implement the round() XPath function
9729  *    number round(number)
9730  * The round function returns the number that is closest to the
9731  * argument and that is an integer. If there are two such numbers,
9732  * then the one that is closest to positive infinity is returned.
9733  */
9734 void
9735 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9736     double f;
9737
9738     CHECK_ARITY(1);
9739     CAST_TO_NUMBER;
9740     CHECK_TYPE(XPATH_NUMBER);
9741
9742     f = ctxt->value->floatval;
9743
9744     /* Test for zero to keep negative zero unchanged. */
9745     if ((xmlXPathIsNaN(f)) || (f == 0.0))
9746         return;
9747
9748     if ((f >= -0.5) && (f < 0.0)) {
9749         /* Negative zero. */
9750         ctxt->value->floatval = xmlXPathNZERO;
9751     }
9752     else {
9753         double rounded = floor(f);
9754         if (f - rounded >= 0.5)
9755             rounded += 1.0;
9756         ctxt->value->floatval = rounded;
9757     }
9758 }
9759
9760 /************************************************************************
9761  *                                                                      *
9762  *                      The Parser                                      *
9763  *                                                                      *
9764  ************************************************************************/
9765
9766 /*
9767  * a few forward declarations since we use a recursive call based
9768  * implementation.
9769  */
9770 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9771 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9772 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9773 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9774 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9775                                           int qualified);
9776
9777 /**
9778  * xmlXPathCurrentChar:
9779  * @ctxt:  the XPath parser context
9780  * @cur:  pointer to the beginning of the char
9781  * @len:  pointer to the length of the char read
9782  *
9783  * The current char value, if using UTF-8 this may actually span multiple
9784  * bytes in the input buffer.
9785  *
9786  * Returns the current char value and its length
9787  */
9788
9789 static int
9790 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9791     unsigned char c;
9792     unsigned int val;
9793     const xmlChar *cur;
9794
9795     if (ctxt == NULL)
9796         return(0);
9797     cur = ctxt->cur;
9798
9799     /*
9800      * We are supposed to handle UTF8, check it's valid
9801      * From rfc2044: encoding of the Unicode values on UTF-8:
9802      *
9803      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9804      * 0000 0000-0000 007F   0xxxxxxx
9805      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9806      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9807      *
9808      * Check for the 0x110000 limit too
9809      */
9810     c = *cur;
9811     if (c & 0x80) {
9812         if ((cur[1] & 0xc0) != 0x80)
9813             goto encoding_error;
9814         if ((c & 0xe0) == 0xe0) {
9815
9816             if ((cur[2] & 0xc0) != 0x80)
9817                 goto encoding_error;
9818             if ((c & 0xf0) == 0xf0) {
9819                 if (((c & 0xf8) != 0xf0) ||
9820                     ((cur[3] & 0xc0) != 0x80))
9821                     goto encoding_error;
9822                 /* 4-byte code */
9823                 *len = 4;
9824                 val = (cur[0] & 0x7) << 18;
9825                 val |= (cur[1] & 0x3f) << 12;
9826                 val |= (cur[2] & 0x3f) << 6;
9827                 val |= cur[3] & 0x3f;
9828             } else {
9829               /* 3-byte code */
9830                 *len = 3;
9831                 val = (cur[0] & 0xf) << 12;
9832                 val |= (cur[1] & 0x3f) << 6;
9833                 val |= cur[2] & 0x3f;
9834             }
9835         } else {
9836           /* 2-byte code */
9837             *len = 2;
9838             val = (cur[0] & 0x1f) << 6;
9839             val |= cur[1] & 0x3f;
9840         }
9841         if (!IS_CHAR(val)) {
9842             XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9843         }
9844         return(val);
9845     } else {
9846         /* 1-byte code */
9847         *len = 1;
9848         return((int) *cur);
9849     }
9850 encoding_error:
9851     /*
9852      * If we detect an UTF8 error that probably means that the
9853      * input encoding didn't get properly advertised in the
9854      * declaration header. Report the error and switch the encoding
9855      * to ISO-Latin-1 (if you don't like this policy, just declare the
9856      * encoding !)
9857      */
9858     *len = 0;
9859     XP_ERROR0(XPATH_ENCODING_ERROR);
9860 }
9861
9862 /**
9863  * xmlXPathParseNCName:
9864  * @ctxt:  the XPath Parser context
9865  *
9866  * parse an XML namespace non qualified name.
9867  *
9868  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9869  *
9870  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9871  *                       CombiningChar | Extender
9872  *
9873  * Returns the namespace name or NULL
9874  */
9875
9876 xmlChar *
9877 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9878     const xmlChar *in;
9879     xmlChar *ret;
9880     int count = 0;
9881
9882     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9883     /*
9884      * Accelerator for simple ASCII names
9885      */
9886     in = ctxt->cur;
9887     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9888         ((*in >= 0x41) && (*in <= 0x5A)) ||
9889         (*in == '_')) {
9890         in++;
9891         while (((*in >= 0x61) && (*in <= 0x7A)) ||
9892                ((*in >= 0x41) && (*in <= 0x5A)) ||
9893                ((*in >= 0x30) && (*in <= 0x39)) ||
9894                (*in == '_') || (*in == '.') ||
9895                (*in == '-'))
9896             in++;
9897         if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9898             (*in == '[') || (*in == ']') || (*in == ':') ||
9899             (*in == '@') || (*in == '*')) {
9900             count = in - ctxt->cur;
9901             if (count == 0)
9902                 return(NULL);
9903             ret = xmlStrndup(ctxt->cur, count);
9904             ctxt->cur = in;
9905             return(ret);
9906         }
9907     }
9908     return(xmlXPathParseNameComplex(ctxt, 0));
9909 }
9910
9911
9912 /**
9913  * xmlXPathParseQName:
9914  * @ctxt:  the XPath Parser context
9915  * @prefix:  a xmlChar **
9916  *
9917  * parse an XML qualified name
9918  *
9919  * [NS 5] QName ::= (Prefix ':')? LocalPart
9920  *
9921  * [NS 6] Prefix ::= NCName
9922  *
9923  * [NS 7] LocalPart ::= NCName
9924  *
9925  * Returns the function returns the local part, and prefix is updated
9926  *   to get the Prefix if any.
9927  */
9928
9929 static xmlChar *
9930 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9931     xmlChar *ret = NULL;
9932
9933     *prefix = NULL;
9934     ret = xmlXPathParseNCName(ctxt);
9935     if (ret && CUR == ':') {
9936         *prefix = ret;
9937         NEXT;
9938         ret = xmlXPathParseNCName(ctxt);
9939     }
9940     return(ret);
9941 }
9942
9943 /**
9944  * xmlXPathParseName:
9945  * @ctxt:  the XPath Parser context
9946  *
9947  * parse an XML name
9948  *
9949  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9950  *                  CombiningChar | Extender
9951  *
9952  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9953  *
9954  * Returns the namespace name or NULL
9955  */
9956
9957 xmlChar *
9958 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9959     const xmlChar *in;
9960     xmlChar *ret;
9961     size_t count = 0;
9962
9963     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9964     /*
9965      * Accelerator for simple ASCII names
9966      */
9967     in = ctxt->cur;
9968     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9969         ((*in >= 0x41) && (*in <= 0x5A)) ||
9970         (*in == '_') || (*in == ':')) {
9971         in++;
9972         while (((*in >= 0x61) && (*in <= 0x7A)) ||
9973                ((*in >= 0x41) && (*in <= 0x5A)) ||
9974                ((*in >= 0x30) && (*in <= 0x39)) ||
9975                (*in == '_') || (*in == '-') ||
9976                (*in == ':') || (*in == '.'))
9977             in++;
9978         if ((*in > 0) && (*in < 0x80)) {
9979             count = in - ctxt->cur;
9980             if (count > XML_MAX_NAME_LENGTH) {
9981                 ctxt->cur = in;
9982                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9983             }
9984             ret = xmlStrndup(ctxt->cur, count);
9985             ctxt->cur = in;
9986             return(ret);
9987         }
9988     }
9989     return(xmlXPathParseNameComplex(ctxt, 1));
9990 }
9991
9992 static xmlChar *
9993 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9994     xmlChar buf[XML_MAX_NAMELEN + 5];
9995     int len = 0, l;
9996     int c;
9997
9998     /*
9999      * Handler for more complex cases
10000      */
10001     c = CUR_CHAR(l);
10002     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10003         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
10004         (c == '*') || /* accelerators */
10005         (!IS_LETTER(c) && (c != '_') &&
10006          ((!qualified) || (c != ':')))) {
10007         return(NULL);
10008     }
10009
10010     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10011            ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10012             (c == '.') || (c == '-') ||
10013             (c == '_') || ((qualified) && (c == ':')) ||
10014             (IS_COMBINING(c)) ||
10015             (IS_EXTENDER(c)))) {
10016         COPY_BUF(l,buf,len,c);
10017         NEXTL(l);
10018         c = CUR_CHAR(l);
10019         if (len >= XML_MAX_NAMELEN) {
10020             /*
10021              * Okay someone managed to make a huge name, so he's ready to pay
10022              * for the processing speed.
10023              */
10024             xmlChar *buffer;
10025             int max = len * 2;
10026
10027             if (len > XML_MAX_NAME_LENGTH) {
10028                 XP_ERRORNULL(XPATH_EXPR_ERROR);
10029             }
10030             buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10031             if (buffer == NULL) {
10032                 XP_ERRORNULL(XPATH_MEMORY_ERROR);
10033             }
10034             memcpy(buffer, buf, len);
10035             while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10036                    (c == '.') || (c == '-') ||
10037                    (c == '_') || ((qualified) && (c == ':')) ||
10038                    (IS_COMBINING(c)) ||
10039                    (IS_EXTENDER(c))) {
10040                 if (len + 10 > max) {
10041                     if (max > XML_MAX_NAME_LENGTH) {
10042                         XP_ERRORNULL(XPATH_EXPR_ERROR);
10043                     }
10044                     max *= 2;
10045                     buffer = (xmlChar *) xmlRealloc(buffer,
10046                                                     max * sizeof(xmlChar));
10047                     if (buffer == NULL) {
10048                         XP_ERRORNULL(XPATH_MEMORY_ERROR);
10049                     }
10050                 }
10051                 COPY_BUF(l,buffer,len,c);
10052                 NEXTL(l);
10053                 c = CUR_CHAR(l);
10054             }
10055             buffer[len] = 0;
10056             return(buffer);
10057         }
10058     }
10059     if (len == 0)
10060         return(NULL);
10061     return(xmlStrndup(buf, len));
10062 }
10063
10064 #define MAX_FRAC 20
10065
10066 /**
10067  * xmlXPathStringEvalNumber:
10068  * @str:  A string to scan
10069  *
10070  *  [30a]  Float  ::= Number ('e' Digits?)?
10071  *
10072  *  [30]   Number ::=   Digits ('.' Digits?)?
10073  *                    | '.' Digits
10074  *  [31]   Digits ::=   [0-9]+
10075  *
10076  * Compile a Number in the string
10077  * In complement of the Number expression, this function also handles
10078  * negative values : '-' Number.
10079  *
10080  * Returns the double value.
10081  */
10082 double
10083 xmlXPathStringEvalNumber(const xmlChar *str) {
10084     const xmlChar *cur = str;
10085     double ret;
10086     int ok = 0;
10087     int isneg = 0;
10088     int exponent = 0;
10089     int is_exponent_negative = 0;
10090 #ifdef __GNUC__
10091     unsigned long tmp = 0;
10092     double temp;
10093 #endif
10094     if (cur == NULL) return(0);
10095     while (IS_BLANK_CH(*cur)) cur++;
10096     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10097         return(xmlXPathNAN);
10098     }
10099     if (*cur == '-') {
10100         isneg = 1;
10101         cur++;
10102     }
10103
10104 #ifdef __GNUC__
10105     /*
10106      * tmp/temp is a workaround against a gcc compiler bug
10107      * http://veillard.com/gcc.bug
10108      */
10109     ret = 0;
10110     while ((*cur >= '0') && (*cur <= '9')) {
10111         ret = ret * 10;
10112         tmp = (*cur - '0');
10113         ok = 1;
10114         cur++;
10115         temp = (double) tmp;
10116         ret = ret + temp;
10117     }
10118 #else
10119     ret = 0;
10120     while ((*cur >= '0') && (*cur <= '9')) {
10121         ret = ret * 10 + (*cur - '0');
10122         ok = 1;
10123         cur++;
10124     }
10125 #endif
10126
10127     if (*cur == '.') {
10128         int v, frac = 0, max;
10129         double fraction = 0;
10130
10131         cur++;
10132         if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10133             return(xmlXPathNAN);
10134         }
10135         while (*cur == '0') {
10136             frac = frac + 1;
10137             cur++;
10138         }
10139         max = frac + MAX_FRAC;
10140         while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10141             v = (*cur - '0');
10142             fraction = fraction * 10 + v;
10143             frac = frac + 1;
10144             cur++;
10145         }
10146         fraction /= pow(10.0, frac);
10147         ret = ret + fraction;
10148         while ((*cur >= '0') && (*cur <= '9'))
10149             cur++;
10150     }
10151     if ((*cur == 'e') || (*cur == 'E')) {
10152       cur++;
10153       if (*cur == '-') {
10154         is_exponent_negative = 1;
10155         cur++;
10156       } else if (*cur == '+') {
10157         cur++;
10158       }
10159       while ((*cur >= '0') && (*cur <= '9')) {
10160         if (exponent < 1000000)
10161           exponent = exponent * 10 + (*cur - '0');
10162         cur++;
10163       }
10164     }
10165     while (IS_BLANK_CH(*cur)) cur++;
10166     if (*cur != 0) return(xmlXPathNAN);
10167     if (isneg) ret = -ret;
10168     if (is_exponent_negative) exponent = -exponent;
10169     ret *= pow(10.0, (double)exponent);
10170     return(ret);
10171 }
10172
10173 /**
10174  * xmlXPathCompNumber:
10175  * @ctxt:  the XPath Parser context
10176  *
10177  *  [30]   Number ::=   Digits ('.' Digits?)?
10178  *                    | '.' Digits
10179  *  [31]   Digits ::=   [0-9]+
10180  *
10181  * Compile a Number, then push it on the stack
10182  *
10183  */
10184 static void
10185 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10186 {
10187     double ret = 0.0;
10188     int ok = 0;
10189     int exponent = 0;
10190     int is_exponent_negative = 0;
10191 #ifdef __GNUC__
10192     unsigned long tmp = 0;
10193     double temp;
10194 #endif
10195
10196     CHECK_ERROR;
10197     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10198         XP_ERROR(XPATH_NUMBER_ERROR);
10199     }
10200 #ifdef __GNUC__
10201     /*
10202      * tmp/temp is a workaround against a gcc compiler bug
10203      * http://veillard.com/gcc.bug
10204      */
10205     ret = 0;
10206     while ((CUR >= '0') && (CUR <= '9')) {
10207         ret = ret * 10;
10208         tmp = (CUR - '0');
10209         ok = 1;
10210         NEXT;
10211         temp = (double) tmp;
10212         ret = ret + temp;
10213     }
10214 #else
10215     ret = 0;
10216     while ((CUR >= '0') && (CUR <= '9')) {
10217         ret = ret * 10 + (CUR - '0');
10218         ok = 1;
10219         NEXT;
10220     }
10221 #endif
10222     if (CUR == '.') {
10223         int v, frac = 0, max;
10224         double fraction = 0;
10225
10226         NEXT;
10227         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10228             XP_ERROR(XPATH_NUMBER_ERROR);
10229         }
10230         while (CUR == '0') {
10231             frac = frac + 1;
10232             NEXT;
10233         }
10234         max = frac + MAX_FRAC;
10235         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10236             v = (CUR - '0');
10237             fraction = fraction * 10 + v;
10238             frac = frac + 1;
10239             NEXT;
10240         }
10241         fraction /= pow(10.0, frac);
10242         ret = ret + fraction;
10243         while ((CUR >= '0') && (CUR <= '9'))
10244             NEXT;
10245     }
10246     if ((CUR == 'e') || (CUR == 'E')) {
10247         NEXT;
10248         if (CUR == '-') {
10249             is_exponent_negative = 1;
10250             NEXT;
10251         } else if (CUR == '+') {
10252             NEXT;
10253         }
10254         while ((CUR >= '0') && (CUR <= '9')) {
10255             if (exponent < 1000000)
10256                 exponent = exponent * 10 + (CUR - '0');
10257             NEXT;
10258         }
10259         if (is_exponent_negative)
10260             exponent = -exponent;
10261         ret *= pow(10.0, (double) exponent);
10262     }
10263     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10264                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10265 }
10266
10267 /**
10268  * xmlXPathParseLiteral:
10269  * @ctxt:  the XPath Parser context
10270  *
10271  * Parse a Literal
10272  *
10273  *  [29]   Literal ::=   '"' [^"]* '"'
10274  *                    | "'" [^']* "'"
10275  *
10276  * Returns the value found or NULL in case of error
10277  */
10278 static xmlChar *
10279 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10280     const xmlChar *q;
10281     xmlChar *ret = NULL;
10282
10283     if (CUR == '"') {
10284         NEXT;
10285         q = CUR_PTR;
10286         while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10287             NEXT;
10288         if (!IS_CHAR_CH(CUR)) {
10289             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10290         } else {
10291             ret = xmlStrndup(q, CUR_PTR - q);
10292             NEXT;
10293         }
10294     } else if (CUR == '\'') {
10295         NEXT;
10296         q = CUR_PTR;
10297         while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10298             NEXT;
10299         if (!IS_CHAR_CH(CUR)) {
10300             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10301         } else {
10302             ret = xmlStrndup(q, CUR_PTR - q);
10303             NEXT;
10304         }
10305     } else {
10306         XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10307     }
10308     return(ret);
10309 }
10310
10311 /**
10312  * xmlXPathCompLiteral:
10313  * @ctxt:  the XPath Parser context
10314  *
10315  * Parse a Literal and push it on the stack.
10316  *
10317  *  [29]   Literal ::=   '"' [^"]* '"'
10318  *                    | "'" [^']* "'"
10319  *
10320  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10321  */
10322 static void
10323 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10324     const xmlChar *q;
10325     xmlChar *ret = NULL;
10326
10327     if (CUR == '"') {
10328         NEXT;
10329         q = CUR_PTR;
10330         while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10331             NEXT;
10332         if (!IS_CHAR_CH(CUR)) {
10333             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10334         } else {
10335             ret = xmlStrndup(q, CUR_PTR - q);
10336             NEXT;
10337         }
10338     } else if (CUR == '\'') {
10339         NEXT;
10340         q = CUR_PTR;
10341         while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10342             NEXT;
10343         if (!IS_CHAR_CH(CUR)) {
10344             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10345         } else {
10346             ret = xmlStrndup(q, CUR_PTR - q);
10347             NEXT;
10348         }
10349     } else {
10350         XP_ERROR(XPATH_START_LITERAL_ERROR);
10351     }
10352     if (ret == NULL) return;
10353     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10354                    xmlXPathCacheNewString(ctxt->context, ret), NULL);
10355     xmlFree(ret);
10356 }
10357
10358 /**
10359  * xmlXPathCompVariableReference:
10360  * @ctxt:  the XPath Parser context
10361  *
10362  * Parse a VariableReference, evaluate it and push it on the stack.
10363  *
10364  * The variable bindings consist of a mapping from variable names
10365  * to variable values. The value of a variable is an object, which can be
10366  * of any of the types that are possible for the value of an expression,
10367  * and may also be of additional types not specified here.
10368  *
10369  * Early evaluation is possible since:
10370  * The variable bindings [...] used to evaluate a subexpression are
10371  * always the same as those used to evaluate the containing expression.
10372  *
10373  *  [36]   VariableReference ::=   '$' QName
10374  */
10375 static void
10376 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10377     xmlChar *name;
10378     xmlChar *prefix;
10379
10380     SKIP_BLANKS;
10381     if (CUR != '$') {
10382         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10383     }
10384     NEXT;
10385     name = xmlXPathParseQName(ctxt, &prefix);
10386     if (name == NULL) {
10387         xmlFree(prefix);
10388         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10389     }
10390     ctxt->comp->last = -1;
10391     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10392                    name, prefix);
10393     SKIP_BLANKS;
10394     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10395         XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10396     }
10397 }
10398
10399 /**
10400  * xmlXPathIsNodeType:
10401  * @name:  a name string
10402  *
10403  * Is the name given a NodeType one.
10404  *
10405  *  [38]   NodeType ::=   'comment'
10406  *                    | 'text'
10407  *                    | 'processing-instruction'
10408  *                    | 'node'
10409  *
10410  * Returns 1 if true 0 otherwise
10411  */
10412 int
10413 xmlXPathIsNodeType(const xmlChar *name) {
10414     if (name == NULL)
10415         return(0);
10416
10417     if (xmlStrEqual(name, BAD_CAST "node"))
10418         return(1);
10419     if (xmlStrEqual(name, BAD_CAST "text"))
10420         return(1);
10421     if (xmlStrEqual(name, BAD_CAST "comment"))
10422         return(1);
10423     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10424         return(1);
10425     return(0);
10426 }
10427
10428 /**
10429  * xmlXPathCompFunctionCall:
10430  * @ctxt:  the XPath Parser context
10431  *
10432  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10433  *  [17]   Argument ::=   Expr
10434  *
10435  * Compile a function call, the evaluation of all arguments are
10436  * pushed on the stack
10437  */
10438 static void
10439 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10440     xmlChar *name;
10441     xmlChar *prefix;
10442     int nbargs = 0;
10443     int sort = 1;
10444
10445     name = xmlXPathParseQName(ctxt, &prefix);
10446     if (name == NULL) {
10447         xmlFree(prefix);
10448         XP_ERROR(XPATH_EXPR_ERROR);
10449     }
10450     SKIP_BLANKS;
10451 #ifdef DEBUG_EXPR
10452     if (prefix == NULL)
10453         xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10454                         name);
10455     else
10456         xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10457                         prefix, name);
10458 #endif
10459
10460     if (CUR != '(') {
10461         xmlFree(name);
10462         xmlFree(prefix);
10463         XP_ERROR(XPATH_EXPR_ERROR);
10464     }
10465     NEXT;
10466     SKIP_BLANKS;
10467
10468     /*
10469     * Optimization for count(): we don't need the node-set to be sorted.
10470     */
10471     if ((prefix == NULL) && (name[0] == 'c') &&
10472         xmlStrEqual(name, BAD_CAST "count"))
10473     {
10474         sort = 0;
10475     }
10476     ctxt->comp->last = -1;
10477     if (CUR != ')') {
10478         while (CUR != 0) {
10479             int op1 = ctxt->comp->last;
10480             ctxt->comp->last = -1;
10481             xmlXPathCompileExpr(ctxt, sort);
10482             if (ctxt->error != XPATH_EXPRESSION_OK) {
10483                 xmlFree(name);
10484                 xmlFree(prefix);
10485                 return;
10486             }
10487             PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10488             nbargs++;
10489             if (CUR == ')') break;
10490             if (CUR != ',') {
10491                 xmlFree(name);
10492                 xmlFree(prefix);
10493                 XP_ERROR(XPATH_EXPR_ERROR);
10494             }
10495             NEXT;
10496             SKIP_BLANKS;
10497         }
10498     }
10499     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10500                    name, prefix);
10501     NEXT;
10502     SKIP_BLANKS;
10503 }
10504
10505 /**
10506  * xmlXPathCompPrimaryExpr:
10507  * @ctxt:  the XPath Parser context
10508  *
10509  *  [15]   PrimaryExpr ::=   VariableReference
10510  *                | '(' Expr ')'
10511  *                | Literal
10512  *                | Number
10513  *                | FunctionCall
10514  *
10515  * Compile a primary expression.
10516  */
10517 static void
10518 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10519     SKIP_BLANKS;
10520     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10521     else if (CUR == '(') {
10522         NEXT;
10523         SKIP_BLANKS;
10524         xmlXPathCompileExpr(ctxt, 1);
10525         CHECK_ERROR;
10526         if (CUR != ')') {
10527             XP_ERROR(XPATH_EXPR_ERROR);
10528         }
10529         NEXT;
10530         SKIP_BLANKS;
10531     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10532         xmlXPathCompNumber(ctxt);
10533     } else if ((CUR == '\'') || (CUR == '"')) {
10534         xmlXPathCompLiteral(ctxt);
10535     } else {
10536         xmlXPathCompFunctionCall(ctxt);
10537     }
10538     SKIP_BLANKS;
10539 }
10540
10541 /**
10542  * xmlXPathCompFilterExpr:
10543  * @ctxt:  the XPath Parser context
10544  *
10545  *  [20]   FilterExpr ::=   PrimaryExpr
10546  *               | FilterExpr Predicate
10547  *
10548  * Compile a filter expression.
10549  * Square brackets are used to filter expressions in the same way that
10550  * they are used in location paths. It is an error if the expression to
10551  * be filtered does not evaluate to a node-set. The context node list
10552  * used for evaluating the expression in square brackets is the node-set
10553  * to be filtered listed in document order.
10554  */
10555
10556 static void
10557 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10558     xmlXPathCompPrimaryExpr(ctxt);
10559     CHECK_ERROR;
10560     SKIP_BLANKS;
10561
10562     while (CUR == '[') {
10563         xmlXPathCompPredicate(ctxt, 1);
10564         SKIP_BLANKS;
10565     }
10566
10567
10568 }
10569
10570 /**
10571  * xmlXPathScanName:
10572  * @ctxt:  the XPath Parser context
10573  *
10574  * Trickery: parse an XML name but without consuming the input flow
10575  * Needed to avoid insanity in the parser state.
10576  *
10577  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10578  *                  CombiningChar | Extender
10579  *
10580  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10581  *
10582  * [6] Names ::= Name (S Name)*
10583  *
10584  * Returns the Name parsed or NULL
10585  */
10586
10587 static xmlChar *
10588 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10589     int len = 0, l;
10590     int c;
10591     const xmlChar *cur;
10592     xmlChar *ret;
10593
10594     cur = ctxt->cur;
10595
10596     c = CUR_CHAR(l);
10597     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10598         (!IS_LETTER(c) && (c != '_') &&
10599          (c != ':'))) {
10600         return(NULL);
10601     }
10602
10603     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10604            ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10605             (c == '.') || (c == '-') ||
10606             (c == '_') || (c == ':') ||
10607             (IS_COMBINING(c)) ||
10608             (IS_EXTENDER(c)))) {
10609         len += l;
10610         NEXTL(l);
10611         c = CUR_CHAR(l);
10612     }
10613     ret = xmlStrndup(cur, ctxt->cur - cur);
10614     ctxt->cur = cur;
10615     return(ret);
10616 }
10617
10618 /**
10619  * xmlXPathCompPathExpr:
10620  * @ctxt:  the XPath Parser context
10621  *
10622  *  [19]   PathExpr ::=   LocationPath
10623  *               | FilterExpr
10624  *               | FilterExpr '/' RelativeLocationPath
10625  *               | FilterExpr '//' RelativeLocationPath
10626  *
10627  * Compile a path expression.
10628  * The / operator and // operators combine an arbitrary expression
10629  * and a relative location path. It is an error if the expression
10630  * does not evaluate to a node-set.
10631  * The / operator does composition in the same way as when / is
10632  * used in a location path. As in location paths, // is short for
10633  * /descendant-or-self::node()/.
10634  */
10635
10636 static void
10637 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10638     int lc = 1;           /* Should we branch to LocationPath ?         */
10639     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10640
10641     SKIP_BLANKS;
10642     if ((CUR == '$') || (CUR == '(') ||
10643         (IS_ASCII_DIGIT(CUR)) ||
10644         (CUR == '\'') || (CUR == '"') ||
10645         (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10646         lc = 0;
10647     } else if (CUR == '*') {
10648         /* relative or absolute location path */
10649         lc = 1;
10650     } else if (CUR == '/') {
10651         /* relative or absolute location path */
10652         lc = 1;
10653     } else if (CUR == '@') {
10654         /* relative abbreviated attribute location path */
10655         lc = 1;
10656     } else if (CUR == '.') {
10657         /* relative abbreviated attribute location path */
10658         lc = 1;
10659     } else {
10660         /*
10661          * Problem is finding if we have a name here whether it's:
10662          *   - a nodetype
10663          *   - a function call in which case it's followed by '('
10664          *   - an axis in which case it's followed by ':'
10665          *   - a element name
10666          * We do an a priori analysis here rather than having to
10667          * maintain parsed token content through the recursive function
10668          * calls. This looks uglier but makes the code easier to
10669          * read/write/debug.
10670          */
10671         SKIP_BLANKS;
10672         name = xmlXPathScanName(ctxt);
10673         if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10674 #ifdef DEBUG_STEP
10675             xmlGenericError(xmlGenericErrorContext,
10676                     "PathExpr: Axis\n");
10677 #endif
10678             lc = 1;
10679             xmlFree(name);
10680         } else if (name != NULL) {
10681             int len =xmlStrlen(name);
10682
10683
10684             while (NXT(len) != 0) {
10685                 if (NXT(len) == '/') {
10686                     /* element name */
10687 #ifdef DEBUG_STEP
10688                     xmlGenericError(xmlGenericErrorContext,
10689                             "PathExpr: AbbrRelLocation\n");
10690 #endif
10691                     lc = 1;
10692                     break;
10693                 } else if (IS_BLANK_CH(NXT(len))) {
10694                     /* ignore blanks */
10695                     ;
10696                 } else if (NXT(len) == ':') {
10697 #ifdef DEBUG_STEP
10698                     xmlGenericError(xmlGenericErrorContext,
10699                             "PathExpr: AbbrRelLocation\n");
10700 #endif
10701                     lc = 1;
10702                     break;
10703                 } else if ((NXT(len) == '(')) {
10704                     /* Node Type or Function */
10705                     if (xmlXPathIsNodeType(name)) {
10706 #ifdef DEBUG_STEP
10707                         xmlGenericError(xmlGenericErrorContext,
10708                                 "PathExpr: Type search\n");
10709 #endif
10710                         lc = 1;
10711 #ifdef LIBXML_XPTR_ENABLED
10712                     } else if (ctxt->xptr &&
10713                                xmlStrEqual(name, BAD_CAST "range-to")) {
10714                         lc = 1;
10715 #endif
10716                     } else {
10717 #ifdef DEBUG_STEP
10718                         xmlGenericError(xmlGenericErrorContext,
10719                                 "PathExpr: function call\n");
10720 #endif
10721                         lc = 0;
10722                     }
10723                     break;
10724                 } else if ((NXT(len) == '[')) {
10725                     /* element name */
10726 #ifdef DEBUG_STEP
10727                     xmlGenericError(xmlGenericErrorContext,
10728                             "PathExpr: AbbrRelLocation\n");
10729 #endif
10730                     lc = 1;
10731                     break;
10732                 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10733                            (NXT(len) == '=')) {
10734                     lc = 1;
10735                     break;
10736                 } else {
10737                     lc = 1;
10738                     break;
10739                 }
10740                 len++;
10741             }
10742             if (NXT(len) == 0) {
10743 #ifdef DEBUG_STEP
10744                 xmlGenericError(xmlGenericErrorContext,
10745                         "PathExpr: AbbrRelLocation\n");
10746 #endif
10747                 /* element name */
10748                 lc = 1;
10749             }
10750             xmlFree(name);
10751         } else {
10752             /* make sure all cases are covered explicitly */
10753             XP_ERROR(XPATH_EXPR_ERROR);
10754         }
10755     }
10756
10757     if (lc) {
10758         if (CUR == '/') {
10759             PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10760         } else {
10761             PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10762         }
10763         xmlXPathCompLocationPath(ctxt);
10764     } else {
10765         xmlXPathCompFilterExpr(ctxt);
10766         CHECK_ERROR;
10767         if ((CUR == '/') && (NXT(1) == '/')) {
10768             SKIP(2);
10769             SKIP_BLANKS;
10770
10771             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10772                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10773             PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10774
10775             xmlXPathCompRelativeLocationPath(ctxt);
10776         } else if (CUR == '/') {
10777             xmlXPathCompRelativeLocationPath(ctxt);
10778         }
10779     }
10780     SKIP_BLANKS;
10781 }
10782
10783 /**
10784  * xmlXPathCompUnionExpr:
10785  * @ctxt:  the XPath Parser context
10786  *
10787  *  [18]   UnionExpr ::=   PathExpr
10788  *               | UnionExpr '|' PathExpr
10789  *
10790  * Compile an union expression.
10791  */
10792
10793 static void
10794 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10795     xmlXPathCompPathExpr(ctxt);
10796     CHECK_ERROR;
10797     SKIP_BLANKS;
10798     while (CUR == '|') {
10799         int op1 = ctxt->comp->last;
10800         PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10801
10802         NEXT;
10803         SKIP_BLANKS;
10804         xmlXPathCompPathExpr(ctxt);
10805
10806         PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10807
10808         SKIP_BLANKS;
10809     }
10810 }
10811
10812 /**
10813  * xmlXPathCompUnaryExpr:
10814  * @ctxt:  the XPath Parser context
10815  *
10816  *  [27]   UnaryExpr ::=   UnionExpr
10817  *                   | '-' UnaryExpr
10818  *
10819  * Compile an unary expression.
10820  */
10821
10822 static void
10823 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10824     int minus = 0;
10825     int found = 0;
10826
10827     SKIP_BLANKS;
10828     while (CUR == '-') {
10829         minus = 1 - minus;
10830         found = 1;
10831         NEXT;
10832         SKIP_BLANKS;
10833     }
10834
10835     xmlXPathCompUnionExpr(ctxt);
10836     CHECK_ERROR;
10837     if (found) {
10838         if (minus)
10839             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10840         else
10841             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10842     }
10843 }
10844
10845 /**
10846  * xmlXPathCompMultiplicativeExpr:
10847  * @ctxt:  the XPath Parser context
10848  *
10849  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10850  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10851  *                   | MultiplicativeExpr 'div' UnaryExpr
10852  *                   | MultiplicativeExpr 'mod' UnaryExpr
10853  *  [34]   MultiplyOperator ::=   '*'
10854  *
10855  * Compile an Additive expression.
10856  */
10857
10858 static void
10859 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10860     xmlXPathCompUnaryExpr(ctxt);
10861     CHECK_ERROR;
10862     SKIP_BLANKS;
10863     while ((CUR == '*') ||
10864            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10865            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10866         int op = -1;
10867         int op1 = ctxt->comp->last;
10868
10869         if (CUR == '*') {
10870             op = 0;
10871             NEXT;
10872         } else if (CUR == 'd') {
10873             op = 1;
10874             SKIP(3);
10875         } else if (CUR == 'm') {
10876             op = 2;
10877             SKIP(3);
10878         }
10879         SKIP_BLANKS;
10880         xmlXPathCompUnaryExpr(ctxt);
10881         CHECK_ERROR;
10882         PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10883         SKIP_BLANKS;
10884     }
10885 }
10886
10887 /**
10888  * xmlXPathCompAdditiveExpr:
10889  * @ctxt:  the XPath Parser context
10890  *
10891  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10892  *                   | AdditiveExpr '+' MultiplicativeExpr
10893  *                   | AdditiveExpr '-' MultiplicativeExpr
10894  *
10895  * Compile an Additive expression.
10896  */
10897
10898 static void
10899 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10900
10901     xmlXPathCompMultiplicativeExpr(ctxt);
10902     CHECK_ERROR;
10903     SKIP_BLANKS;
10904     while ((CUR == '+') || (CUR == '-')) {
10905         int plus;
10906         int op1 = ctxt->comp->last;
10907
10908         if (CUR == '+') plus = 1;
10909         else plus = 0;
10910         NEXT;
10911         SKIP_BLANKS;
10912         xmlXPathCompMultiplicativeExpr(ctxt);
10913         CHECK_ERROR;
10914         PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10915         SKIP_BLANKS;
10916     }
10917 }
10918
10919 /**
10920  * xmlXPathCompRelationalExpr:
10921  * @ctxt:  the XPath Parser context
10922  *
10923  *  [24]   RelationalExpr ::=   AdditiveExpr
10924  *                 | RelationalExpr '<' AdditiveExpr
10925  *                 | RelationalExpr '>' AdditiveExpr
10926  *                 | RelationalExpr '<=' AdditiveExpr
10927  *                 | RelationalExpr '>=' AdditiveExpr
10928  *
10929  *  A <= B > C is allowed ? Answer from James, yes with
10930  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10931  *  which is basically what got implemented.
10932  *
10933  * Compile a Relational expression, then push the result
10934  * on the stack
10935  */
10936
10937 static void
10938 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10939     xmlXPathCompAdditiveExpr(ctxt);
10940     CHECK_ERROR;
10941     SKIP_BLANKS;
10942     while ((CUR == '<') ||
10943            (CUR == '>') ||
10944            ((CUR == '<') && (NXT(1) == '=')) ||
10945            ((CUR == '>') && (NXT(1) == '='))) {
10946         int inf, strict;
10947         int op1 = ctxt->comp->last;
10948
10949         if (CUR == '<') inf = 1;
10950         else inf = 0;
10951         if (NXT(1) == '=') strict = 0;
10952         else strict = 1;
10953         NEXT;
10954         if (!strict) NEXT;
10955         SKIP_BLANKS;
10956         xmlXPathCompAdditiveExpr(ctxt);
10957         CHECK_ERROR;
10958         PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10959         SKIP_BLANKS;
10960     }
10961 }
10962
10963 /**
10964  * xmlXPathCompEqualityExpr:
10965  * @ctxt:  the XPath Parser context
10966  *
10967  *  [23]   EqualityExpr ::=   RelationalExpr
10968  *                 | EqualityExpr '=' RelationalExpr
10969  *                 | EqualityExpr '!=' RelationalExpr
10970  *
10971  *  A != B != C is allowed ? Answer from James, yes with
10972  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10973  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10974  *  which is basically what got implemented.
10975  *
10976  * Compile an Equality expression.
10977  *
10978  */
10979 static void
10980 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10981     xmlXPathCompRelationalExpr(ctxt);
10982     CHECK_ERROR;
10983     SKIP_BLANKS;
10984     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10985         int eq;
10986         int op1 = ctxt->comp->last;
10987
10988         if (CUR == '=') eq = 1;
10989         else eq = 0;
10990         NEXT;
10991         if (!eq) NEXT;
10992         SKIP_BLANKS;
10993         xmlXPathCompRelationalExpr(ctxt);
10994         CHECK_ERROR;
10995         PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10996         SKIP_BLANKS;
10997     }
10998 }
10999
11000 /**
11001  * xmlXPathCompAndExpr:
11002  * @ctxt:  the XPath Parser context
11003  *
11004  *  [22]   AndExpr ::=   EqualityExpr
11005  *                 | AndExpr 'and' EqualityExpr
11006  *
11007  * Compile an AND expression.
11008  *
11009  */
11010 static void
11011 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
11012     xmlXPathCompEqualityExpr(ctxt);
11013     CHECK_ERROR;
11014     SKIP_BLANKS;
11015     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
11016         int op1 = ctxt->comp->last;
11017         SKIP(3);
11018         SKIP_BLANKS;
11019         xmlXPathCompEqualityExpr(ctxt);
11020         CHECK_ERROR;
11021         PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11022         SKIP_BLANKS;
11023     }
11024 }
11025
11026 /**
11027  * xmlXPathCompileExpr:
11028  * @ctxt:  the XPath Parser context
11029  *
11030  *  [14]   Expr ::=   OrExpr
11031  *  [21]   OrExpr ::=   AndExpr
11032  *                 | OrExpr 'or' AndExpr
11033  *
11034  * Parse and compile an expression
11035  */
11036 static void
11037 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11038     xmlXPathCompAndExpr(ctxt);
11039     CHECK_ERROR;
11040     SKIP_BLANKS;
11041     while ((CUR == 'o') && (NXT(1) == 'r')) {
11042         int op1 = ctxt->comp->last;
11043         SKIP(2);
11044         SKIP_BLANKS;
11045         xmlXPathCompAndExpr(ctxt);
11046         CHECK_ERROR;
11047         PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11048         SKIP_BLANKS;
11049     }
11050     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11051         /* more ops could be optimized too */
11052         /*
11053         * This is the main place to eliminate sorting for
11054         * operations which don't require a sorted node-set.
11055         * E.g. count().
11056         */
11057         PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11058     }
11059 }
11060
11061 /**
11062  * xmlXPathCompPredicate:
11063  * @ctxt:  the XPath Parser context
11064  * @filter:  act as a filter
11065  *
11066  *  [8]   Predicate ::=   '[' PredicateExpr ']'
11067  *  [9]   PredicateExpr ::=   Expr
11068  *
11069  * Compile a predicate expression
11070  */
11071 static void
11072 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11073     int op1 = ctxt->comp->last;
11074
11075     SKIP_BLANKS;
11076     if (CUR != '[') {
11077         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11078     }
11079     NEXT;
11080     SKIP_BLANKS;
11081
11082     ctxt->comp->last = -1;
11083     /*
11084     * This call to xmlXPathCompileExpr() will deactivate sorting
11085     * of the predicate result.
11086     * TODO: Sorting is still activated for filters, since I'm not
11087     *  sure if needed. Normally sorting should not be needed, since
11088     *  a filter can only diminish the number of items in a sequence,
11089     *  but won't change its order; so if the initial sequence is sorted,
11090     *  subsequent sorting is not needed.
11091     */
11092     if (! filter)
11093         xmlXPathCompileExpr(ctxt, 0);
11094     else
11095         xmlXPathCompileExpr(ctxt, 1);
11096     CHECK_ERROR;
11097
11098     if (CUR != ']') {
11099         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11100     }
11101
11102     if (filter)
11103         PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11104     else
11105         PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11106
11107     NEXT;
11108     SKIP_BLANKS;
11109 }
11110
11111 /**
11112  * xmlXPathCompNodeTest:
11113  * @ctxt:  the XPath Parser context
11114  * @test:  pointer to a xmlXPathTestVal
11115  * @type:  pointer to a xmlXPathTypeVal
11116  * @prefix:  placeholder for a possible name prefix
11117  *
11118  * [7] NodeTest ::=   NameTest
11119  *                  | NodeType '(' ')'
11120  *                  | 'processing-instruction' '(' Literal ')'
11121  *
11122  * [37] NameTest ::=  '*'
11123  *                  | NCName ':' '*'
11124  *                  | QName
11125  * [38] NodeType ::= 'comment'
11126  *                 | 'text'
11127  *                 | 'processing-instruction'
11128  *                 | 'node'
11129  *
11130  * Returns the name found and updates @test, @type and @prefix appropriately
11131  */
11132 static xmlChar *
11133 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11134                      xmlXPathTypeVal *type, const xmlChar **prefix,
11135                      xmlChar *name) {
11136     int blanks;
11137
11138     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11139         STRANGE;
11140         return(NULL);
11141     }
11142     *type = (xmlXPathTypeVal) 0;
11143     *test = (xmlXPathTestVal) 0;
11144     *prefix = NULL;
11145     SKIP_BLANKS;
11146
11147     if ((name == NULL) && (CUR == '*')) {
11148         /*
11149          * All elements
11150          */
11151         NEXT;
11152         *test = NODE_TEST_ALL;
11153         return(NULL);
11154     }
11155
11156     if (name == NULL)
11157         name = xmlXPathParseNCName(ctxt);
11158     if (name == NULL) {
11159         XP_ERRORNULL(XPATH_EXPR_ERROR);
11160     }
11161
11162     blanks = IS_BLANK_CH(CUR);
11163     SKIP_BLANKS;
11164     if (CUR == '(') {
11165         NEXT;
11166         /*
11167          * NodeType or PI search
11168          */
11169         if (xmlStrEqual(name, BAD_CAST "comment"))
11170             *type = NODE_TYPE_COMMENT;
11171         else if (xmlStrEqual(name, BAD_CAST "node"))
11172             *type = NODE_TYPE_NODE;
11173         else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11174             *type = NODE_TYPE_PI;
11175         else if (xmlStrEqual(name, BAD_CAST "text"))
11176             *type = NODE_TYPE_TEXT;
11177         else {
11178             if (name != NULL)
11179                 xmlFree(name);
11180             XP_ERRORNULL(XPATH_EXPR_ERROR);
11181         }
11182
11183         *test = NODE_TEST_TYPE;
11184
11185         SKIP_BLANKS;
11186         if (*type == NODE_TYPE_PI) {
11187             /*
11188              * Specific case: search a PI by name.
11189              */
11190             if (name != NULL)
11191                 xmlFree(name);
11192             name = NULL;
11193             if (CUR != ')') {
11194                 name = xmlXPathParseLiteral(ctxt);
11195                 CHECK_ERROR NULL;
11196                 *test = NODE_TEST_PI;
11197                 SKIP_BLANKS;
11198             }
11199         }
11200         if (CUR != ')') {
11201             if (name != NULL)
11202                 xmlFree(name);
11203             XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11204         }
11205         NEXT;
11206         return(name);
11207     }
11208     *test = NODE_TEST_NAME;
11209     if ((!blanks) && (CUR == ':')) {
11210         NEXT;
11211
11212         /*
11213          * Since currently the parser context don't have a
11214          * namespace list associated:
11215          * The namespace name for this prefix can be computed
11216          * only at evaluation time. The compilation is done
11217          * outside of any context.
11218          */
11219 #if 0
11220         *prefix = xmlXPathNsLookup(ctxt->context, name);
11221         if (name != NULL)
11222             xmlFree(name);
11223         if (*prefix == NULL) {
11224             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11225         }
11226 #else
11227         *prefix = name;
11228 #endif
11229
11230         if (CUR == '*') {
11231             /*
11232              * All elements
11233              */
11234             NEXT;
11235             *test = NODE_TEST_ALL;
11236             return(NULL);
11237         }
11238
11239         name = xmlXPathParseNCName(ctxt);
11240         if (name == NULL) {
11241             XP_ERRORNULL(XPATH_EXPR_ERROR);
11242         }
11243     }
11244     return(name);
11245 }
11246
11247 /**
11248  * xmlXPathIsAxisName:
11249  * @name:  a preparsed name token
11250  *
11251  * [6] AxisName ::=   'ancestor'
11252  *                  | 'ancestor-or-self'
11253  *                  | 'attribute'
11254  *                  | 'child'
11255  *                  | 'descendant'
11256  *                  | 'descendant-or-self'
11257  *                  | 'following'
11258  *                  | 'following-sibling'
11259  *                  | 'namespace'
11260  *                  | 'parent'
11261  *                  | 'preceding'
11262  *                  | 'preceding-sibling'
11263  *                  | 'self'
11264  *
11265  * Returns the axis or 0
11266  */
11267 static xmlXPathAxisVal
11268 xmlXPathIsAxisName(const xmlChar *name) {
11269     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11270     switch (name[0]) {
11271         case 'a':
11272             if (xmlStrEqual(name, BAD_CAST "ancestor"))
11273                 ret = AXIS_ANCESTOR;
11274             if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11275                 ret = AXIS_ANCESTOR_OR_SELF;
11276             if (xmlStrEqual(name, BAD_CAST "attribute"))
11277                 ret = AXIS_ATTRIBUTE;
11278             break;
11279         case 'c':
11280             if (xmlStrEqual(name, BAD_CAST "child"))
11281                 ret = AXIS_CHILD;
11282             break;
11283         case 'd':
11284             if (xmlStrEqual(name, BAD_CAST "descendant"))
11285                 ret = AXIS_DESCENDANT;
11286             if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11287                 ret = AXIS_DESCENDANT_OR_SELF;
11288             break;
11289         case 'f':
11290             if (xmlStrEqual(name, BAD_CAST "following"))
11291                 ret = AXIS_FOLLOWING;
11292             if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11293                 ret = AXIS_FOLLOWING_SIBLING;
11294             break;
11295         case 'n':
11296             if (xmlStrEqual(name, BAD_CAST "namespace"))
11297                 ret = AXIS_NAMESPACE;
11298             break;
11299         case 'p':
11300             if (xmlStrEqual(name, BAD_CAST "parent"))
11301                 ret = AXIS_PARENT;
11302             if (xmlStrEqual(name, BAD_CAST "preceding"))
11303                 ret = AXIS_PRECEDING;
11304             if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11305                 ret = AXIS_PRECEDING_SIBLING;
11306             break;
11307         case 's':
11308             if (xmlStrEqual(name, BAD_CAST "self"))
11309                 ret = AXIS_SELF;
11310             break;
11311     }
11312     return(ret);
11313 }
11314
11315 /**
11316  * xmlXPathCompStep:
11317  * @ctxt:  the XPath Parser context
11318  *
11319  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11320  *                  | AbbreviatedStep
11321  *
11322  * [12] AbbreviatedStep ::=   '.' | '..'
11323  *
11324  * [5] AxisSpecifier ::= AxisName '::'
11325  *                  | AbbreviatedAxisSpecifier
11326  *
11327  * [13] AbbreviatedAxisSpecifier ::= '@'?
11328  *
11329  * Modified for XPtr range support as:
11330  *
11331  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11332  *                     | AbbreviatedStep
11333  *                     | 'range-to' '(' Expr ')' Predicate*
11334  *
11335  * Compile one step in a Location Path
11336  * A location step of . is short for self::node(). This is
11337  * particularly useful in conjunction with //. For example, the
11338  * location path .//para is short for
11339  * self::node()/descendant-or-self::node()/child::para
11340  * and so will select all para descendant elements of the context
11341  * node.
11342  * Similarly, a location step of .. is short for parent::node().
11343  * For example, ../title is short for parent::node()/child::title
11344  * and so will select the title children of the parent of the context
11345  * node.
11346  */
11347 static void
11348 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11349 #ifdef LIBXML_XPTR_ENABLED
11350     int rangeto = 0;
11351     int op2 = -1;
11352 #endif
11353
11354     SKIP_BLANKS;
11355     if ((CUR == '.') && (NXT(1) == '.')) {
11356         SKIP(2);
11357         SKIP_BLANKS;
11358         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11359                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11360     } else if (CUR == '.') {
11361         NEXT;
11362         SKIP_BLANKS;
11363     } else {
11364         xmlChar *name = NULL;
11365         const xmlChar *prefix = NULL;
11366         xmlXPathTestVal test = (xmlXPathTestVal) 0;
11367         xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11368         xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11369         int op1;
11370
11371         /*
11372          * The modification needed for XPointer change to the production
11373          */
11374 #ifdef LIBXML_XPTR_ENABLED
11375         if (ctxt->xptr) {
11376             name = xmlXPathParseNCName(ctxt);
11377             if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11378                 op2 = ctxt->comp->last;
11379                 xmlFree(name);
11380                 SKIP_BLANKS;
11381                 if (CUR != '(') {
11382                     XP_ERROR(XPATH_EXPR_ERROR);
11383                 }
11384                 NEXT;
11385                 SKIP_BLANKS;
11386
11387                 xmlXPathCompileExpr(ctxt, 1);
11388                 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11389                 CHECK_ERROR;
11390
11391                 SKIP_BLANKS;
11392                 if (CUR != ')') {
11393                     XP_ERROR(XPATH_EXPR_ERROR);
11394                 }
11395                 NEXT;
11396                 rangeto = 1;
11397                 goto eval_predicates;
11398             }
11399         }
11400 #endif
11401         if (CUR == '*') {
11402             axis = AXIS_CHILD;
11403         } else {
11404             if (name == NULL)
11405                 name = xmlXPathParseNCName(ctxt);
11406             if (name != NULL) {
11407                 axis = xmlXPathIsAxisName(name);
11408                 if (axis != 0) {
11409                     SKIP_BLANKS;
11410                     if ((CUR == ':') && (NXT(1) == ':')) {
11411                         SKIP(2);
11412                         xmlFree(name);
11413                         name = NULL;
11414                     } else {
11415                         /* an element name can conflict with an axis one :-\ */
11416                         axis = AXIS_CHILD;
11417                     }
11418                 } else {
11419                     axis = AXIS_CHILD;
11420                 }
11421             } else if (CUR == '@') {
11422                 NEXT;
11423                 axis = AXIS_ATTRIBUTE;
11424             } else {
11425                 axis = AXIS_CHILD;
11426             }
11427         }
11428
11429         if (ctxt->error != XPATH_EXPRESSION_OK) {
11430             xmlFree(name);
11431             return;
11432         }
11433
11434         name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11435         if (test == 0)
11436             return;
11437
11438         if ((prefix != NULL) && (ctxt->context != NULL) &&
11439             (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11440             if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11441                 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11442             }
11443         }
11444 #ifdef DEBUG_STEP
11445         xmlGenericError(xmlGenericErrorContext,
11446                 "Basis : computing new set\n");
11447 #endif
11448
11449 #ifdef DEBUG_STEP
11450         xmlGenericError(xmlGenericErrorContext, "Basis : ");
11451         if (ctxt->value == NULL)
11452             xmlGenericError(xmlGenericErrorContext, "no value\n");
11453         else if (ctxt->value->nodesetval == NULL)
11454             xmlGenericError(xmlGenericErrorContext, "Empty\n");
11455         else
11456             xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11457 #endif
11458
11459 #ifdef LIBXML_XPTR_ENABLED
11460 eval_predicates:
11461 #endif
11462         op1 = ctxt->comp->last;
11463         ctxt->comp->last = -1;
11464
11465         SKIP_BLANKS;
11466         while (CUR == '[') {
11467             xmlXPathCompPredicate(ctxt, 0);
11468         }
11469
11470 #ifdef LIBXML_XPTR_ENABLED
11471         if (rangeto) {
11472             PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11473         } else
11474 #endif
11475             PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11476                            test, type, (void *)prefix, (void *)name);
11477
11478     }
11479 #ifdef DEBUG_STEP
11480     xmlGenericError(xmlGenericErrorContext, "Step : ");
11481     if (ctxt->value == NULL)
11482         xmlGenericError(xmlGenericErrorContext, "no value\n");
11483     else if (ctxt->value->nodesetval == NULL)
11484         xmlGenericError(xmlGenericErrorContext, "Empty\n");
11485     else
11486         xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11487                 ctxt->value->nodesetval);
11488 #endif
11489 }
11490
11491 /**
11492  * xmlXPathCompRelativeLocationPath:
11493  * @ctxt:  the XPath Parser context
11494  *
11495  *  [3]   RelativeLocationPath ::=   Step
11496  *                     | RelativeLocationPath '/' Step
11497  *                     | AbbreviatedRelativeLocationPath
11498  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11499  *
11500  * Compile a relative location path.
11501  */
11502 static void
11503 xmlXPathCompRelativeLocationPath
11504 (xmlXPathParserContextPtr ctxt) {
11505     SKIP_BLANKS;
11506     if ((CUR == '/') && (NXT(1) == '/')) {
11507         SKIP(2);
11508         SKIP_BLANKS;
11509         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11510                          NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11511     } else if (CUR == '/') {
11512             NEXT;
11513         SKIP_BLANKS;
11514     }
11515     xmlXPathCompStep(ctxt);
11516     CHECK_ERROR;
11517     SKIP_BLANKS;
11518     while (CUR == '/') {
11519         if ((CUR == '/') && (NXT(1) == '/')) {
11520             SKIP(2);
11521             SKIP_BLANKS;
11522             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11523                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11524             xmlXPathCompStep(ctxt);
11525         } else if (CUR == '/') {
11526             NEXT;
11527             SKIP_BLANKS;
11528             xmlXPathCompStep(ctxt);
11529         }
11530         SKIP_BLANKS;
11531     }
11532 }
11533
11534 /**
11535  * xmlXPathCompLocationPath:
11536  * @ctxt:  the XPath Parser context
11537  *
11538  *  [1]   LocationPath ::=   RelativeLocationPath
11539  *                     | AbsoluteLocationPath
11540  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11541  *                     | AbbreviatedAbsoluteLocationPath
11542  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11543  *                           '//' RelativeLocationPath
11544  *
11545  * Compile a location path
11546  *
11547  * // is short for /descendant-or-self::node()/. For example,
11548  * //para is short for /descendant-or-self::node()/child::para and
11549  * so will select any para element in the document (even a para element
11550  * that is a document element will be selected by //para since the
11551  * document element node is a child of the root node); div//para is
11552  * short for div/descendant-or-self::node()/child::para and so will
11553  * select all para descendants of div children.
11554  */
11555 static void
11556 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11557     SKIP_BLANKS;
11558     if (CUR != '/') {
11559         xmlXPathCompRelativeLocationPath(ctxt);
11560     } else {
11561         while (CUR == '/') {
11562             if ((CUR == '/') && (NXT(1) == '/')) {
11563                 SKIP(2);
11564                 SKIP_BLANKS;
11565                 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11566                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11567                 xmlXPathCompRelativeLocationPath(ctxt);
11568             } else if (CUR == '/') {
11569                 NEXT;
11570                 SKIP_BLANKS;
11571                 if ((CUR != 0 ) &&
11572                     ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11573                      (CUR == '@') || (CUR == '*')))
11574                     xmlXPathCompRelativeLocationPath(ctxt);
11575             }
11576             CHECK_ERROR;
11577         }
11578     }
11579 }
11580
11581 /************************************************************************
11582  *                                                                      *
11583  *              XPath precompiled expression evaluation                 *
11584  *                                                                      *
11585  ************************************************************************/
11586
11587 static int
11588 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11589
11590 #ifdef DEBUG_STEP
11591 static void
11592 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11593                           int nbNodes)
11594 {
11595     xmlGenericError(xmlGenericErrorContext, "new step : ");
11596     switch (op->value) {
11597         case AXIS_ANCESTOR:
11598             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11599             break;
11600         case AXIS_ANCESTOR_OR_SELF:
11601             xmlGenericError(xmlGenericErrorContext,
11602                             "axis 'ancestors-or-self' ");
11603             break;
11604         case AXIS_ATTRIBUTE:
11605             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11606             break;
11607         case AXIS_CHILD:
11608             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11609             break;
11610         case AXIS_DESCENDANT:
11611             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11612             break;
11613         case AXIS_DESCENDANT_OR_SELF:
11614             xmlGenericError(xmlGenericErrorContext,
11615                             "axis 'descendant-or-self' ");
11616             break;
11617         case AXIS_FOLLOWING:
11618             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11619             break;
11620         case AXIS_FOLLOWING_SIBLING:
11621             xmlGenericError(xmlGenericErrorContext,
11622                             "axis 'following-siblings' ");
11623             break;
11624         case AXIS_NAMESPACE:
11625             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11626             break;
11627         case AXIS_PARENT:
11628             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11629             break;
11630         case AXIS_PRECEDING:
11631             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11632             break;
11633         case AXIS_PRECEDING_SIBLING:
11634             xmlGenericError(xmlGenericErrorContext,
11635                             "axis 'preceding-sibling' ");
11636             break;
11637         case AXIS_SELF:
11638             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11639             break;
11640     }
11641     xmlGenericError(xmlGenericErrorContext,
11642         " context contains %d nodes\n", nbNodes);
11643     switch (op->value2) {
11644         case NODE_TEST_NONE:
11645             xmlGenericError(xmlGenericErrorContext,
11646                             "           searching for none !!!\n");
11647             break;
11648         case NODE_TEST_TYPE:
11649             xmlGenericError(xmlGenericErrorContext,
11650                             "           searching for type %d\n", op->value3);
11651             break;
11652         case NODE_TEST_PI:
11653             xmlGenericError(xmlGenericErrorContext,
11654                             "           searching for PI !!!\n");
11655             break;
11656         case NODE_TEST_ALL:
11657             xmlGenericError(xmlGenericErrorContext,
11658                             "           searching for *\n");
11659             break;
11660         case NODE_TEST_NS:
11661             xmlGenericError(xmlGenericErrorContext,
11662                             "           searching for namespace %s\n",
11663                             op->value5);
11664             break;
11665         case NODE_TEST_NAME:
11666             xmlGenericError(xmlGenericErrorContext,
11667                             "           searching for name %s\n", op->value5);
11668             if (op->value4)
11669                 xmlGenericError(xmlGenericErrorContext,
11670                                 "           with namespace %s\n", op->value4);
11671             break;
11672     }
11673     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11674 }
11675 #endif /* DEBUG_STEP */
11676
11677 static int
11678 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11679                             xmlXPathStepOpPtr op,
11680                             xmlNodeSetPtr set,
11681                             int contextSize,
11682                             int hasNsNodes)
11683 {
11684     if (op->ch1 != -1) {
11685         xmlXPathCompExprPtr comp = ctxt->comp;
11686         /*
11687         * Process inner predicates first.
11688         */
11689         if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11690             /*
11691             * TODO: raise an internal error.
11692             */
11693         }
11694         contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11695             &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11696         CHECK_ERROR0;
11697         if (contextSize <= 0)
11698             return(0);
11699     }
11700     if (op->ch2 != -1) {
11701         xmlXPathContextPtr xpctxt = ctxt->context;
11702         xmlNodePtr contextNode, oldContextNode;
11703         xmlDocPtr oldContextDoc;
11704         int i, res, contextPos = 0, newContextSize;
11705         xmlXPathStepOpPtr exprOp;
11706         xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11707
11708 #ifdef LIBXML_XPTR_ENABLED
11709         /*
11710         * URGENT TODO: Check the following:
11711         *  We don't expect location sets if evaluating prediates, right?
11712         *  Only filters should expect location sets, right?
11713         */
11714 #endif
11715         /*
11716         * SPEC XPath 1.0:
11717         *  "For each node in the node-set to be filtered, the
11718         *  PredicateExpr is evaluated with that node as the
11719         *  context node, with the number of nodes in the
11720         *  node-set as the context size, and with the proximity
11721         *  position of the node in the node-set with respect to
11722         *  the axis as the context position;"
11723         * @oldset is the node-set" to be filtered.
11724         *
11725         * SPEC XPath 1.0:
11726         *  "only predicates change the context position and
11727         *  context size (see [2.4 Predicates])."
11728         * Example:
11729         *   node-set  context pos
11730         *    nA         1
11731         *    nB         2
11732         *    nC         3
11733         *   After applying predicate [position() > 1] :
11734         *   node-set  context pos
11735         *    nB         1
11736         *    nC         2
11737         */
11738         oldContextNode = xpctxt->node;
11739         oldContextDoc = xpctxt->doc;
11740         /*
11741         * Get the expression of this predicate.
11742         */
11743         exprOp = &ctxt->comp->steps[op->ch2];
11744         newContextSize = 0;
11745         for (i = 0; i < set->nodeNr; i++) {
11746             if (set->nodeTab[i] == NULL)
11747                 continue;
11748
11749             contextNode = set->nodeTab[i];
11750             xpctxt->node = contextNode;
11751             xpctxt->contextSize = contextSize;
11752             xpctxt->proximityPosition = ++contextPos;
11753
11754             /*
11755             * Also set the xpath document in case things like
11756             * key() are evaluated in the predicate.
11757             */
11758             if ((contextNode->type != XML_NAMESPACE_DECL) &&
11759                 (contextNode->doc != NULL))
11760                 xpctxt->doc = contextNode->doc;
11761             /*
11762             * Evaluate the predicate expression with 1 context node
11763             * at a time; this node is packaged into a node set; this
11764             * node set is handed over to the evaluation mechanism.
11765             */
11766             if (contextObj == NULL)
11767                 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11768             else {
11769                 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11770                     contextNode) < 0) {
11771                     ctxt->error = XPATH_MEMORY_ERROR;
11772                     goto evaluation_exit;
11773                 }
11774             }
11775
11776             valuePush(ctxt, contextObj);
11777
11778             res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11779
11780             if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11781                 xmlXPathNodeSetClear(set, hasNsNodes);
11782                 newContextSize = 0;
11783                 goto evaluation_exit;
11784             }
11785
11786             if (res != 0) {
11787                 newContextSize++;
11788             } else {
11789                 /*
11790                 * Remove the entry from the initial node set.
11791                 */
11792                 set->nodeTab[i] = NULL;
11793                 if (contextNode->type == XML_NAMESPACE_DECL)
11794                     xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11795             }
11796             if (ctxt->value == contextObj) {
11797                 /*
11798                 * Don't free the temporary XPath object holding the
11799                 * context node, in order to avoid massive recreation
11800                 * inside this loop.
11801                 */
11802                 valuePop(ctxt);
11803                 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11804             } else {
11805                 /*
11806                 * TODO: The object was lost in the evaluation machinery.
11807                 *  Can this happen? Maybe in internal-error cases.
11808                 */
11809                 contextObj = NULL;
11810             }
11811         }
11812
11813         if (contextObj != NULL) {
11814             if (ctxt->value == contextObj)
11815                 valuePop(ctxt);
11816             xmlXPathReleaseObject(xpctxt, contextObj);
11817         }
11818 evaluation_exit:
11819         if (exprRes != NULL)
11820             xmlXPathReleaseObject(ctxt->context, exprRes);
11821         /*
11822         * Reset/invalidate the context.
11823         */
11824         xpctxt->node = oldContextNode;
11825         xpctxt->doc = oldContextDoc;
11826         xpctxt->contextSize = -1;
11827         xpctxt->proximityPosition = -1;
11828         return(newContextSize);
11829     }
11830     return(contextSize);
11831 }
11832
11833 static int
11834 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11835                                       xmlXPathStepOpPtr op,
11836                                       xmlNodeSetPtr set,
11837                                       int contextSize,
11838                                       int minPos,
11839                                       int maxPos,
11840                                       int hasNsNodes)
11841 {
11842     if (op->ch1 != -1) {
11843         xmlXPathCompExprPtr comp = ctxt->comp;
11844         if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11845             /*
11846             * TODO: raise an internal error.
11847             */
11848         }
11849         contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11850             &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11851         CHECK_ERROR0;
11852         if (contextSize <= 0)
11853             return(0);
11854     }
11855     /*
11856     * Check if the node set contains a sufficient number of nodes for
11857     * the requested range.
11858     */
11859     if (contextSize < minPos) {
11860         xmlXPathNodeSetClear(set, hasNsNodes);
11861         return(0);
11862     }
11863     if (op->ch2 == -1) {
11864         /*
11865         * TODO: Can this ever happen?
11866         */
11867         return (contextSize);
11868     } else {
11869         xmlDocPtr oldContextDoc;
11870         int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11871         xmlXPathStepOpPtr exprOp;
11872         xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11873         xmlNodePtr oldContextNode, contextNode = NULL;
11874         xmlXPathContextPtr xpctxt = ctxt->context;
11875         int frame;
11876
11877 #ifdef LIBXML_XPTR_ENABLED
11878             /*
11879             * URGENT TODO: Check the following:
11880             *  We don't expect location sets if evaluating prediates, right?
11881             *  Only filters should expect location sets, right?
11882         */
11883 #endif /* LIBXML_XPTR_ENABLED */
11884
11885         /*
11886         * Save old context.
11887         */
11888         oldContextNode = xpctxt->node;
11889         oldContextDoc = xpctxt->doc;
11890         /*
11891         * Get the expression of this predicate.
11892         */
11893         exprOp = &ctxt->comp->steps[op->ch2];
11894         for (i = 0; i < set->nodeNr; i++) {
11895             xmlXPathObjectPtr tmp;
11896
11897             if (set->nodeTab[i] == NULL)
11898                 continue;
11899
11900             contextNode = set->nodeTab[i];
11901             xpctxt->node = contextNode;
11902             xpctxt->contextSize = contextSize;
11903             xpctxt->proximityPosition = ++contextPos;
11904
11905             /*
11906             * Initialize the new set.
11907             * Also set the xpath document in case things like
11908             * key() evaluation are attempted on the predicate
11909             */
11910             if ((contextNode->type != XML_NAMESPACE_DECL) &&
11911                 (contextNode->doc != NULL))
11912                 xpctxt->doc = contextNode->doc;
11913             /*
11914             * Evaluate the predicate expression with 1 context node
11915             * at a time; this node is packaged into a node set; this
11916             * node set is handed over to the evaluation mechanism.
11917             */
11918             if (contextObj == NULL)
11919                 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11920             else {
11921                 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11922                     contextNode) < 0) {
11923                     ctxt->error = XPATH_MEMORY_ERROR;
11924                     goto evaluation_exit;
11925                 }
11926             }
11927
11928             frame = xmlXPathSetFrame(ctxt);
11929             valuePush(ctxt, contextObj);
11930             res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11931             tmp = valuePop(ctxt);
11932             xmlXPathPopFrame(ctxt, frame);
11933
11934             if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11935                 while (tmp != contextObj) {
11936                     /*
11937                      * Free up the result
11938                      * then pop off contextObj, which will be freed later
11939                      */
11940                     xmlXPathReleaseObject(xpctxt, tmp);
11941                     tmp = valuePop(ctxt);
11942                 }
11943                 goto evaluation_error;
11944             }
11945             /* push the result back onto the stack */
11946             valuePush(ctxt, tmp);
11947
11948             if (res)
11949                 pos++;
11950
11951             if (res && (pos >= minPos) && (pos <= maxPos)) {
11952                 /*
11953                 * Fits in the requested range.
11954                 */
11955                 newContextSize++;
11956                 if (minPos == maxPos) {
11957                     /*
11958                     * Only 1 node was requested.
11959                     */
11960                     if (contextNode->type == XML_NAMESPACE_DECL) {
11961                         /*
11962                         * As always: take care of those nasty
11963                         * namespace nodes.
11964                         */
11965                         set->nodeTab[i] = NULL;
11966                     }
11967                     xmlXPathNodeSetClear(set, hasNsNodes);
11968                     set->nodeNr = 1;
11969                     set->nodeTab[0] = contextNode;
11970                     goto evaluation_exit;
11971                 }
11972                 if (pos == maxPos) {
11973                     /*
11974                     * We are done.
11975                     */
11976                     xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11977                     goto evaluation_exit;
11978                 }
11979             } else {
11980                 /*
11981                 * Remove the entry from the initial node set.
11982                 */
11983                 set->nodeTab[i] = NULL;
11984                 if (contextNode->type == XML_NAMESPACE_DECL)
11985                     xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11986             }
11987             if (exprRes != NULL) {
11988                 xmlXPathReleaseObject(ctxt->context, exprRes);
11989                 exprRes = NULL;
11990             }
11991             if (ctxt->value == contextObj) {
11992                 /*
11993                 * Don't free the temporary XPath object holding the
11994                 * context node, in order to avoid massive recreation
11995                 * inside this loop.
11996                 */
11997                 valuePop(ctxt);
11998                 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11999             } else {
12000                 /*
12001                 * The object was lost in the evaluation machinery.
12002                 * Can this happen? Maybe in case of internal-errors.
12003                 */
12004                 contextObj = NULL;
12005             }
12006         }
12007         goto evaluation_exit;
12008
12009 evaluation_error:
12010         xmlXPathNodeSetClear(set, hasNsNodes);
12011         newContextSize = 0;
12012
12013 evaluation_exit:
12014         if (contextObj != NULL) {
12015             if (ctxt->value == contextObj)
12016                 valuePop(ctxt);
12017             xmlXPathReleaseObject(xpctxt, contextObj);
12018         }
12019         if (exprRes != NULL)
12020             xmlXPathReleaseObject(ctxt->context, exprRes);
12021         /*
12022         * Reset/invalidate the context.
12023         */
12024         xpctxt->node = oldContextNode;
12025         xpctxt->doc = oldContextDoc;
12026         xpctxt->contextSize = -1;
12027         xpctxt->proximityPosition = -1;
12028         return(newContextSize);
12029     }
12030     return(contextSize);
12031 }
12032
12033 static int
12034 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12035                             xmlXPathStepOpPtr op,
12036                             int *maxPos)
12037 {
12038
12039     xmlXPathStepOpPtr exprOp;
12040
12041     /*
12042     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12043     */
12044
12045     /*
12046     * If not -1, then ch1 will point to:
12047     * 1) For predicates (XPATH_OP_PREDICATE):
12048     *    - an inner predicate operator
12049     * 2) For filters (XPATH_OP_FILTER):
12050     *    - an inner filter operater OR
12051     *    - an expression selecting the node set.
12052     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
12053     */
12054     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12055         return(0);
12056
12057     if (op->ch2 != -1) {
12058         exprOp = &ctxt->comp->steps[op->ch2];
12059     } else
12060         return(0);
12061
12062     if ((exprOp != NULL) &&
12063         (exprOp->op == XPATH_OP_VALUE) &&
12064         (exprOp->value4 != NULL) &&
12065         (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12066     {
12067         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12068
12069         /*
12070         * We have a "[n]" predicate here.
12071         * TODO: Unfortunately this simplistic test here is not
12072         * able to detect a position() predicate in compound
12073         * expressions like "[@attr = 'a" and position() = 1],
12074         * and even not the usage of position() in
12075         * "[position() = 1]"; thus - obviously - a position-range,
12076         * like it "[position() < 5]", is also not detected.
12077         * Maybe we could rewrite the AST to ease the optimization.
12078         */
12079
12080         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12081             *maxPos = (int) floatval;
12082             if (floatval == (double) *maxPos)
12083                 return(1);
12084         }
12085     }
12086     return(0);
12087 }
12088
12089 static int
12090 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12091                            xmlXPathStepOpPtr op,
12092                            xmlNodePtr * first, xmlNodePtr * last,
12093                            int toBool)
12094 {
12095
12096 #define XP_TEST_HIT \
12097     if (hasAxisRange != 0) { \
12098         if (++pos == maxPos) { \
12099             if (addNode(seq, cur) < 0) \
12100                 ctxt->error = XPATH_MEMORY_ERROR; \
12101             goto axis_range_end; } \
12102     } else { \
12103         if (addNode(seq, cur) < 0) \
12104             ctxt->error = XPATH_MEMORY_ERROR; \
12105         if (breakOnFirstHit) goto first_hit; }
12106
12107 #define XP_TEST_HIT_NS \
12108     if (hasAxisRange != 0) { \
12109         if (++pos == maxPos) { \
12110             hasNsNodes = 1; \
12111             if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12112                 ctxt->error = XPATH_MEMORY_ERROR; \
12113         goto axis_range_end; } \
12114     } else { \
12115         hasNsNodes = 1; \
12116         if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12117             ctxt->error = XPATH_MEMORY_ERROR; \
12118         if (breakOnFirstHit) goto first_hit; }
12119
12120     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12121     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12122     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12123     const xmlChar *prefix = op->value4;
12124     const xmlChar *name = op->value5;
12125     const xmlChar *URI = NULL;
12126
12127 #ifdef DEBUG_STEP
12128     int nbMatches = 0, prevMatches = 0;
12129 #endif
12130     int total = 0, hasNsNodes = 0;
12131     /* The popped object holding the context nodes */
12132     xmlXPathObjectPtr obj;
12133     /* The set of context nodes for the node tests */
12134     xmlNodeSetPtr contextSeq;
12135     int contextIdx;
12136     xmlNodePtr contextNode;
12137     /* The final resulting node set wrt to all context nodes */
12138     xmlNodeSetPtr outSeq;
12139     /*
12140     * The temporary resulting node set wrt 1 context node.
12141     * Used to feed predicate evaluation.
12142     */
12143     xmlNodeSetPtr seq;
12144     xmlNodePtr cur;
12145     /* First predicate operator */
12146     xmlXPathStepOpPtr predOp;
12147     int maxPos; /* The requested position() (when a "[n]" predicate) */
12148     int hasPredicateRange, hasAxisRange, pos, size, newSize;
12149     int breakOnFirstHit;
12150
12151     xmlXPathTraversalFunction next = NULL;
12152     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12153     xmlXPathNodeSetMergeFunction mergeAndClear;
12154     xmlNodePtr oldContextNode;
12155     xmlXPathContextPtr xpctxt = ctxt->context;
12156
12157
12158     CHECK_TYPE0(XPATH_NODESET);
12159     obj = valuePop(ctxt);
12160     /*
12161     * Setup namespaces.
12162     */
12163     if (prefix != NULL) {
12164         URI = xmlXPathNsLookup(xpctxt, prefix);
12165         if (URI == NULL) {
12166             xmlXPathReleaseObject(xpctxt, obj);
12167             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12168         }
12169     }
12170     /*
12171     * Setup axis.
12172     *
12173     * MAYBE FUTURE TODO: merging optimizations:
12174     * - If the nodes to be traversed wrt to the initial nodes and
12175     *   the current axis cannot overlap, then we could avoid searching
12176     *   for duplicates during the merge.
12177     *   But the question is how/when to evaluate if they cannot overlap.
12178     *   Example: if we know that for two initial nodes, the one is
12179     *   not in the ancestor-or-self axis of the other, then we could safely
12180     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12181     *   the descendant-or-self axis.
12182     */
12183     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12184     switch (axis) {
12185         case AXIS_ANCESTOR:
12186             first = NULL;
12187             next = xmlXPathNextAncestor;
12188             break;
12189         case AXIS_ANCESTOR_OR_SELF:
12190             first = NULL;
12191             next = xmlXPathNextAncestorOrSelf;
12192             break;
12193         case AXIS_ATTRIBUTE:
12194             first = NULL;
12195             last = NULL;
12196             next = xmlXPathNextAttribute;
12197             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12198             break;
12199         case AXIS_CHILD:
12200             last = NULL;
12201             if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12202                 (type == NODE_TYPE_NODE))
12203             {
12204                 /*
12205                 * Optimization if an element node type is 'element'.
12206                 */
12207                 next = xmlXPathNextChildElement;
12208             } else
12209                 next = xmlXPathNextChild;
12210             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12211             break;
12212         case AXIS_DESCENDANT:
12213             last = NULL;
12214             next = xmlXPathNextDescendant;
12215             break;
12216         case AXIS_DESCENDANT_OR_SELF:
12217             last = NULL;
12218             next = xmlXPathNextDescendantOrSelf;
12219             break;
12220         case AXIS_FOLLOWING:
12221             last = NULL;
12222             next = xmlXPathNextFollowing;
12223             break;
12224         case AXIS_FOLLOWING_SIBLING:
12225             last = NULL;
12226             next = xmlXPathNextFollowingSibling;
12227             break;
12228         case AXIS_NAMESPACE:
12229             first = NULL;
12230             last = NULL;
12231             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12232             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12233             break;
12234         case AXIS_PARENT:
12235             first = NULL;
12236             next = xmlXPathNextParent;
12237             break;
12238         case AXIS_PRECEDING:
12239             first = NULL;
12240             next = xmlXPathNextPrecedingInternal;
12241             break;
12242         case AXIS_PRECEDING_SIBLING:
12243             first = NULL;
12244             next = xmlXPathNextPrecedingSibling;
12245             break;
12246         case AXIS_SELF:
12247             first = NULL;
12248             last = NULL;
12249             next = xmlXPathNextSelf;
12250             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12251             break;
12252     }
12253
12254 #ifdef DEBUG_STEP
12255     xmlXPathDebugDumpStepAxis(op,
12256         (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12257 #endif
12258
12259     if (next == NULL) {
12260         xmlXPathReleaseObject(xpctxt, obj);
12261         return(0);
12262     }
12263     contextSeq = obj->nodesetval;
12264     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12265         xmlXPathReleaseObject(xpctxt, obj);
12266         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12267         return(0);
12268     }
12269     /*
12270     * Predicate optimization ---------------------------------------------
12271     * If this step has a last predicate, which contains a position(),
12272     * then we'll optimize (although not exactly "position()", but only
12273     * the  short-hand form, i.e., "[n]".
12274     *
12275     * Example - expression "/foo[parent::bar][1]":
12276     *
12277     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12278     *   ROOT                               -- op->ch1
12279     *   PREDICATE                          -- op->ch2 (predOp)
12280     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12281     *       SORT
12282     *         COLLECT  'parent' 'name' 'node' bar
12283     *           NODE
12284     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12285     *
12286     */
12287     maxPos = 0;
12288     predOp = NULL;
12289     hasPredicateRange = 0;
12290     hasAxisRange = 0;
12291     if (op->ch2 != -1) {
12292         /*
12293         * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12294         */
12295         predOp = &ctxt->comp->steps[op->ch2];
12296         if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12297             if (predOp->ch1 != -1) {
12298                 /*
12299                 * Use the next inner predicate operator.
12300                 */
12301                 predOp = &ctxt->comp->steps[predOp->ch1];
12302                 hasPredicateRange = 1;
12303             } else {
12304                 /*
12305                 * There's no other predicate than the [n] predicate.
12306                 */
12307                 predOp = NULL;
12308                 hasAxisRange = 1;
12309             }
12310         }
12311     }
12312     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12313     /*
12314     * Axis traversal -----------------------------------------------------
12315     */
12316     /*
12317      * 2.3 Node Tests
12318      *  - For the attribute axis, the principal node type is attribute.
12319      *  - For the namespace axis, the principal node type is namespace.
12320      *  - For other axes, the principal node type is element.
12321      *
12322      * A node test * is true for any node of the
12323      * principal node type. For example, child::* will
12324      * select all element children of the context node
12325      */
12326     oldContextNode = xpctxt->node;
12327     addNode = xmlXPathNodeSetAddUnique;
12328     outSeq = NULL;
12329     seq = NULL;
12330     contextNode = NULL;
12331     contextIdx = 0;
12332
12333
12334     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12335            (ctxt->error == XPATH_EXPRESSION_OK)) {
12336         xpctxt->node = contextSeq->nodeTab[contextIdx++];
12337
12338         if (seq == NULL) {
12339             seq = xmlXPathNodeSetCreate(NULL);
12340             if (seq == NULL) {
12341                 total = 0;
12342                 goto error;
12343             }
12344         }
12345         /*
12346         * Traverse the axis and test the nodes.
12347         */
12348         pos = 0;
12349         cur = NULL;
12350         hasNsNodes = 0;
12351         do {
12352             cur = next(ctxt, cur);
12353             if (cur == NULL)
12354                 break;
12355
12356             /*
12357             * QUESTION TODO: What does the "first" and "last" stuff do?
12358             */
12359             if ((first != NULL) && (*first != NULL)) {
12360                 if (*first == cur)
12361                     break;
12362                 if (((total % 256) == 0) &&
12363 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12364                     (xmlXPathCmpNodesExt(*first, cur) >= 0))
12365 #else
12366                     (xmlXPathCmpNodes(*first, cur) >= 0))
12367 #endif
12368                 {
12369                     break;
12370                 }
12371             }
12372             if ((last != NULL) && (*last != NULL)) {
12373                 if (*last == cur)
12374                     break;
12375                 if (((total % 256) == 0) &&
12376 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12377                     (xmlXPathCmpNodesExt(cur, *last) >= 0))
12378 #else
12379                     (xmlXPathCmpNodes(cur, *last) >= 0))
12380 #endif
12381                 {
12382                     break;
12383                 }
12384             }
12385
12386             total++;
12387
12388 #ifdef DEBUG_STEP
12389             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12390 #endif
12391
12392             switch (test) {
12393                 case NODE_TEST_NONE:
12394                     total = 0;
12395                     STRANGE
12396                     goto error;
12397                 case NODE_TEST_TYPE:
12398                     if (type == NODE_TYPE_NODE) {
12399                         switch (cur->type) {
12400                             case XML_DOCUMENT_NODE:
12401                             case XML_HTML_DOCUMENT_NODE:
12402 #ifdef LIBXML_DOCB_ENABLED
12403                             case XML_DOCB_DOCUMENT_NODE:
12404 #endif
12405                             case XML_ELEMENT_NODE:
12406                             case XML_ATTRIBUTE_NODE:
12407                             case XML_PI_NODE:
12408                             case XML_COMMENT_NODE:
12409                             case XML_CDATA_SECTION_NODE:
12410                             case XML_TEXT_NODE:
12411                                 XP_TEST_HIT
12412                                 break;
12413                             case XML_NAMESPACE_DECL: {
12414                                 if (axis == AXIS_NAMESPACE) {
12415                                     XP_TEST_HIT_NS
12416                                 } else {
12417                                     hasNsNodes = 1;
12418                                     XP_TEST_HIT
12419                                 }
12420                                 break;
12421                             }
12422                             default:
12423                                 break;
12424                         }
12425                     } else if (cur->type == type) {
12426                         if (cur->type == XML_NAMESPACE_DECL)
12427                             XP_TEST_HIT_NS
12428                         else
12429                             XP_TEST_HIT
12430                     } else if ((type == NODE_TYPE_TEXT) &&
12431                          (cur->type == XML_CDATA_SECTION_NODE))
12432                     {
12433                         XP_TEST_HIT
12434                     }
12435                     break;
12436                 case NODE_TEST_PI:
12437                     if ((cur->type == XML_PI_NODE) &&
12438                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12439                     {
12440                         XP_TEST_HIT
12441                     }
12442                     break;
12443                 case NODE_TEST_ALL:
12444                     if (axis == AXIS_ATTRIBUTE) {
12445                         if (cur->type == XML_ATTRIBUTE_NODE)
12446                         {
12447                             if (prefix == NULL)
12448                             {
12449                                 XP_TEST_HIT
12450                             } else if ((cur->ns != NULL) &&
12451                                 (xmlStrEqual(URI, cur->ns->href)))
12452                             {
12453                                 XP_TEST_HIT
12454                             }
12455                         }
12456                     } else if (axis == AXIS_NAMESPACE) {
12457                         if (cur->type == XML_NAMESPACE_DECL)
12458                         {
12459                             XP_TEST_HIT_NS
12460                         }
12461                     } else {
12462                         if (cur->type == XML_ELEMENT_NODE) {
12463                             if (prefix == NULL)
12464                             {
12465                                 XP_TEST_HIT
12466
12467                             } else if ((cur->ns != NULL) &&
12468                                 (xmlStrEqual(URI, cur->ns->href)))
12469                             {
12470                                 XP_TEST_HIT
12471                             }
12472                         }
12473                     }
12474                     break;
12475                 case NODE_TEST_NS:{
12476                         TODO;
12477                         break;
12478                     }
12479                 case NODE_TEST_NAME:
12480                     if (axis == AXIS_ATTRIBUTE) {
12481                         if (cur->type != XML_ATTRIBUTE_NODE)
12482                             break;
12483                     } else if (axis == AXIS_NAMESPACE) {
12484                         if (cur->type != XML_NAMESPACE_DECL)
12485                             break;
12486                     } else {
12487                         if (cur->type != XML_ELEMENT_NODE)
12488                             break;
12489                     }
12490                     switch (cur->type) {
12491                         case XML_ELEMENT_NODE:
12492                             if (xmlStrEqual(name, cur->name)) {
12493                                 if (prefix == NULL) {
12494                                     if (cur->ns == NULL)
12495                                     {
12496                                         XP_TEST_HIT
12497                                     }
12498                                 } else {
12499                                     if ((cur->ns != NULL) &&
12500                                         (xmlStrEqual(URI, cur->ns->href)))
12501                                     {
12502                                         XP_TEST_HIT
12503                                     }
12504                                 }
12505                             }
12506                             break;
12507                         case XML_ATTRIBUTE_NODE:{
12508                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12509
12510                                 if (xmlStrEqual(name, attr->name)) {
12511                                     if (prefix == NULL) {
12512                                         if ((attr->ns == NULL) ||
12513                                             (attr->ns->prefix == NULL))
12514                                         {
12515                                             XP_TEST_HIT
12516                                         }
12517                                     } else {
12518                                         if ((attr->ns != NULL) &&
12519                                             (xmlStrEqual(URI,
12520                                               attr->ns->href)))
12521                                         {
12522                                             XP_TEST_HIT
12523                                         }
12524                                     }
12525                                 }
12526                                 break;
12527                             }
12528                         case XML_NAMESPACE_DECL:
12529                             if (cur->type == XML_NAMESPACE_DECL) {
12530                                 xmlNsPtr ns = (xmlNsPtr) cur;
12531
12532                                 if ((ns->prefix != NULL) && (name != NULL)
12533                                     && (xmlStrEqual(ns->prefix, name)))
12534                                 {
12535                                     XP_TEST_HIT_NS
12536                                 }
12537                             }
12538                             break;
12539                         default:
12540                             break;
12541                     }
12542                     break;
12543             } /* switch(test) */
12544         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12545
12546         goto apply_predicates;
12547
12548 axis_range_end: /* ----------------------------------------------------- */
12549         /*
12550         * We have a "/foo[n]", and position() = n was reached.
12551         * Note that we can have as well "/foo/::parent::foo[1]", so
12552         * a duplicate-aware merge is still needed.
12553         * Merge with the result.
12554         */
12555         if (outSeq == NULL) {
12556             outSeq = seq;
12557             seq = NULL;
12558         } else
12559             outSeq = mergeAndClear(outSeq, seq, 0);
12560         /*
12561         * Break if only a true/false result was requested.
12562         */
12563         if (toBool)
12564             break;
12565         continue;
12566
12567 first_hit: /* ---------------------------------------------------------- */
12568         /*
12569         * Break if only a true/false result was requested and
12570         * no predicates existed and a node test succeeded.
12571         */
12572         if (outSeq == NULL) {
12573             outSeq = seq;
12574             seq = NULL;
12575         } else
12576             outSeq = mergeAndClear(outSeq, seq, 0);
12577         break;
12578
12579 #ifdef DEBUG_STEP
12580         if (seq != NULL)
12581             nbMatches += seq->nodeNr;
12582 #endif
12583
12584 apply_predicates: /* --------------------------------------------------- */
12585         if (ctxt->error != XPATH_EXPRESSION_OK)
12586             goto error;
12587
12588         /*
12589         * Apply predicates.
12590         */
12591         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12592             /*
12593             * E.g. when we have a "/foo[some expression][n]".
12594             */
12595             /*
12596             * QUESTION TODO: The old predicate evaluation took into
12597             *  account location-sets.
12598             *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12599             *  Do we expect such a set here?
12600             *  All what I learned now from the evaluation semantics
12601             *  does not indicate that a location-set will be processed
12602             *  here, so this looks OK.
12603             */
12604             /*
12605             * Iterate over all predicates, starting with the outermost
12606             * predicate.
12607             * TODO: Problem: we cannot execute the inner predicates first
12608             *  since we cannot go back *up* the operator tree!
12609             *  Options we have:
12610             *  1) Use of recursive functions (like is it currently done
12611             *     via xmlXPathCompOpEval())
12612             *  2) Add a predicate evaluation information stack to the
12613             *     context struct
12614             *  3) Change the way the operators are linked; we need a
12615             *     "parent" field on xmlXPathStepOp
12616             *
12617             * For the moment, I'll try to solve this with a recursive
12618             * function: xmlXPathCompOpEvalPredicate().
12619             */
12620             size = seq->nodeNr;
12621             if (hasPredicateRange != 0)
12622                 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12623                     predOp, seq, size, maxPos, maxPos, hasNsNodes);
12624             else
12625                 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12626                     predOp, seq, size, hasNsNodes);
12627
12628             if (ctxt->error != XPATH_EXPRESSION_OK) {
12629                 total = 0;
12630                 goto error;
12631             }
12632             /*
12633             * Add the filtered set of nodes to the result node set.
12634             */
12635             if (newSize == 0) {
12636                 /*
12637                 * The predicates filtered all nodes out.
12638                 */
12639                 xmlXPathNodeSetClear(seq, hasNsNodes);
12640             } else if (seq->nodeNr > 0) {
12641                 /*
12642                 * Add to result set.
12643                 */
12644                 if (outSeq == NULL) {
12645                     if (size != newSize) {
12646                         /*
12647                         * We need to merge and clear here, since
12648                         * the sequence will contained NULLed entries.
12649                         */
12650                         outSeq = mergeAndClear(NULL, seq, 1);
12651                     } else {
12652                         outSeq = seq;
12653                         seq = NULL;
12654                     }
12655                 } else
12656                     outSeq = mergeAndClear(outSeq, seq,
12657                         (size != newSize) ? 1: 0);
12658                 /*
12659                 * Break if only a true/false result was requested.
12660                 */
12661                 if (toBool)
12662                     break;
12663             }
12664         } else if (seq->nodeNr > 0) {
12665             /*
12666             * Add to result set.
12667             */
12668             if (outSeq == NULL) {
12669                 outSeq = seq;
12670                 seq = NULL;
12671             } else {
12672                 outSeq = mergeAndClear(outSeq, seq, 0);
12673             }
12674         }
12675     }
12676
12677 error:
12678     if ((obj->boolval) && (obj->user != NULL)) {
12679         /*
12680         * QUESTION TODO: What does this do and why?
12681         * TODO: Do we have to do this also for the "error"
12682         * cleanup further down?
12683         */
12684         ctxt->value->boolval = 1;
12685         ctxt->value->user = obj->user;
12686         obj->user = NULL;
12687         obj->boolval = 0;
12688     }
12689     xmlXPathReleaseObject(xpctxt, obj);
12690
12691     /*
12692     * Ensure we return at least an emtpy set.
12693     */
12694     if (outSeq == NULL) {
12695         if ((seq != NULL) && (seq->nodeNr == 0))
12696             outSeq = seq;
12697         else
12698             outSeq = xmlXPathNodeSetCreate(NULL);
12699         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12700     }
12701     if ((seq != NULL) && (seq != outSeq)) {
12702          xmlXPathFreeNodeSet(seq);
12703     }
12704     /*
12705     * Hand over the result. Better to push the set also in
12706     * case of errors.
12707     */
12708     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12709     /*
12710     * Reset the context node.
12711     */
12712     xpctxt->node = oldContextNode;
12713     /*
12714     * When traversing the namespace axis in "toBool" mode, it's
12715     * possible that tmpNsList wasn't freed.
12716     */
12717     if (xpctxt->tmpNsList != NULL) {
12718         xmlFree(xpctxt->tmpNsList);
12719         xpctxt->tmpNsList = NULL;
12720     }
12721
12722 #ifdef DEBUG_STEP
12723     xmlGenericError(xmlGenericErrorContext,
12724         "\nExamined %d nodes, found %d nodes at that step\n",
12725         total, nbMatches);
12726 #endif
12727
12728     return(total);
12729 }
12730
12731 static int
12732 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12733                               xmlXPathStepOpPtr op, xmlNodePtr * first);
12734
12735 /**
12736  * xmlXPathCompOpEvalFirst:
12737  * @ctxt:  the XPath parser context with the compiled expression
12738  * @op:  an XPath compiled operation
12739  * @first:  the first elem found so far
12740  *
12741  * Evaluate the Precompiled XPath operation searching only the first
12742  * element in document order
12743  *
12744  * Returns the number of examined objects.
12745  */
12746 static int
12747 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12748                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12749 {
12750     int total = 0, cur;
12751     xmlXPathCompExprPtr comp;
12752     xmlXPathObjectPtr arg1, arg2;
12753
12754     CHECK_ERROR0;
12755     comp = ctxt->comp;
12756     switch (op->op) {
12757         case XPATH_OP_END:
12758             return (0);
12759         case XPATH_OP_UNION:
12760             total =
12761                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12762                                         first);
12763             CHECK_ERROR0;
12764             if ((ctxt->value != NULL)
12765                 && (ctxt->value->type == XPATH_NODESET)
12766                 && (ctxt->value->nodesetval != NULL)
12767                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12768                 /*
12769                  * limit tree traversing to first node in the result
12770                  */
12771                 /*
12772                 * OPTIMIZE TODO: This implicitely sorts
12773                 *  the result, even if not needed. E.g. if the argument
12774                 *  of the count() function, no sorting is needed.
12775                 * OPTIMIZE TODO: How do we know if the node-list wasn't
12776                 *  aready sorted?
12777                 */
12778                 if (ctxt->value->nodesetval->nodeNr > 1)
12779                     xmlXPathNodeSetSort(ctxt->value->nodesetval);
12780                 *first = ctxt->value->nodesetval->nodeTab[0];
12781             }
12782             cur =
12783                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12784                                         first);
12785             CHECK_ERROR0;
12786
12787             arg2 = valuePop(ctxt);
12788             arg1 = valuePop(ctxt);
12789             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12790                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12791                 xmlXPathReleaseObject(ctxt->context, arg1);
12792                 xmlXPathReleaseObject(ctxt->context, arg2);
12793                 XP_ERROR0(XPATH_INVALID_TYPE);
12794             }
12795
12796             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12797                                                     arg2->nodesetval);
12798             valuePush(ctxt, arg1);
12799             xmlXPathReleaseObject(ctxt->context, arg2);
12800             /* optimizer */
12801             if (total > cur)
12802                 xmlXPathCompSwap(op);
12803             return (total + cur);
12804         case XPATH_OP_ROOT:
12805             xmlXPathRoot(ctxt);
12806             return (0);
12807         case XPATH_OP_NODE:
12808             if (op->ch1 != -1)
12809                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12810             CHECK_ERROR0;
12811             if (op->ch2 != -1)
12812                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12813             CHECK_ERROR0;
12814             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12815                 ctxt->context->node));
12816             return (total);
12817         case XPATH_OP_RESET:
12818             if (op->ch1 != -1)
12819                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12820             CHECK_ERROR0;
12821             if (op->ch2 != -1)
12822                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12823             CHECK_ERROR0;
12824             ctxt->context->node = NULL;
12825             return (total);
12826         case XPATH_OP_COLLECT:{
12827                 if (op->ch1 == -1)
12828                     return (total);
12829
12830                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12831                 CHECK_ERROR0;
12832
12833                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12834                 return (total);
12835             }
12836         case XPATH_OP_VALUE:
12837             valuePush(ctxt,
12838                       xmlXPathCacheObjectCopy(ctxt->context,
12839                         (xmlXPathObjectPtr) op->value4));
12840             return (0);
12841         case XPATH_OP_SORT:
12842             if (op->ch1 != -1)
12843                 total +=
12844                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12845                                             first);
12846             CHECK_ERROR0;
12847             if ((ctxt->value != NULL)
12848                 && (ctxt->value->type == XPATH_NODESET)
12849                 && (ctxt->value->nodesetval != NULL)
12850                 && (ctxt->value->nodesetval->nodeNr > 1))
12851                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12852             return (total);
12853 #ifdef XP_OPTIMIZED_FILTER_FIRST
12854         case XPATH_OP_FILTER:
12855                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12856             return (total);
12857 #endif
12858         default:
12859             return (xmlXPathCompOpEval(ctxt, op));
12860     }
12861 }
12862
12863 /**
12864  * xmlXPathCompOpEvalLast:
12865  * @ctxt:  the XPath parser context with the compiled expression
12866  * @op:  an XPath compiled operation
12867  * @last:  the last elem found so far
12868  *
12869  * Evaluate the Precompiled XPath operation searching only the last
12870  * element in document order
12871  *
12872  * Returns the number of nodes traversed
12873  */
12874 static int
12875 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12876                        xmlNodePtr * last)
12877 {
12878     int total = 0, cur;
12879     xmlXPathCompExprPtr comp;
12880     xmlXPathObjectPtr arg1, arg2;
12881     xmlNodePtr bak;
12882     xmlDocPtr bakd;
12883     int pp;
12884     int cs;
12885
12886     CHECK_ERROR0;
12887     comp = ctxt->comp;
12888     switch (op->op) {
12889         case XPATH_OP_END:
12890             return (0);
12891         case XPATH_OP_UNION:
12892             bakd = ctxt->context->doc;
12893             bak = ctxt->context->node;
12894             pp = ctxt->context->proximityPosition;
12895             cs = ctxt->context->contextSize;
12896             total =
12897                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12898             CHECK_ERROR0;
12899             if ((ctxt->value != NULL)
12900                 && (ctxt->value->type == XPATH_NODESET)
12901                 && (ctxt->value->nodesetval != NULL)
12902                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12903                 /*
12904                  * limit tree traversing to first node in the result
12905                  */
12906                 if (ctxt->value->nodesetval->nodeNr > 1)
12907                     xmlXPathNodeSetSort(ctxt->value->nodesetval);
12908                 *last =
12909                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12910                                                      nodesetval->nodeNr -
12911                                                      1];
12912             }
12913             ctxt->context->doc = bakd;
12914             ctxt->context->node = bak;
12915             ctxt->context->proximityPosition = pp;
12916             ctxt->context->contextSize = cs;
12917             cur =
12918                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12919             CHECK_ERROR0;
12920             if ((ctxt->value != NULL)
12921                 && (ctxt->value->type == XPATH_NODESET)
12922                 && (ctxt->value->nodesetval != NULL)
12923                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12924             }
12925
12926             arg2 = valuePop(ctxt);
12927             arg1 = valuePop(ctxt);
12928             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12929                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12930                 xmlXPathReleaseObject(ctxt->context, arg1);
12931                 xmlXPathReleaseObject(ctxt->context, arg2);
12932                 XP_ERROR0(XPATH_INVALID_TYPE);
12933             }
12934
12935             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12936                                                     arg2->nodesetval);
12937             valuePush(ctxt, arg1);
12938             xmlXPathReleaseObject(ctxt->context, arg2);
12939             /* optimizer */
12940             if (total > cur)
12941                 xmlXPathCompSwap(op);
12942             return (total + cur);
12943         case XPATH_OP_ROOT:
12944             xmlXPathRoot(ctxt);
12945             return (0);
12946         case XPATH_OP_NODE:
12947             if (op->ch1 != -1)
12948                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12949             CHECK_ERROR0;
12950             if (op->ch2 != -1)
12951                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12952             CHECK_ERROR0;
12953             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12954                 ctxt->context->node));
12955             return (total);
12956         case XPATH_OP_RESET:
12957             if (op->ch1 != -1)
12958                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12959             CHECK_ERROR0;
12960             if (op->ch2 != -1)
12961                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12962             CHECK_ERROR0;
12963             ctxt->context->node = NULL;
12964             return (total);
12965         case XPATH_OP_COLLECT:{
12966                 if (op->ch1 == -1)
12967                     return (0);
12968
12969                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12970                 CHECK_ERROR0;
12971
12972                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12973                 return (total);
12974             }
12975         case XPATH_OP_VALUE:
12976             valuePush(ctxt,
12977                       xmlXPathCacheObjectCopy(ctxt->context,
12978                         (xmlXPathObjectPtr) op->value4));
12979             return (0);
12980         case XPATH_OP_SORT:
12981             if (op->ch1 != -1)
12982                 total +=
12983                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12984                                            last);
12985             CHECK_ERROR0;
12986             if ((ctxt->value != NULL)
12987                 && (ctxt->value->type == XPATH_NODESET)
12988                 && (ctxt->value->nodesetval != NULL)
12989                 && (ctxt->value->nodesetval->nodeNr > 1))
12990                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12991             return (total);
12992         default:
12993             return (xmlXPathCompOpEval(ctxt, op));
12994     }
12995 }
12996
12997 #ifdef XP_OPTIMIZED_FILTER_FIRST
12998 static int
12999 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
13000                               xmlXPathStepOpPtr op, xmlNodePtr * first)
13001 {
13002     int total = 0;
13003     xmlXPathCompExprPtr comp;
13004     xmlXPathObjectPtr res;
13005     xmlXPathObjectPtr obj;
13006     xmlNodeSetPtr oldset;
13007     xmlNodePtr oldnode;
13008     xmlDocPtr oldDoc;
13009     int i;
13010
13011     CHECK_ERROR0;
13012     comp = ctxt->comp;
13013     /*
13014     * Optimization for ()[last()] selection i.e. the last elem
13015     */
13016     if ((op->ch1 != -1) && (op->ch2 != -1) &&
13017         (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13018         (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13019         int f = comp->steps[op->ch2].ch1;
13020
13021         if ((f != -1) &&
13022             (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13023             (comp->steps[f].value5 == NULL) &&
13024             (comp->steps[f].value == 0) &&
13025             (comp->steps[f].value4 != NULL) &&
13026             (xmlStrEqual
13027             (comp->steps[f].value4, BAD_CAST "last"))) {
13028             xmlNodePtr last = NULL;
13029
13030             total +=
13031                 xmlXPathCompOpEvalLast(ctxt,
13032                     &comp->steps[op->ch1],
13033                     &last);
13034             CHECK_ERROR0;
13035             /*
13036             * The nodeset should be in document order,
13037             * Keep only the last value
13038             */
13039             if ((ctxt->value != NULL) &&
13040                 (ctxt->value->type == XPATH_NODESET) &&
13041                 (ctxt->value->nodesetval != NULL) &&
13042                 (ctxt->value->nodesetval->nodeTab != NULL) &&
13043                 (ctxt->value->nodesetval->nodeNr > 1)) {
13044                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13045                 *first = *(ctxt->value->nodesetval->nodeTab);
13046             }
13047             return (total);
13048         }
13049     }
13050
13051     if (op->ch1 != -1)
13052         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13053     CHECK_ERROR0;
13054     if (op->ch2 == -1)
13055         return (total);
13056     if (ctxt->value == NULL)
13057         return (total);
13058
13059 #ifdef LIBXML_XPTR_ENABLED
13060     oldnode = ctxt->context->node;
13061     /*
13062     * Hum are we filtering the result of an XPointer expression
13063     */
13064     if (ctxt->value->type == XPATH_LOCATIONSET) {
13065         xmlXPathObjectPtr tmp = NULL;
13066         xmlLocationSetPtr newlocset = NULL;
13067         xmlLocationSetPtr oldlocset;
13068
13069         /*
13070         * Extract the old locset, and then evaluate the result of the
13071         * expression for all the element in the locset. use it to grow
13072         * up a new locset.
13073         */
13074         CHECK_TYPE0(XPATH_LOCATIONSET);
13075         obj = valuePop(ctxt);
13076         oldlocset = obj->user;
13077         ctxt->context->node = NULL;
13078
13079         if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13080             ctxt->context->contextSize = 0;
13081             ctxt->context->proximityPosition = 0;
13082             if (op->ch2 != -1)
13083                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13084             res = valuePop(ctxt);
13085             if (res != NULL) {
13086                 xmlXPathReleaseObject(ctxt->context, res);
13087             }
13088             valuePush(ctxt, obj);
13089             CHECK_ERROR0;
13090             return (total);
13091         }
13092         newlocset = xmlXPtrLocationSetCreate(NULL);
13093
13094         for (i = 0; i < oldlocset->locNr; i++) {
13095             /*
13096             * Run the evaluation with a node list made of a
13097             * single item in the nodelocset.
13098             */
13099             ctxt->context->node = oldlocset->locTab[i]->user;
13100             ctxt->context->contextSize = oldlocset->locNr;
13101             ctxt->context->proximityPosition = i + 1;
13102             if (tmp == NULL) {
13103                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13104                     ctxt->context->node);
13105             } else {
13106                 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13107                                              ctxt->context->node) < 0) {
13108                     ctxt->error = XPATH_MEMORY_ERROR;
13109                 }
13110             }
13111             valuePush(ctxt, tmp);
13112             if (op->ch2 != -1)
13113                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13114             if (ctxt->error != XPATH_EXPRESSION_OK) {
13115                 xmlXPathFreeObject(obj);
13116                 return(0);
13117             }
13118             /*
13119             * The result of the evaluation need to be tested to
13120             * decided whether the filter succeeded or not
13121             */
13122             res = valuePop(ctxt);
13123             if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13124                 xmlXPtrLocationSetAdd(newlocset,
13125                     xmlXPathCacheObjectCopy(ctxt->context,
13126                         oldlocset->locTab[i]));
13127             }
13128             /*
13129             * Cleanup
13130             */
13131             if (res != NULL) {
13132                 xmlXPathReleaseObject(ctxt->context, res);
13133             }
13134             if (ctxt->value == tmp) {
13135                 valuePop(ctxt);
13136                 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13137                 /*
13138                 * REVISIT TODO: Don't create a temporary nodeset
13139                 * for everly iteration.
13140                 */
13141                 /* OLD: xmlXPathFreeObject(res); */
13142             } else
13143                 tmp = NULL;
13144             ctxt->context->node = NULL;
13145             /*
13146             * Only put the first node in the result, then leave.
13147             */
13148             if (newlocset->locNr > 0) {
13149                 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13150                 break;
13151             }
13152         }
13153         if (tmp != NULL) {
13154             xmlXPathReleaseObject(ctxt->context, tmp);
13155         }
13156         /*
13157         * The result is used as the new evaluation locset.
13158         */
13159         xmlXPathReleaseObject(ctxt->context, obj);
13160         ctxt->context->node = NULL;
13161         ctxt->context->contextSize = -1;
13162         ctxt->context->proximityPosition = -1;
13163         valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13164         ctxt->context->node = oldnode;
13165         return (total);
13166     }
13167 #endif /* LIBXML_XPTR_ENABLED */
13168
13169     /*
13170     * Extract the old set, and then evaluate the result of the
13171     * expression for all the element in the set. use it to grow
13172     * up a new set.
13173     */
13174     CHECK_TYPE0(XPATH_NODESET);
13175     obj = valuePop(ctxt);
13176     oldset = obj->nodesetval;
13177
13178     oldnode = ctxt->context->node;
13179     oldDoc = ctxt->context->doc;
13180     ctxt->context->node = NULL;
13181
13182     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13183         ctxt->context->contextSize = 0;
13184         ctxt->context->proximityPosition = 0;
13185         /* QUESTION TODO: Why was this code commented out?
13186             if (op->ch2 != -1)
13187                 total +=
13188                     xmlXPathCompOpEval(ctxt,
13189                         &comp->steps[op->ch2]);
13190             CHECK_ERROR0;
13191             res = valuePop(ctxt);
13192             if (res != NULL)
13193                 xmlXPathFreeObject(res);
13194         */
13195         valuePush(ctxt, obj);
13196         ctxt->context->node = oldnode;
13197         CHECK_ERROR0;
13198     } else {
13199         xmlNodeSetPtr newset;
13200         xmlXPathObjectPtr tmp = NULL;
13201         /*
13202         * Initialize the new set.
13203         * Also set the xpath document in case things like
13204         * key() evaluation are attempted on the predicate
13205         */
13206         newset = xmlXPathNodeSetCreate(NULL);
13207         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13208
13209         for (i = 0; i < oldset->nodeNr; i++) {
13210             /*
13211             * Run the evaluation with a node list made of
13212             * a single item in the nodeset.
13213             */
13214             ctxt->context->node = oldset->nodeTab[i];
13215             if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13216                 (oldset->nodeTab[i]->doc != NULL))
13217                 ctxt->context->doc = oldset->nodeTab[i]->doc;
13218             if (tmp == NULL) {
13219                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13220                     ctxt->context->node);
13221             } else {
13222                 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13223                                              ctxt->context->node) < 0) {
13224                     ctxt->error = XPATH_MEMORY_ERROR;
13225                 }
13226             }
13227             valuePush(ctxt, tmp);
13228             ctxt->context->contextSize = oldset->nodeNr;
13229             ctxt->context->proximityPosition = i + 1;
13230             if (op->ch2 != -1)
13231                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13232             if (ctxt->error != XPATH_EXPRESSION_OK) {
13233                 xmlXPathFreeNodeSet(newset);
13234                 xmlXPathFreeObject(obj);
13235                 return(0);
13236             }
13237             /*
13238             * The result of the evaluation needs to be tested to
13239             * decide whether the filter succeeded or not
13240             */
13241             res = valuePop(ctxt);
13242             if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13243                 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13244                     ctxt->error = XPATH_MEMORY_ERROR;
13245             }
13246             /*
13247             * Cleanup
13248             */
13249             if (res != NULL) {
13250                 xmlXPathReleaseObject(ctxt->context, res);
13251             }
13252             if (ctxt->value == tmp) {
13253                 valuePop(ctxt);
13254                 /*
13255                 * Don't free the temporary nodeset
13256                 * in order to avoid massive recreation inside this
13257                 * loop.
13258                 */
13259                 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13260             } else
13261                 tmp = NULL;
13262             ctxt->context->node = NULL;
13263             /*
13264             * Only put the first node in the result, then leave.
13265             */
13266             if (newset->nodeNr > 0) {
13267                 *first = *(newset->nodeTab);
13268                 break;
13269             }
13270         }
13271         if (tmp != NULL) {
13272             xmlXPathReleaseObject(ctxt->context, tmp);
13273         }
13274         /*
13275         * The result is used as the new evaluation set.
13276         */
13277         xmlXPathReleaseObject(ctxt->context, obj);
13278         ctxt->context->node = NULL;
13279         ctxt->context->contextSize = -1;
13280         ctxt->context->proximityPosition = -1;
13281         /* may want to move this past the '}' later */
13282         ctxt->context->doc = oldDoc;
13283         valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13284     }
13285     ctxt->context->node = oldnode;
13286     return(total);
13287 }
13288 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13289
13290 /**
13291  * xmlXPathCompOpEval:
13292  * @ctxt:  the XPath parser context with the compiled expression
13293  * @op:  an XPath compiled operation
13294  *
13295  * Evaluate the Precompiled XPath operation
13296  * Returns the number of nodes traversed
13297  */
13298 static int
13299 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13300 {
13301     int total = 0;
13302     int equal, ret;
13303     xmlXPathCompExprPtr comp;
13304     xmlXPathObjectPtr arg1, arg2;
13305     xmlNodePtr bak;
13306     xmlDocPtr bakd;
13307     int pp;
13308     int cs;
13309
13310     CHECK_ERROR0;
13311     comp = ctxt->comp;
13312     switch (op->op) {
13313         case XPATH_OP_END:
13314             return (0);
13315         case XPATH_OP_AND:
13316             bakd = ctxt->context->doc;
13317             bak = ctxt->context->node;
13318             pp = ctxt->context->proximityPosition;
13319             cs = ctxt->context->contextSize;
13320             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13321             CHECK_ERROR0;
13322             xmlXPathBooleanFunction(ctxt, 1);
13323             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13324                 return (total);
13325             arg2 = valuePop(ctxt);
13326             ctxt->context->doc = bakd;
13327             ctxt->context->node = bak;
13328             ctxt->context->proximityPosition = pp;
13329             ctxt->context->contextSize = cs;
13330             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13331             if (ctxt->error) {
13332                 xmlXPathFreeObject(arg2);
13333                 return(0);
13334             }
13335             xmlXPathBooleanFunction(ctxt, 1);
13336             arg1 = valuePop(ctxt);
13337             arg1->boolval &= arg2->boolval;
13338             valuePush(ctxt, arg1);
13339             xmlXPathReleaseObject(ctxt->context, arg2);
13340             return (total);
13341         case XPATH_OP_OR:
13342             bakd = ctxt->context->doc;
13343             bak = ctxt->context->node;
13344             pp = ctxt->context->proximityPosition;
13345             cs = ctxt->context->contextSize;
13346             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13347             CHECK_ERROR0;
13348             xmlXPathBooleanFunction(ctxt, 1);
13349             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13350                 return (total);
13351             arg2 = valuePop(ctxt);
13352             ctxt->context->doc = bakd;
13353             ctxt->context->node = bak;
13354             ctxt->context->proximityPosition = pp;
13355             ctxt->context->contextSize = cs;
13356             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13357             if (ctxt->error) {
13358                 xmlXPathFreeObject(arg2);
13359                 return(0);
13360             }
13361             xmlXPathBooleanFunction(ctxt, 1);
13362             arg1 = valuePop(ctxt);
13363             arg1->boolval |= arg2->boolval;
13364             valuePush(ctxt, arg1);
13365             xmlXPathReleaseObject(ctxt->context, arg2);
13366             return (total);
13367         case XPATH_OP_EQUAL:
13368             bakd = ctxt->context->doc;
13369             bak = ctxt->context->node;
13370             pp = ctxt->context->proximityPosition;
13371             cs = ctxt->context->contextSize;
13372             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13373             CHECK_ERROR0;
13374             ctxt->context->doc = bakd;
13375             ctxt->context->node = bak;
13376             ctxt->context->proximityPosition = pp;
13377             ctxt->context->contextSize = cs;
13378             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13379             CHECK_ERROR0;
13380             if (op->value)
13381                 equal = xmlXPathEqualValues(ctxt);
13382             else
13383                 equal = xmlXPathNotEqualValues(ctxt);
13384             valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13385             return (total);
13386         case XPATH_OP_CMP:
13387             bakd = ctxt->context->doc;
13388             bak = ctxt->context->node;
13389             pp = ctxt->context->proximityPosition;
13390             cs = ctxt->context->contextSize;
13391             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13392             CHECK_ERROR0;
13393             ctxt->context->doc = bakd;
13394             ctxt->context->node = bak;
13395             ctxt->context->proximityPosition = pp;
13396             ctxt->context->contextSize = cs;
13397             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13398             CHECK_ERROR0;
13399             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13400             valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13401             return (total);
13402         case XPATH_OP_PLUS:
13403             bakd = ctxt->context->doc;
13404             bak = ctxt->context->node;
13405             pp = ctxt->context->proximityPosition;
13406             cs = ctxt->context->contextSize;
13407             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13408             CHECK_ERROR0;
13409             if (op->ch2 != -1) {
13410                 ctxt->context->doc = bakd;
13411                 ctxt->context->node = bak;
13412                 ctxt->context->proximityPosition = pp;
13413                 ctxt->context->contextSize = cs;
13414                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13415             }
13416             CHECK_ERROR0;
13417             if (op->value == 0)
13418                 xmlXPathSubValues(ctxt);
13419             else if (op->value == 1)
13420                 xmlXPathAddValues(ctxt);
13421             else if (op->value == 2)
13422                 xmlXPathValueFlipSign(ctxt);
13423             else if (op->value == 3) {
13424                 CAST_TO_NUMBER;
13425                 CHECK_TYPE0(XPATH_NUMBER);
13426             }
13427             return (total);
13428         case XPATH_OP_MULT:
13429             bakd = ctxt->context->doc;
13430             bak = ctxt->context->node;
13431             pp = ctxt->context->proximityPosition;
13432             cs = ctxt->context->contextSize;
13433             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13434             CHECK_ERROR0;
13435             ctxt->context->doc = bakd;
13436             ctxt->context->node = bak;
13437             ctxt->context->proximityPosition = pp;
13438             ctxt->context->contextSize = cs;
13439             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13440             CHECK_ERROR0;
13441             if (op->value == 0)
13442                 xmlXPathMultValues(ctxt);
13443             else if (op->value == 1)
13444                 xmlXPathDivValues(ctxt);
13445             else if (op->value == 2)
13446                 xmlXPathModValues(ctxt);
13447             return (total);
13448         case XPATH_OP_UNION:
13449             bakd = ctxt->context->doc;
13450             bak = ctxt->context->node;
13451             pp = ctxt->context->proximityPosition;
13452             cs = ctxt->context->contextSize;
13453             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13454             CHECK_ERROR0;
13455             ctxt->context->doc = bakd;
13456             ctxt->context->node = bak;
13457             ctxt->context->proximityPosition = pp;
13458             ctxt->context->contextSize = cs;
13459             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13460             CHECK_ERROR0;
13461
13462             arg2 = valuePop(ctxt);
13463             arg1 = valuePop(ctxt);
13464             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13465                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13466                 xmlXPathReleaseObject(ctxt->context, arg1);
13467                 xmlXPathReleaseObject(ctxt->context, arg2);
13468                 XP_ERROR0(XPATH_INVALID_TYPE);
13469             }
13470
13471             if ((arg1->nodesetval == NULL) ||
13472                 ((arg2->nodesetval != NULL) &&
13473                  (arg2->nodesetval->nodeNr != 0)))
13474             {
13475                 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13476                                                         arg2->nodesetval);
13477             }
13478
13479             valuePush(ctxt, arg1);
13480             xmlXPathReleaseObject(ctxt->context, arg2);
13481             return (total);
13482         case XPATH_OP_ROOT:
13483             xmlXPathRoot(ctxt);
13484             return (total);
13485         case XPATH_OP_NODE:
13486             if (op->ch1 != -1)
13487                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13488             CHECK_ERROR0;
13489             if (op->ch2 != -1)
13490                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13491             CHECK_ERROR0;
13492             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13493                 ctxt->context->node));
13494             return (total);
13495         case XPATH_OP_RESET:
13496             if (op->ch1 != -1)
13497                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13498             CHECK_ERROR0;
13499             if (op->ch2 != -1)
13500                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13501             CHECK_ERROR0;
13502             ctxt->context->node = NULL;
13503             return (total);
13504         case XPATH_OP_COLLECT:{
13505                 if (op->ch1 == -1)
13506                     return (total);
13507
13508                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13509                 CHECK_ERROR0;
13510
13511                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13512                 return (total);
13513             }
13514         case XPATH_OP_VALUE:
13515             valuePush(ctxt,
13516                       xmlXPathCacheObjectCopy(ctxt->context,
13517                         (xmlXPathObjectPtr) op->value4));
13518             return (total);
13519         case XPATH_OP_VARIABLE:{
13520                 xmlXPathObjectPtr val;
13521
13522                 if (op->ch1 != -1)
13523                     total +=
13524                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13525                 if (op->value5 == NULL) {
13526                     val = xmlXPathVariableLookup(ctxt->context, op->value4);
13527                     if (val == NULL) {
13528                         ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13529                         return(0);
13530                     }
13531                     valuePush(ctxt, val);
13532                 } else {
13533                     const xmlChar *URI;
13534
13535                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13536                     if (URI == NULL) {
13537                         xmlGenericError(xmlGenericErrorContext,
13538             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13539                                     (char *) op->value4, (char *)op->value5);
13540                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13541                         return (total);
13542                     }
13543                     val = xmlXPathVariableLookupNS(ctxt->context,
13544                                                        op->value4, URI);
13545                     if (val == NULL) {
13546                         ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13547                         return(0);
13548                     }
13549                     valuePush(ctxt, val);
13550                 }
13551                 return (total);
13552             }
13553         case XPATH_OP_FUNCTION:{
13554                 xmlXPathFunction func;
13555                 const xmlChar *oldFunc, *oldFuncURI;
13556                 int i;
13557                 int frame;
13558
13559                 frame = xmlXPathSetFrame(ctxt);
13560                 if (op->ch1 != -1) {
13561                     total +=
13562                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13563                     if (ctxt->error != XPATH_EXPRESSION_OK) {
13564                         xmlXPathPopFrame(ctxt, frame);
13565                         return (total);
13566                     }
13567                 }
13568                 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13569                     xmlGenericError(xmlGenericErrorContext,
13570                             "xmlXPathCompOpEval: parameter error\n");
13571                     ctxt->error = XPATH_INVALID_OPERAND;
13572                     xmlXPathPopFrame(ctxt, frame);
13573                     return (total);
13574                 }
13575                 for (i = 0; i < op->value; i++) {
13576                     if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13577                         xmlGenericError(xmlGenericErrorContext,
13578                                 "xmlXPathCompOpEval: parameter error\n");
13579                         ctxt->error = XPATH_INVALID_OPERAND;
13580                         xmlXPathPopFrame(ctxt, frame);
13581                         return (total);
13582                     }
13583                 }
13584                 if (op->cache != NULL)
13585                     func = op->cache;
13586                 else {
13587                     const xmlChar *URI = NULL;
13588
13589                     if (op->value5 == NULL)
13590                         func =
13591                             xmlXPathFunctionLookup(ctxt->context,
13592                                                    op->value4);
13593                     else {
13594                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13595                         if (URI == NULL) {
13596                             xmlGenericError(xmlGenericErrorContext,
13597             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13598                                     (char *)op->value4, (char *)op->value5);
13599                             xmlXPathPopFrame(ctxt, frame);
13600                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13601                             return (total);
13602                         }
13603                         func = xmlXPathFunctionLookupNS(ctxt->context,
13604                                                         op->value4, URI);
13605                     }
13606                     if (func == NULL) {
13607                         xmlGenericError(xmlGenericErrorContext,
13608                                 "xmlXPathCompOpEval: function %s not found\n",
13609                                         (char *)op->value4);
13610                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13611                     }
13612                     op->cache = func;
13613                     op->cacheURI = (void *) URI;
13614                 }
13615                 oldFunc = ctxt->context->function;
13616                 oldFuncURI = ctxt->context->functionURI;
13617                 ctxt->context->function = op->value4;
13618                 ctxt->context->functionURI = op->cacheURI;
13619                 func(ctxt, op->value);
13620                 ctxt->context->function = oldFunc;
13621                 ctxt->context->functionURI = oldFuncURI;
13622                 xmlXPathPopFrame(ctxt, frame);
13623                 return (total);
13624             }
13625         case XPATH_OP_ARG:
13626             bakd = ctxt->context->doc;
13627             bak = ctxt->context->node;
13628             pp = ctxt->context->proximityPosition;
13629             cs = ctxt->context->contextSize;
13630             if (op->ch1 != -1) {
13631                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13632                 ctxt->context->contextSize = cs;
13633                 ctxt->context->proximityPosition = pp;
13634                 ctxt->context->node = bak;
13635                 ctxt->context->doc = bakd;
13636                 CHECK_ERROR0;
13637             }
13638             if (op->ch2 != -1) {
13639                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13640                 ctxt->context->contextSize = cs;
13641                 ctxt->context->proximityPosition = pp;
13642                 ctxt->context->node = bak;
13643                 ctxt->context->doc = bakd;
13644                 CHECK_ERROR0;
13645             }
13646             return (total);
13647         case XPATH_OP_PREDICATE:
13648         case XPATH_OP_FILTER:{
13649                 xmlXPathObjectPtr res;
13650                 xmlXPathObjectPtr obj, tmp;
13651                 xmlNodeSetPtr newset = NULL;
13652                 xmlNodeSetPtr oldset;
13653                 xmlNodePtr oldnode;
13654                 xmlDocPtr oldDoc;
13655                 int i;
13656
13657                 /*
13658                  * Optimization for ()[1] selection i.e. the first elem
13659                  */
13660                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13661 #ifdef XP_OPTIMIZED_FILTER_FIRST
13662                     /*
13663                     * FILTER TODO: Can we assume that the inner processing
13664                     *  will result in an ordered list if we have an
13665                     *  XPATH_OP_FILTER?
13666                     *  What about an additional field or flag on
13667                     *  xmlXPathObject like @sorted ? This way we wouln'd need
13668                     *  to assume anything, so it would be more robust and
13669                     *  easier to optimize.
13670                     */
13671                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13672                      (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13673 #else
13674                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13675 #endif
13676                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13677                     xmlXPathObjectPtr val;
13678
13679                     val = comp->steps[op->ch2].value4;
13680                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13681                         (val->floatval == 1.0)) {
13682                         xmlNodePtr first = NULL;
13683
13684                         total +=
13685                             xmlXPathCompOpEvalFirst(ctxt,
13686                                                     &comp->steps[op->ch1],
13687                                                     &first);
13688                         CHECK_ERROR0;
13689                         /*
13690                          * The nodeset should be in document order,
13691                          * Keep only the first value
13692                          */
13693                         if ((ctxt->value != NULL) &&
13694                             (ctxt->value->type == XPATH_NODESET) &&
13695                             (ctxt->value->nodesetval != NULL) &&
13696                             (ctxt->value->nodesetval->nodeNr > 1))
13697                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13698                                                         1, 1);
13699                         return (total);
13700                     }
13701                 }
13702                 /*
13703                  * Optimization for ()[last()] selection i.e. the last elem
13704                  */
13705                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13706                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13707                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13708                     int f = comp->steps[op->ch2].ch1;
13709
13710                     if ((f != -1) &&
13711                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13712                         (comp->steps[f].value5 == NULL) &&
13713                         (comp->steps[f].value == 0) &&
13714                         (comp->steps[f].value4 != NULL) &&
13715                         (xmlStrEqual
13716                          (comp->steps[f].value4, BAD_CAST "last"))) {
13717                         xmlNodePtr last = NULL;
13718
13719                         total +=
13720                             xmlXPathCompOpEvalLast(ctxt,
13721                                                    &comp->steps[op->ch1],
13722                                                    &last);
13723                         CHECK_ERROR0;
13724                         /*
13725                          * The nodeset should be in document order,
13726                          * Keep only the last value
13727                          */
13728                         if ((ctxt->value != NULL) &&
13729                             (ctxt->value->type == XPATH_NODESET) &&
13730                             (ctxt->value->nodesetval != NULL) &&
13731                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13732                             (ctxt->value->nodesetval->nodeNr > 1))
13733                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13734                         return (total);
13735                     }
13736                 }
13737                 /*
13738                 * Process inner predicates first.
13739                 * Example "index[parent::book][1]":
13740                 * ...
13741                 *   PREDICATE   <-- we are here "[1]"
13742                 *     PREDICATE <-- process "[parent::book]" first
13743                 *       SORT
13744                 *         COLLECT  'parent' 'name' 'node' book
13745                 *           NODE
13746                 *     ELEM Object is a number : 1
13747                 */
13748                 if (op->ch1 != -1)
13749                     total +=
13750                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13751                 CHECK_ERROR0;
13752                 if (op->ch2 == -1)
13753                     return (total);
13754                 if (ctxt->value == NULL)
13755                     return (total);
13756
13757                 oldnode = ctxt->context->node;
13758
13759 #ifdef LIBXML_XPTR_ENABLED
13760                 /*
13761                  * Hum are we filtering the result of an XPointer expression
13762                  */
13763                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13764                     xmlLocationSetPtr newlocset = NULL;
13765                     xmlLocationSetPtr oldlocset;
13766
13767                     /*
13768                      * Extract the old locset, and then evaluate the result of the
13769                      * expression for all the element in the locset. use it to grow
13770                      * up a new locset.
13771                      */
13772                     CHECK_TYPE0(XPATH_LOCATIONSET);
13773                     obj = valuePop(ctxt);
13774                     oldlocset = obj->user;
13775                     ctxt->context->node = NULL;
13776
13777                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13778                         ctxt->context->contextSize = 0;
13779                         ctxt->context->proximityPosition = 0;
13780                         if (op->ch2 != -1)
13781                             total +=
13782                                 xmlXPathCompOpEval(ctxt,
13783                                                    &comp->steps[op->ch2]);
13784                         res = valuePop(ctxt);
13785                         if (res != NULL) {
13786                             xmlXPathReleaseObject(ctxt->context, res);
13787                         }
13788                         valuePush(ctxt, obj);
13789                         CHECK_ERROR0;
13790                         return (total);
13791                     }
13792                     newlocset = xmlXPtrLocationSetCreate(NULL);
13793
13794                     for (i = 0; i < oldlocset->locNr; i++) {
13795                         /*
13796                          * Run the evaluation with a node list made of a
13797                          * single item in the nodelocset.
13798                          */
13799                         ctxt->context->node = oldlocset->locTab[i]->user;
13800                         ctxt->context->contextSize = oldlocset->locNr;
13801                         ctxt->context->proximityPosition = i + 1;
13802                         tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13803                             ctxt->context->node);
13804                         valuePush(ctxt, tmp);
13805
13806                         if (op->ch2 != -1)
13807                             total +=
13808                                 xmlXPathCompOpEval(ctxt,
13809                                                    &comp->steps[op->ch2]);
13810                         if (ctxt->error != XPATH_EXPRESSION_OK) {
13811                             xmlXPathFreeObject(obj);
13812                             return(0);
13813                         }
13814
13815                         /*
13816                          * The result of the evaluation need to be tested to
13817                          * decided whether the filter succeeded or not
13818                          */
13819                         res = valuePop(ctxt);
13820                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13821                             xmlXPtrLocationSetAdd(newlocset,
13822                                                   xmlXPathObjectCopy
13823                                                   (oldlocset->locTab[i]));
13824                         }
13825
13826                         /*
13827                          * Cleanup
13828                          */
13829                         if (res != NULL) {
13830                             xmlXPathReleaseObject(ctxt->context, res);
13831                         }
13832                         if (ctxt->value == tmp) {
13833                             res = valuePop(ctxt);
13834                             xmlXPathReleaseObject(ctxt->context, res);
13835                         }
13836
13837                         ctxt->context->node = NULL;
13838                     }
13839
13840                     /*
13841                      * The result is used as the new evaluation locset.
13842                      */
13843                     xmlXPathReleaseObject(ctxt->context, obj);
13844                     ctxt->context->node = NULL;
13845                     ctxt->context->contextSize = -1;
13846                     ctxt->context->proximityPosition = -1;
13847                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13848                     ctxt->context->node = oldnode;
13849                     return (total);
13850                 }
13851 #endif /* LIBXML_XPTR_ENABLED */
13852
13853                 /*
13854                  * Extract the old set, and then evaluate the result of the
13855                  * expression for all the element in the set. use it to grow
13856                  * up a new set.
13857                  */
13858                 CHECK_TYPE0(XPATH_NODESET);
13859                 obj = valuePop(ctxt);
13860                 oldset = obj->nodesetval;
13861
13862                 oldnode = ctxt->context->node;
13863                 oldDoc = ctxt->context->doc;
13864                 ctxt->context->node = NULL;
13865
13866                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13867                     ctxt->context->contextSize = 0;
13868                     ctxt->context->proximityPosition = 0;
13869 /*
13870                     if (op->ch2 != -1)
13871                         total +=
13872                             xmlXPathCompOpEval(ctxt,
13873                                                &comp->steps[op->ch2]);
13874                     CHECK_ERROR0;
13875                     res = valuePop(ctxt);
13876                     if (res != NULL)
13877                         xmlXPathFreeObject(res);
13878 */
13879                     valuePush(ctxt, obj);
13880                     ctxt->context->node = oldnode;
13881                     CHECK_ERROR0;
13882                 } else {
13883                     tmp = NULL;
13884                     /*
13885                      * Initialize the new set.
13886                      * Also set the xpath document in case things like
13887                      * key() evaluation are attempted on the predicate
13888                      */
13889                     newset = xmlXPathNodeSetCreate(NULL);
13890                     /*
13891                     * SPEC XPath 1.0:
13892                     *  "For each node in the node-set to be filtered, the
13893                     *  PredicateExpr is evaluated with that node as the
13894                     *  context node, with the number of nodes in the
13895                     *  node-set as the context size, and with the proximity
13896                     *  position of the node in the node-set with respect to
13897                     *  the axis as the context position;"
13898                     * @oldset is the node-set" to be filtered.
13899                     *
13900                     * SPEC XPath 1.0:
13901                     *  "only predicates change the context position and
13902                     *  context size (see [2.4 Predicates])."
13903                     * Example:
13904                     *   node-set  context pos
13905                     *    nA         1
13906                     *    nB         2
13907                     *    nC         3
13908                     *   After applying predicate [position() > 1] :
13909                     *   node-set  context pos
13910                     *    nB         1
13911                     *    nC         2
13912                     *
13913                     * removed the first node in the node-set, then
13914                     * the context position of the
13915                     */
13916                     for (i = 0; i < oldset->nodeNr; i++) {
13917                         /*
13918                          * Run the evaluation with a node list made of
13919                          * a single item in the nodeset.
13920                          */
13921                         ctxt->context->node = oldset->nodeTab[i];
13922                         if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13923                             (oldset->nodeTab[i]->doc != NULL))
13924                             ctxt->context->doc = oldset->nodeTab[i]->doc;
13925                         if (tmp == NULL) {
13926                             tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13927                                 ctxt->context->node);
13928                         } else {
13929                             if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13930                                                ctxt->context->node) < 0) {
13931                                 ctxt->error = XPATH_MEMORY_ERROR;
13932                             }
13933                         }
13934                         valuePush(ctxt, tmp);
13935                         ctxt->context->contextSize = oldset->nodeNr;
13936                         ctxt->context->proximityPosition = i + 1;
13937                         /*
13938                         * Evaluate the predicate against the context node.
13939                         * Can/should we optimize position() predicates
13940                         * here (e.g. "[1]")?
13941                         */
13942                         if (op->ch2 != -1)
13943                             total +=
13944                                 xmlXPathCompOpEval(ctxt,
13945                                                    &comp->steps[op->ch2]);
13946                         if (ctxt->error != XPATH_EXPRESSION_OK) {
13947                             xmlXPathFreeNodeSet(newset);
13948                             xmlXPathFreeObject(obj);
13949                             return(0);
13950                         }
13951
13952                         /*
13953                          * The result of the evaluation needs to be tested to
13954                          * decide whether the filter succeeded or not
13955                          */
13956                         /*
13957                         * OPTIMIZE TODO: Can we use
13958                         * xmlXPathNodeSetAdd*Unique()* instead?
13959                         */
13960                         res = valuePop(ctxt);
13961                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13962                             if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13963                                 < 0)
13964                                 ctxt->error = XPATH_MEMORY_ERROR;
13965                         }
13966
13967                         /*
13968                          * Cleanup
13969                          */
13970                         if (res != NULL) {
13971                             xmlXPathReleaseObject(ctxt->context, res);
13972                         }
13973                         if (ctxt->value == tmp) {
13974                             valuePop(ctxt);
13975                             xmlXPathNodeSetClear(tmp->nodesetval, 1);
13976                             /*
13977                             * Don't free the temporary nodeset
13978                             * in order to avoid massive recreation inside this
13979                             * loop.
13980                             */
13981                         } else
13982                             tmp = NULL;
13983                         ctxt->context->node = NULL;
13984                     }
13985                     if (tmp != NULL)
13986                         xmlXPathReleaseObject(ctxt->context, tmp);
13987                     /*
13988                      * The result is used as the new evaluation set.
13989                      */
13990                     xmlXPathReleaseObject(ctxt->context, obj);
13991                     ctxt->context->node = NULL;
13992                     ctxt->context->contextSize = -1;
13993                     ctxt->context->proximityPosition = -1;
13994                     /* may want to move this past the '}' later */
13995                     ctxt->context->doc = oldDoc;
13996                     valuePush(ctxt,
13997                         xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13998                 }
13999                 ctxt->context->node = oldnode;
14000                 return (total);
14001             }
14002         case XPATH_OP_SORT:
14003             if (op->ch1 != -1)
14004                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
14005             CHECK_ERROR0;
14006             if ((ctxt->value != NULL) &&
14007                 (ctxt->value->type == XPATH_NODESET) &&
14008                 (ctxt->value->nodesetval != NULL) &&
14009                 (ctxt->value->nodesetval->nodeNr > 1))
14010             {
14011                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
14012             }
14013             return (total);
14014 #ifdef LIBXML_XPTR_ENABLED
14015         case XPATH_OP_RANGETO:{
14016                 xmlXPathObjectPtr range;
14017                 xmlXPathObjectPtr res, obj;
14018                 xmlXPathObjectPtr tmp;
14019                 xmlLocationSetPtr newlocset = NULL;
14020                     xmlLocationSetPtr oldlocset;
14021                 xmlNodeSetPtr oldset;
14022                 int i, j;
14023
14024                 if (op->ch1 != -1) {
14025                     total +=
14026                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
14027                     CHECK_ERROR0;
14028                 }
14029                 if (ctxt->value == NULL) {
14030                     XP_ERROR0(XPATH_INVALID_OPERAND);
14031                 }
14032                 if (op->ch2 == -1)
14033                     return (total);
14034
14035                 if (ctxt->value->type == XPATH_LOCATIONSET) {
14036                     /*
14037                      * Extract the old locset, and then evaluate the result of the
14038                      * expression for all the element in the locset. use it to grow
14039                      * up a new locset.
14040                      */
14041                     CHECK_TYPE0(XPATH_LOCATIONSET);
14042                     obj = valuePop(ctxt);
14043                     oldlocset = obj->user;
14044
14045                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
14046                         ctxt->context->node = NULL;
14047                         ctxt->context->contextSize = 0;
14048                         ctxt->context->proximityPosition = 0;
14049                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
14050                         res = valuePop(ctxt);
14051                         if (res != NULL) {
14052                             xmlXPathReleaseObject(ctxt->context, res);
14053                         }
14054                         valuePush(ctxt, obj);
14055                         CHECK_ERROR0;
14056                         return (total);
14057                     }
14058                     newlocset = xmlXPtrLocationSetCreate(NULL);
14059
14060                     for (i = 0; i < oldlocset->locNr; i++) {
14061                         /*
14062                          * Run the evaluation with a node list made of a
14063                          * single item in the nodelocset.
14064                          */
14065                         ctxt->context->node = oldlocset->locTab[i]->user;
14066                         ctxt->context->contextSize = oldlocset->locNr;
14067                         ctxt->context->proximityPosition = i + 1;
14068                         tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14069                             ctxt->context->node);
14070                         valuePush(ctxt, tmp);
14071
14072                         if (op->ch2 != -1)
14073                             total +=
14074                                 xmlXPathCompOpEval(ctxt,
14075                                                    &comp->steps[op->ch2]);
14076                         if (ctxt->error != XPATH_EXPRESSION_OK) {
14077                             xmlXPathFreeObject(obj);
14078                             return(0);
14079                         }
14080
14081                         res = valuePop(ctxt);
14082                         if (res->type == XPATH_LOCATIONSET) {
14083                             xmlLocationSetPtr rloc =
14084                                 (xmlLocationSetPtr)res->user;
14085                             for (j=0; j<rloc->locNr; j++) {
14086                                 range = xmlXPtrNewRange(
14087                                   oldlocset->locTab[i]->user,
14088                                   oldlocset->locTab[i]->index,
14089                                   rloc->locTab[j]->user2,
14090                                   rloc->locTab[j]->index2);
14091                                 if (range != NULL) {
14092                                     xmlXPtrLocationSetAdd(newlocset, range);
14093                                 }
14094                             }
14095                         } else {
14096                             range = xmlXPtrNewRangeNodeObject(
14097                                 (xmlNodePtr)oldlocset->locTab[i]->user, res);
14098                             if (range != NULL) {
14099                                 xmlXPtrLocationSetAdd(newlocset,range);
14100                             }
14101                         }
14102
14103                         /*
14104                          * Cleanup
14105                          */
14106                         if (res != NULL) {
14107                             xmlXPathReleaseObject(ctxt->context, res);
14108                         }
14109                         if (ctxt->value == tmp) {
14110                             res = valuePop(ctxt);
14111                             xmlXPathReleaseObject(ctxt->context, res);
14112                         }
14113
14114                         ctxt->context->node = NULL;
14115                     }
14116                 } else {        /* Not a location set */
14117                     CHECK_TYPE0(XPATH_NODESET);
14118                     obj = valuePop(ctxt);
14119                     oldset = obj->nodesetval;
14120                     ctxt->context->node = NULL;
14121
14122                     newlocset = xmlXPtrLocationSetCreate(NULL);
14123
14124                     if (oldset != NULL) {
14125                         for (i = 0; i < oldset->nodeNr; i++) {
14126                             /*
14127                              * Run the evaluation with a node list made of a single item
14128                              * in the nodeset.
14129                              */
14130                             ctxt->context->node = oldset->nodeTab[i];
14131                             /*
14132                             * OPTIMIZE TODO: Avoid recreation for every iteration.
14133                             */
14134                             tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14135                                 ctxt->context->node);
14136                             valuePush(ctxt, tmp);
14137
14138                             if (op->ch2 != -1)
14139                                 total +=
14140                                     xmlXPathCompOpEval(ctxt,
14141                                                    &comp->steps[op->ch2]);
14142                             if (ctxt->error != XPATH_EXPRESSION_OK) {
14143                                 xmlXPathFreeObject(obj);
14144                                 return(0);
14145                             }
14146
14147                             res = valuePop(ctxt);
14148                             range =
14149                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14150                                                       res);
14151                             if (range != NULL) {
14152                                 xmlXPtrLocationSetAdd(newlocset, range);
14153                             }
14154
14155                             /*
14156                              * Cleanup
14157                              */
14158                             if (res != NULL) {
14159                                 xmlXPathReleaseObject(ctxt->context, res);
14160                             }
14161                             if (ctxt->value == tmp) {
14162                                 res = valuePop(ctxt);
14163                                 xmlXPathReleaseObject(ctxt->context, res);
14164                             }
14165
14166                             ctxt->context->node = NULL;
14167                         }
14168                     }
14169                 }
14170
14171                 /*
14172                  * The result is used as the new evaluation set.
14173                  */
14174                 xmlXPathReleaseObject(ctxt->context, obj);
14175                 ctxt->context->node = NULL;
14176                 ctxt->context->contextSize = -1;
14177                 ctxt->context->proximityPosition = -1;
14178                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14179                 return (total);
14180             }
14181 #endif /* LIBXML_XPTR_ENABLED */
14182     }
14183     xmlGenericError(xmlGenericErrorContext,
14184                     "XPath: unknown precompiled operation %d\n", op->op);
14185     ctxt->error = XPATH_INVALID_OPERAND;
14186     return (total);
14187 }
14188
14189 /**
14190  * xmlXPathCompOpEvalToBoolean:
14191  * @ctxt:  the XPath parser context
14192  *
14193  * Evaluates if the expression evaluates to true.
14194  *
14195  * Returns 1 if true, 0 if false and -1 on API or internal errors.
14196  */
14197 static int
14198 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14199                             xmlXPathStepOpPtr op,
14200                             int isPredicate)
14201 {
14202     xmlXPathObjectPtr resObj = NULL;
14203
14204 start:
14205     /* comp = ctxt->comp; */
14206     switch (op->op) {
14207         case XPATH_OP_END:
14208             return (0);
14209         case XPATH_OP_VALUE:
14210             resObj = (xmlXPathObjectPtr) op->value4;
14211             if (isPredicate)
14212                 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14213             return(xmlXPathCastToBoolean(resObj));
14214         case XPATH_OP_SORT:
14215             /*
14216             * We don't need sorting for boolean results. Skip this one.
14217             */
14218             if (op->ch1 != -1) {
14219                 op = &ctxt->comp->steps[op->ch1];
14220                 goto start;
14221             }
14222             return(0);
14223         case XPATH_OP_COLLECT:
14224             if (op->ch1 == -1)
14225                 return(0);
14226
14227             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14228             if (ctxt->error != XPATH_EXPRESSION_OK)
14229                 return(-1);
14230
14231             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14232             if (ctxt->error != XPATH_EXPRESSION_OK)
14233                 return(-1);
14234
14235             resObj = valuePop(ctxt);
14236             if (resObj == NULL)
14237                 return(-1);
14238             break;
14239         default:
14240             /*
14241             * Fallback to call xmlXPathCompOpEval().
14242             */
14243             xmlXPathCompOpEval(ctxt, op);
14244             if (ctxt->error != XPATH_EXPRESSION_OK)
14245                 return(-1);
14246
14247             resObj = valuePop(ctxt);
14248             if (resObj == NULL)
14249                 return(-1);
14250             break;
14251     }
14252
14253     if (resObj) {
14254         int res;
14255
14256         if (resObj->type == XPATH_BOOLEAN) {
14257             res = resObj->boolval;
14258         } else if (isPredicate) {
14259             /*
14260             * For predicates a result of type "number" is handled
14261             * differently:
14262             * SPEC XPath 1.0:
14263             * "If the result is a number, the result will be converted
14264             *  to true if the number is equal to the context position
14265             *  and will be converted to false otherwise;"
14266             */
14267             res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14268         } else {
14269             res = xmlXPathCastToBoolean(resObj);
14270         }
14271         xmlXPathReleaseObject(ctxt->context, resObj);
14272         return(res);
14273     }
14274
14275     return(0);
14276 }
14277
14278 #ifdef XPATH_STREAMING
14279 /**
14280  * xmlXPathRunStreamEval:
14281  * @ctxt:  the XPath parser context with the compiled expression
14282  *
14283  * Evaluate the Precompiled Streamable XPath expression in the given context.
14284  */
14285 static int
14286 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14287                       xmlXPathObjectPtr *resultSeq, int toBool)
14288 {
14289     int max_depth, min_depth;
14290     int from_root;
14291     int ret, depth;
14292     int eval_all_nodes;
14293     xmlNodePtr cur = NULL, limit = NULL;
14294     xmlStreamCtxtPtr patstream = NULL;
14295
14296     int nb_nodes = 0;
14297
14298     if ((ctxt == NULL) || (comp == NULL))
14299         return(-1);
14300     max_depth = xmlPatternMaxDepth(comp);
14301     if (max_depth == -1)
14302         return(-1);
14303     if (max_depth == -2)
14304         max_depth = 10000;
14305     min_depth = xmlPatternMinDepth(comp);
14306     if (min_depth == -1)
14307         return(-1);
14308     from_root = xmlPatternFromRoot(comp);
14309     if (from_root < 0)
14310         return(-1);
14311 #if 0
14312     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14313 #endif
14314
14315     if (! toBool) {
14316         if (resultSeq == NULL)
14317             return(-1);
14318         *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14319         if (*resultSeq == NULL)
14320             return(-1);
14321     }
14322
14323     /*
14324      * handle the special cases of "/" amd "." being matched
14325      */
14326     if (min_depth == 0) {
14327         if (from_root) {
14328             /* Select "/" */
14329             if (toBool)
14330                 return(1);
14331             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14332                                      (xmlNodePtr) ctxt->doc);
14333         } else {
14334             /* Select "self::node()" */
14335             if (toBool)
14336                 return(1);
14337             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14338         }
14339     }
14340     if (max_depth == 0) {
14341         return(0);
14342     }
14343
14344     if (from_root) {
14345         cur = (xmlNodePtr)ctxt->doc;
14346     } else if (ctxt->node != NULL) {
14347         switch (ctxt->node->type) {
14348             case XML_ELEMENT_NODE:
14349             case XML_DOCUMENT_NODE:
14350             case XML_DOCUMENT_FRAG_NODE:
14351             case XML_HTML_DOCUMENT_NODE:
14352 #ifdef LIBXML_DOCB_ENABLED
14353             case XML_DOCB_DOCUMENT_NODE:
14354 #endif
14355                 cur = ctxt->node;
14356                 break;
14357             case XML_ATTRIBUTE_NODE:
14358             case XML_TEXT_NODE:
14359             case XML_CDATA_SECTION_NODE:
14360             case XML_ENTITY_REF_NODE:
14361             case XML_ENTITY_NODE:
14362             case XML_PI_NODE:
14363             case XML_COMMENT_NODE:
14364             case XML_NOTATION_NODE:
14365             case XML_DTD_NODE:
14366             case XML_DOCUMENT_TYPE_NODE:
14367             case XML_ELEMENT_DECL:
14368             case XML_ATTRIBUTE_DECL:
14369             case XML_ENTITY_DECL:
14370             case XML_NAMESPACE_DECL:
14371             case XML_XINCLUDE_START:
14372             case XML_XINCLUDE_END:
14373                 break;
14374         }
14375         limit = cur;
14376     }
14377     if (cur == NULL) {
14378         return(0);
14379     }
14380
14381     patstream = xmlPatternGetStreamCtxt(comp);
14382     if (patstream == NULL) {
14383         /*
14384         * QUESTION TODO: Is this an error?
14385         */
14386         return(0);
14387     }
14388
14389     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14390
14391     if (from_root) {
14392         ret = xmlStreamPush(patstream, NULL, NULL);
14393         if (ret < 0) {
14394         } else if (ret == 1) {
14395             if (toBool)
14396                 goto return_1;
14397             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14398         }
14399     }
14400     depth = 0;
14401     goto scan_children;
14402 next_node:
14403     do {
14404         nb_nodes++;
14405
14406         switch (cur->type) {
14407             case XML_ELEMENT_NODE:
14408             case XML_TEXT_NODE:
14409             case XML_CDATA_SECTION_NODE:
14410             case XML_COMMENT_NODE:
14411             case XML_PI_NODE:
14412                 if (cur->type == XML_ELEMENT_NODE) {
14413                     ret = xmlStreamPush(patstream, cur->name,
14414                                 (cur->ns ? cur->ns->href : NULL));
14415                 } else if (eval_all_nodes)
14416                     ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14417                 else
14418                     break;
14419
14420                 if (ret < 0) {
14421                     /* NOP. */
14422                 } else if (ret == 1) {
14423                     if (toBool)
14424                         goto return_1;
14425                     if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14426                         < 0) {
14427                         ctxt->lastError.domain = XML_FROM_XPATH;
14428                         ctxt->lastError.code = XML_ERR_NO_MEMORY;
14429                     }
14430                 }
14431                 if ((cur->children == NULL) || (depth >= max_depth)) {
14432                     ret = xmlStreamPop(patstream);
14433                     while (cur->next != NULL) {
14434                         cur = cur->next;
14435                         if ((cur->type != XML_ENTITY_DECL) &&
14436                             (cur->type != XML_DTD_NODE))
14437                             goto next_node;
14438                     }
14439                 }
14440             default:
14441                 break;
14442         }
14443
14444 scan_children:
14445         if (cur->type == XML_NAMESPACE_DECL) break;
14446         if ((cur->children != NULL) && (depth < max_depth)) {
14447             /*
14448              * Do not descend on entities declarations
14449              */
14450             if (cur->children->type != XML_ENTITY_DECL) {
14451                 cur = cur->children;
14452                 depth++;
14453                 /*
14454                  * Skip DTDs
14455                  */
14456                 if (cur->type != XML_DTD_NODE)
14457                     continue;
14458             }
14459         }
14460
14461         if (cur == limit)
14462             break;
14463
14464         while (cur->next != NULL) {
14465             cur = cur->next;
14466             if ((cur->type != XML_ENTITY_DECL) &&
14467                 (cur->type != XML_DTD_NODE))
14468                 goto next_node;
14469         }
14470
14471         do {
14472             cur = cur->parent;
14473             depth--;
14474             if ((cur == NULL) || (cur == limit))
14475                 goto done;
14476             if (cur->type == XML_ELEMENT_NODE) {
14477                 ret = xmlStreamPop(patstream);
14478             } else if ((eval_all_nodes) &&
14479                 ((cur->type == XML_TEXT_NODE) ||
14480                  (cur->type == XML_CDATA_SECTION_NODE) ||
14481                  (cur->type == XML_COMMENT_NODE) ||
14482                  (cur->type == XML_PI_NODE)))
14483             {
14484                 ret = xmlStreamPop(patstream);
14485             }
14486             if (cur->next != NULL) {
14487                 cur = cur->next;
14488                 break;
14489             }
14490         } while (cur != NULL);
14491
14492     } while ((cur != NULL) && (depth >= 0));
14493
14494 done:
14495
14496 #if 0
14497     printf("stream eval: checked %d nodes selected %d\n",
14498            nb_nodes, retObj->nodesetval->nodeNr);
14499 #endif
14500
14501     if (patstream)
14502         xmlFreeStreamCtxt(patstream);
14503     return(0);
14504
14505 return_1:
14506     if (patstream)
14507         xmlFreeStreamCtxt(patstream);
14508     return(1);
14509 }
14510 #endif /* XPATH_STREAMING */
14511
14512 /**
14513  * xmlXPathRunEval:
14514  * @ctxt:  the XPath parser context with the compiled expression
14515  * @toBool:  evaluate to a boolean result
14516  *
14517  * Evaluate the Precompiled XPath expression in the given context.
14518  */
14519 static int
14520 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14521 {
14522     xmlXPathCompExprPtr comp;
14523
14524     if ((ctxt == NULL) || (ctxt->comp == NULL))
14525         return(-1);
14526
14527     if (ctxt->valueTab == NULL) {
14528         /* Allocate the value stack */
14529         ctxt->valueTab = (xmlXPathObjectPtr *)
14530                          xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14531         if (ctxt->valueTab == NULL) {
14532             xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14533             xmlFree(ctxt);
14534         }
14535         ctxt->valueNr = 0;
14536         ctxt->valueMax = 10;
14537         ctxt->value = NULL;
14538         ctxt->valueFrame = 0;
14539     }
14540 #ifdef XPATH_STREAMING
14541     if (ctxt->comp->stream) {
14542         int res;
14543
14544         if (toBool) {
14545             /*
14546             * Evaluation to boolean result.
14547             */
14548             res = xmlXPathRunStreamEval(ctxt->context,
14549                 ctxt->comp->stream, NULL, 1);
14550             if (res != -1)
14551                 return(res);
14552         } else {
14553             xmlXPathObjectPtr resObj = NULL;
14554
14555             /*
14556             * Evaluation to a sequence.
14557             */
14558             res = xmlXPathRunStreamEval(ctxt->context,
14559                 ctxt->comp->stream, &resObj, 0);
14560
14561             if ((res != -1) && (resObj != NULL)) {
14562                 valuePush(ctxt, resObj);
14563                 return(0);
14564             }
14565             if (resObj != NULL)
14566                 xmlXPathReleaseObject(ctxt->context, resObj);
14567         }
14568         /*
14569         * QUESTION TODO: This falls back to normal XPath evaluation
14570         * if res == -1. Is this intended?
14571         */
14572     }
14573 #endif
14574     comp = ctxt->comp;
14575     if (comp->last < 0) {
14576         xmlGenericError(xmlGenericErrorContext,
14577             "xmlXPathRunEval: last is less than zero\n");
14578         return(-1);
14579     }
14580     if (toBool)
14581         return(xmlXPathCompOpEvalToBoolean(ctxt,
14582             &comp->steps[comp->last], 0));
14583     else
14584         xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14585
14586     return(0);
14587 }
14588
14589 /************************************************************************
14590  *                                                                      *
14591  *                      Public interfaces                               *
14592  *                                                                      *
14593  ************************************************************************/
14594
14595 /**
14596  * xmlXPathEvalPredicate:
14597  * @ctxt:  the XPath context
14598  * @res:  the Predicate Expression evaluation result
14599  *
14600  * Evaluate a predicate result for the current node.
14601  * A PredicateExpr is evaluated by evaluating the Expr and converting
14602  * the result to a boolean. If the result is a number, the result will
14603  * be converted to true if the number is equal to the position of the
14604  * context node in the context node list (as returned by the position
14605  * function) and will be converted to false otherwise; if the result
14606  * is not a number, then the result will be converted as if by a call
14607  * to the boolean function.
14608  *
14609  * Returns 1 if predicate is true, 0 otherwise
14610  */
14611 int
14612 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14613     if ((ctxt == NULL) || (res == NULL)) return(0);
14614     switch (res->type) {
14615         case XPATH_BOOLEAN:
14616             return(res->boolval);
14617         case XPATH_NUMBER:
14618             return(res->floatval == ctxt->proximityPosition);
14619         case XPATH_NODESET:
14620         case XPATH_XSLT_TREE:
14621             if (res->nodesetval == NULL)
14622                 return(0);
14623             return(res->nodesetval->nodeNr != 0);
14624         case XPATH_STRING:
14625             return((res->stringval != NULL) &&
14626                    (xmlStrlen(res->stringval) != 0));
14627         default:
14628             STRANGE
14629     }
14630     return(0);
14631 }
14632
14633 /**
14634  * xmlXPathEvaluatePredicateResult:
14635  * @ctxt:  the XPath Parser context
14636  * @res:  the Predicate Expression evaluation result
14637  *
14638  * Evaluate a predicate result for the current node.
14639  * A PredicateExpr is evaluated by evaluating the Expr and converting
14640  * the result to a boolean. If the result is a number, the result will
14641  * be converted to true if the number is equal to the position of the
14642  * context node in the context node list (as returned by the position
14643  * function) and will be converted to false otherwise; if the result
14644  * is not a number, then the result will be converted as if by a call
14645  * to the boolean function.
14646  *
14647  * Returns 1 if predicate is true, 0 otherwise
14648  */
14649 int
14650 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14651                                 xmlXPathObjectPtr res) {
14652     if ((ctxt == NULL) || (res == NULL)) return(0);
14653     switch (res->type) {
14654         case XPATH_BOOLEAN:
14655             return(res->boolval);
14656         case XPATH_NUMBER:
14657 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14658             return((res->floatval == ctxt->context->proximityPosition) &&
14659                    (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14660 #else
14661             return(res->floatval == ctxt->context->proximityPosition);
14662 #endif
14663         case XPATH_NODESET:
14664         case XPATH_XSLT_TREE:
14665             if (res->nodesetval == NULL)
14666                 return(0);
14667             return(res->nodesetval->nodeNr != 0);
14668         case XPATH_STRING:
14669             return((res->stringval != NULL) && (res->stringval[0] != 0));
14670 #ifdef LIBXML_XPTR_ENABLED
14671         case XPATH_LOCATIONSET:{
14672             xmlLocationSetPtr ptr = res->user;
14673             if (ptr == NULL)
14674                 return(0);
14675             return (ptr->locNr != 0);
14676             }
14677 #endif
14678         default:
14679             STRANGE
14680     }
14681     return(0);
14682 }
14683
14684 #ifdef XPATH_STREAMING
14685 /**
14686  * xmlXPathTryStreamCompile:
14687  * @ctxt: an XPath context
14688  * @str:  the XPath expression
14689  *
14690  * Try to compile the XPath expression as a streamable subset.
14691  *
14692  * Returns the compiled expression or NULL if failed to compile.
14693  */
14694 static xmlXPathCompExprPtr
14695 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14696     /*
14697      * Optimization: use streaming patterns when the XPath expression can
14698      * be compiled to a stream lookup
14699      */
14700     xmlPatternPtr stream;
14701     xmlXPathCompExprPtr comp;
14702     xmlDictPtr dict = NULL;
14703     const xmlChar **namespaces = NULL;
14704     xmlNsPtr ns;
14705     int i, j;
14706
14707     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14708         (!xmlStrchr(str, '@'))) {
14709         const xmlChar *tmp;
14710
14711         /*
14712          * We don't try to handle expressions using the verbose axis
14713          * specifiers ("::"), just the simplied form at this point.
14714          * Additionally, if there is no list of namespaces available and
14715          *  there's a ":" in the expression, indicating a prefixed QName,
14716          *  then we won't try to compile either. xmlPatterncompile() needs
14717          *  to have a list of namespaces at compilation time in order to
14718          *  compile prefixed name tests.
14719          */
14720         tmp = xmlStrchr(str, ':');
14721         if ((tmp != NULL) &&
14722             ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14723             return(NULL);
14724
14725         if (ctxt != NULL) {
14726             dict = ctxt->dict;
14727             if (ctxt->nsNr > 0) {
14728                 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14729                 if (namespaces == NULL) {
14730                     xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14731                     return(NULL);
14732                 }
14733                 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14734                     ns = ctxt->namespaces[j];
14735                     namespaces[i++] = ns->href;
14736                     namespaces[i++] = ns->prefix;
14737                 }
14738                 namespaces[i++] = NULL;
14739                 namespaces[i] = NULL;
14740             }
14741         }
14742
14743         stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14744                         &namespaces[0]);
14745         if (namespaces != NULL) {
14746             xmlFree((xmlChar **)namespaces);
14747         }
14748         if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14749             comp = xmlXPathNewCompExpr();
14750             if (comp == NULL) {
14751                 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14752                 return(NULL);
14753             }
14754             comp->stream = stream;
14755             comp->dict = dict;
14756             if (comp->dict)
14757                 xmlDictReference(comp->dict);
14758             return(comp);
14759         }
14760         xmlFreePattern(stream);
14761     }
14762     return(NULL);
14763 }
14764 #endif /* XPATH_STREAMING */
14765
14766 static void
14767 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14768 {
14769     /*
14770     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14771     * internal representation.
14772     */
14773
14774     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14775         (op->ch1 != -1) &&
14776         (op->ch2 == -1 /* no predicate */))
14777     {
14778         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14779
14780         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14781             ((xmlXPathAxisVal) prevop->value ==
14782                 AXIS_DESCENDANT_OR_SELF) &&
14783             (prevop->ch2 == -1) &&
14784             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14785             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14786         {
14787             /*
14788             * This is a "descendant-or-self::node()" without predicates.
14789             * Try to eliminate it.
14790             */
14791
14792             switch ((xmlXPathAxisVal) op->value) {
14793                 case AXIS_CHILD:
14794                 case AXIS_DESCENDANT:
14795                     /*
14796                     * Convert "descendant-or-self::node()/child::" or
14797                     * "descendant-or-self::node()/descendant::" to
14798                     * "descendant::"
14799                     */
14800                     op->ch1   = prevop->ch1;
14801                     op->value = AXIS_DESCENDANT;
14802                     break;
14803                 case AXIS_SELF:
14804                 case AXIS_DESCENDANT_OR_SELF:
14805                     /*
14806                     * Convert "descendant-or-self::node()/self::" or
14807                     * "descendant-or-self::node()/descendant-or-self::" to
14808                     * to "descendant-or-self::"
14809                     */
14810                     op->ch1   = prevop->ch1;
14811                     op->value = AXIS_DESCENDANT_OR_SELF;
14812                     break;
14813                 default:
14814                     break;
14815             }
14816         }
14817     }
14818
14819     /* OP_VALUE has invalid ch1. */
14820     if (op->op == XPATH_OP_VALUE)
14821         return;
14822
14823     /* Recurse */
14824     if (op->ch1 != -1)
14825         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14826     if (op->ch2 != -1)
14827         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14828 }
14829
14830 /**
14831  * xmlXPathCtxtCompile:
14832  * @ctxt: an XPath context
14833  * @str:  the XPath expression
14834  *
14835  * Compile an XPath expression
14836  *
14837  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14838  *         the caller has to free the object.
14839  */
14840 xmlXPathCompExprPtr
14841 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14842     xmlXPathParserContextPtr pctxt;
14843     xmlXPathCompExprPtr comp;
14844
14845 #ifdef XPATH_STREAMING
14846     comp = xmlXPathTryStreamCompile(ctxt, str);
14847     if (comp != NULL)
14848         return(comp);
14849 #endif
14850
14851     xmlXPathInit();
14852
14853     pctxt = xmlXPathNewParserContext(str, ctxt);
14854     if (pctxt == NULL)
14855         return NULL;
14856     xmlXPathCompileExpr(pctxt, 1);
14857
14858     if( pctxt->error != XPATH_EXPRESSION_OK )
14859     {
14860         xmlXPathFreeParserContext(pctxt);
14861         return(NULL);
14862     }
14863
14864     if (*pctxt->cur != 0) {
14865         /*
14866          * aleksey: in some cases this line prints *second* error message
14867          * (see bug #78858) and probably this should be fixed.
14868          * However, we are not sure that all error messages are printed
14869          * out in other places. It's not critical so we leave it as-is for now
14870          */
14871         xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14872         comp = NULL;
14873     } else {
14874         comp = pctxt->comp;
14875         pctxt->comp = NULL;
14876     }
14877     xmlXPathFreeParserContext(pctxt);
14878
14879     if (comp != NULL) {
14880         comp->expr = xmlStrdup(str);
14881 #ifdef DEBUG_EVAL_COUNTS
14882         comp->string = xmlStrdup(str);
14883         comp->nb = 0;
14884 #endif
14885         if ((comp->nbStep > 1) && (comp->last >= 0)) {
14886             xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14887         }
14888     }
14889     return(comp);
14890 }
14891
14892 /**
14893  * xmlXPathCompile:
14894  * @str:  the XPath expression
14895  *
14896  * Compile an XPath expression
14897  *
14898  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14899  *         the caller has to free the object.
14900  */
14901 xmlXPathCompExprPtr
14902 xmlXPathCompile(const xmlChar *str) {
14903     return(xmlXPathCtxtCompile(NULL, str));
14904 }
14905
14906 /**
14907  * xmlXPathCompiledEvalInternal:
14908  * @comp:  the compiled XPath expression
14909  * @ctxt:  the XPath context
14910  * @resObj: the resulting XPath object or NULL
14911  * @toBool: 1 if only a boolean result is requested
14912  *
14913  * Evaluate the Precompiled XPath expression in the given context.
14914  * The caller has to free @resObj.
14915  *
14916  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14917  *         the caller has to free the object.
14918  */
14919 static int
14920 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14921                              xmlXPathContextPtr ctxt,
14922                              xmlXPathObjectPtr *resObjPtr,
14923                              int toBool)
14924 {
14925     xmlXPathParserContextPtr pctxt;
14926     xmlXPathObjectPtr resObj;
14927 #ifndef LIBXML_THREAD_ENABLED
14928     static int reentance = 0;
14929 #endif
14930     int res;
14931
14932     CHECK_CTXT_NEG(ctxt)
14933
14934     if (comp == NULL)
14935         return(-1);
14936     xmlXPathInit();
14937
14938 #ifndef LIBXML_THREAD_ENABLED
14939     reentance++;
14940     if (reentance > 1)
14941         xmlXPathDisableOptimizer = 1;
14942 #endif
14943
14944 #ifdef DEBUG_EVAL_COUNTS
14945     comp->nb++;
14946     if ((comp->string != NULL) && (comp->nb > 100)) {
14947         fprintf(stderr, "100 x %s\n", comp->string);
14948         comp->nb = 0;
14949     }
14950 #endif
14951     pctxt = xmlXPathCompParserContext(comp, ctxt);
14952     res = xmlXPathRunEval(pctxt, toBool);
14953
14954     if (pctxt->error != XPATH_EXPRESSION_OK) {
14955         resObj = NULL;
14956     } else {
14957         resObj = valuePop(pctxt);
14958         if (resObj == NULL) {
14959             if (!toBool)
14960                 xmlGenericError(xmlGenericErrorContext,
14961                     "xmlXPathCompiledEval: No result on the stack.\n");
14962         } else if (pctxt->valueNr > 0) {
14963             xmlGenericError(xmlGenericErrorContext,
14964                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14965                 pctxt->valueNr);
14966         }
14967     }
14968
14969     if (resObjPtr)
14970         *resObjPtr = resObj;
14971     else
14972         xmlXPathReleaseObject(ctxt, resObj);
14973
14974     pctxt->comp = NULL;
14975     xmlXPathFreeParserContext(pctxt);
14976 #ifndef LIBXML_THREAD_ENABLED
14977     reentance--;
14978 #endif
14979
14980     return(res);
14981 }
14982
14983 /**
14984  * xmlXPathCompiledEval:
14985  * @comp:  the compiled XPath expression
14986  * @ctx:  the XPath context
14987  *
14988  * Evaluate the Precompiled XPath expression in the given context.
14989  *
14990  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14991  *         the caller has to free the object.
14992  */
14993 xmlXPathObjectPtr
14994 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14995 {
14996     xmlXPathObjectPtr res = NULL;
14997
14998     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14999     return(res);
15000 }
15001
15002 /**
15003  * xmlXPathCompiledEvalToBoolean:
15004  * @comp:  the compiled XPath expression
15005  * @ctxt:  the XPath context
15006  *
15007  * Applies the XPath boolean() function on the result of the given
15008  * compiled expression.
15009  *
15010  * Returns 1 if the expression evaluated to true, 0 if to false and
15011  *         -1 in API and internal errors.
15012  */
15013 int
15014 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
15015                               xmlXPathContextPtr ctxt)
15016 {
15017     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
15018 }
15019
15020 /**
15021  * xmlXPathEvalExpr:
15022  * @ctxt:  the XPath Parser context
15023  *
15024  * Parse and evaluate an XPath expression in the given context,
15025  * then push the result on the context stack
15026  */
15027 void
15028 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
15029 #ifdef XPATH_STREAMING
15030     xmlXPathCompExprPtr comp;
15031 #endif
15032
15033     if (ctxt == NULL) return;
15034
15035 #ifdef XPATH_STREAMING
15036     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
15037     if (comp != NULL) {
15038         if (ctxt->comp != NULL)
15039             xmlXPathFreeCompExpr(ctxt->comp);
15040         ctxt->comp = comp;
15041     } else
15042 #endif
15043     {
15044         xmlXPathCompileExpr(ctxt, 1);
15045         CHECK_ERROR;
15046
15047         /* Check for trailing characters. */
15048         if (*ctxt->cur != 0)
15049             XP_ERROR(XPATH_EXPR_ERROR);
15050
15051         if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
15052             xmlXPathOptimizeExpression(ctxt->comp,
15053                 &ctxt->comp->steps[ctxt->comp->last]);
15054     }
15055
15056     xmlXPathRunEval(ctxt, 0);
15057 }
15058
15059 /**
15060  * xmlXPathEval:
15061  * @str:  the XPath expression
15062  * @ctx:  the XPath context
15063  *
15064  * Evaluate the XPath Location Path in the given context.
15065  *
15066  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15067  *         the caller has to free the object.
15068  */
15069 xmlXPathObjectPtr
15070 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15071     xmlXPathParserContextPtr ctxt;
15072     xmlXPathObjectPtr res;
15073
15074     CHECK_CTXT(ctx)
15075
15076     xmlXPathInit();
15077
15078     ctxt = xmlXPathNewParserContext(str, ctx);
15079     if (ctxt == NULL)
15080         return NULL;
15081     xmlXPathEvalExpr(ctxt);
15082
15083     if (ctxt->error != XPATH_EXPRESSION_OK) {
15084         res = NULL;
15085     } else {
15086         res = valuePop(ctxt);
15087         if (res == NULL) {
15088             xmlGenericError(xmlGenericErrorContext,
15089                 "xmlXPathCompiledEval: No result on the stack.\n");
15090         } else if (ctxt->valueNr > 0) {
15091             xmlGenericError(xmlGenericErrorContext,
15092                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
15093                 ctxt->valueNr);
15094         }
15095     }
15096
15097     xmlXPathFreeParserContext(ctxt);
15098     return(res);
15099 }
15100
15101 /**
15102  * xmlXPathSetContextNode:
15103  * @node: the node to to use as the context node
15104  * @ctx:  the XPath context
15105  *
15106  * Sets 'node' as the context node. The node must be in the same
15107  * document as that associated with the context.
15108  *
15109  * Returns -1 in case of error or 0 if successful
15110  */
15111 int
15112 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15113     if ((node == NULL) || (ctx == NULL))
15114         return(-1);
15115
15116     if (node->doc == ctx->doc) {
15117         ctx->node = node;
15118         return(0);
15119     }
15120     return(-1);
15121 }
15122
15123 /**
15124  * xmlXPathNodeEval:
15125  * @node: the node to to use as the context node
15126  * @str:  the XPath expression
15127  * @ctx:  the XPath context
15128  *
15129  * Evaluate the XPath Location Path in the given context. The node 'node'
15130  * is set as the context node. The context node is not restored.
15131  *
15132  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15133  *         the caller has to free the object.
15134  */
15135 xmlXPathObjectPtr
15136 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15137     if (str == NULL)
15138         return(NULL);
15139     if (xmlXPathSetContextNode(node, ctx) < 0)
15140         return(NULL);
15141     return(xmlXPathEval(str, ctx));
15142 }
15143
15144 /**
15145  * xmlXPathEvalExpression:
15146  * @str:  the XPath expression
15147  * @ctxt:  the XPath context
15148  *
15149  * Alias for xmlXPathEval().
15150  *
15151  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15152  *         the caller has to free the object.
15153  */
15154 xmlXPathObjectPtr
15155 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15156     return(xmlXPathEval(str, ctxt));
15157 }
15158
15159 /************************************************************************
15160  *                                                                      *
15161  *      Extra functions not pertaining to the XPath spec                *
15162  *                                                                      *
15163  ************************************************************************/
15164 /**
15165  * xmlXPathEscapeUriFunction:
15166  * @ctxt:  the XPath Parser context
15167  * @nargs:  the number of arguments
15168  *
15169  * Implement the escape-uri() XPath function
15170  *    string escape-uri(string $str, bool $escape-reserved)
15171  *
15172  * This function applies the URI escaping rules defined in section 2 of [RFC
15173  * 2396] to the string supplied as $uri-part, which typically represents all
15174  * or part of a URI. The effect of the function is to replace any special
15175  * character in the string by an escape sequence of the form %xx%yy...,
15176  * where xxyy... is the hexadecimal representation of the octets used to
15177  * represent the character in UTF-8.
15178  *
15179  * The set of characters that are escaped depends on the setting of the
15180  * boolean argument $escape-reserved.
15181  *
15182  * If $escape-reserved is true, all characters are escaped other than lower
15183  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15184  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15185  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15186  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15187  * A-F).
15188  *
15189  * If $escape-reserved is false, the behavior differs in that characters
15190  * referred to in [RFC 2396] as reserved characters are not escaped. These
15191  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15192  *
15193  * [RFC 2396] does not define whether escaped URIs should use lower case or
15194  * upper case for hexadecimal digits. To ensure that escaped URIs can be
15195  * compared using string comparison functions, this function must always use
15196  * the upper-case letters A-F.
15197  *
15198  * Generally, $escape-reserved should be set to true when escaping a string
15199  * that is to form a single part of a URI, and to false when escaping an
15200  * entire URI or URI reference.
15201  *
15202  * In the case of non-ascii characters, the string is encoded according to
15203  * utf-8 and then converted according to RFC 2396.
15204  *
15205  * Examples
15206  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15207  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15208  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15209  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15210  *
15211  */
15212 static void
15213 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15214     xmlXPathObjectPtr str;
15215     int escape_reserved;
15216     xmlBufPtr target;
15217     xmlChar *cptr;
15218     xmlChar escape[4];
15219
15220     CHECK_ARITY(2);
15221
15222     escape_reserved = xmlXPathPopBoolean(ctxt);
15223
15224     CAST_TO_STRING;
15225     str = valuePop(ctxt);
15226
15227     target = xmlBufCreate();
15228
15229     escape[0] = '%';
15230     escape[3] = 0;
15231
15232     if (target) {
15233         for (cptr = str->stringval; *cptr; cptr++) {
15234             if ((*cptr >= 'A' && *cptr <= 'Z') ||
15235                 (*cptr >= 'a' && *cptr <= 'z') ||
15236                 (*cptr >= '0' && *cptr <= '9') ||
15237                 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15238                 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15239                 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15240                 (*cptr == '%' &&
15241                  ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15242                   (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15243                   (cptr[1] >= '0' && cptr[1] <= '9')) &&
15244                  ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15245                   (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15246                   (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15247                 (!escape_reserved &&
15248                  (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15249                   *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15250                   *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15251                   *cptr == ','))) {
15252                 xmlBufAdd(target, cptr, 1);
15253             } else {
15254                 if ((*cptr >> 4) < 10)
15255                     escape[1] = '0' + (*cptr >> 4);
15256                 else
15257                     escape[1] = 'A' - 10 + (*cptr >> 4);
15258                 if ((*cptr & 0xF) < 10)
15259                     escape[2] = '0' + (*cptr & 0xF);
15260                 else
15261                     escape[2] = 'A' - 10 + (*cptr & 0xF);
15262
15263                 xmlBufAdd(target, &escape[0], 3);
15264             }
15265         }
15266     }
15267     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15268         xmlBufContent(target)));
15269     xmlBufFree(target);
15270     xmlXPathReleaseObject(ctxt->context, str);
15271 }
15272
15273 /**
15274  * xmlXPathRegisterAllFunctions:
15275  * @ctxt:  the XPath context
15276  *
15277  * Registers all default XPath functions in this context
15278  */
15279 void
15280 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15281 {
15282     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15283                          xmlXPathBooleanFunction);
15284     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15285                          xmlXPathCeilingFunction);
15286     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15287                          xmlXPathCountFunction);
15288     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15289                          xmlXPathConcatFunction);
15290     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15291                          xmlXPathContainsFunction);
15292     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15293                          xmlXPathIdFunction);
15294     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15295                          xmlXPathFalseFunction);
15296     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15297                          xmlXPathFloorFunction);
15298     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15299                          xmlXPathLastFunction);
15300     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15301                          xmlXPathLangFunction);
15302     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15303                          xmlXPathLocalNameFunction);
15304     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15305                          xmlXPathNotFunction);
15306     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15307                          xmlXPathNameFunction);
15308     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15309                          xmlXPathNamespaceURIFunction);
15310     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15311                          xmlXPathNormalizeFunction);
15312     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15313                          xmlXPathNumberFunction);
15314     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15315                          xmlXPathPositionFunction);
15316     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15317                          xmlXPathRoundFunction);
15318     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15319                          xmlXPathStringFunction);
15320     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15321                          xmlXPathStringLengthFunction);
15322     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15323                          xmlXPathStartsWithFunction);
15324     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15325                          xmlXPathSubstringFunction);
15326     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15327                          xmlXPathSubstringBeforeFunction);
15328     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15329                          xmlXPathSubstringAfterFunction);
15330     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15331                          xmlXPathSumFunction);
15332     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15333                          xmlXPathTrueFunction);
15334     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15335                          xmlXPathTranslateFunction);
15336
15337     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15338          (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15339                          xmlXPathEscapeUriFunction);
15340 }
15341
15342 #endif /* LIBXML_XPATH_ENABLED */
15343 #define bottom_xpath
15344 #include "elfgcchack.h"