Merge "Merge branch 'tizen_base' into tizen" into tizen
[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 #include <stddef.h>
28
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32 #ifdef HAVE_MATH_H
33 #include <math.h>
34 #endif
35 #ifdef HAVE_FLOAT_H
36 #include <float.h>
37 #endif
38 #ifdef HAVE_CTYPE_H
39 #include <ctype.h>
40 #endif
41 #ifdef HAVE_SIGNAL_H
42 #include <signal.h>
43 #endif
44
45 #include <libxml/xmlmemory.h>
46 #include <libxml/tree.h>
47 #include <libxml/valid.h>
48 #include <libxml/xpath.h>
49 #include <libxml/xpathInternals.h>
50 #include <libxml/parserInternals.h>
51 #include <libxml/hash.h>
52 #ifdef LIBXML_XPTR_ENABLED
53 #include <libxml/xpointer.h>
54 #endif
55 #ifdef LIBXML_DEBUG_ENABLED
56 #include <libxml/debugXML.h>
57 #endif
58 #include <libxml/xmlerror.h>
59 #include <libxml/threads.h>
60 #include <libxml/globals.h>
61 #ifdef LIBXML_PATTERN_ENABLED
62 #include <libxml/pattern.h>
63 #endif
64
65 #include "buf.h"
66
67 #ifdef LIBXML_PATTERN_ENABLED
68 #define XPATH_STREAMING
69 #endif
70
71 #define TODO                                                            \
72     xmlGenericError(xmlGenericErrorContext,                             \
73             "Unimplemented block at %s:%d\n",                           \
74             __FILE__, __LINE__);
75
76 /**
77  * WITH_TIM_SORT:
78  *
79  * Use the Timsort algorithm provided in timsort.h to sort
80  * nodeset as this is a great improvement over the old Shell sort
81  * used in xmlXPathNodeSetSort()
82  */
83 #define WITH_TIM_SORT
84
85 /*
86 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
87 * If defined, this will use xmlXPathCmpNodesExt() instead of
88 * xmlXPathCmpNodes(). The new function is optimized comparison of
89 * non-element nodes; actually it will speed up comparison only if
90 * xmlXPathOrderDocElems() was called in order to index the elements of
91 * a tree in document order; Libxslt does such an indexing, thus it will
92 * benefit from this optimization.
93 */
94 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
95
96 /*
97 * XP_OPTIMIZED_FILTER_FIRST:
98 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
99 * in a way, that it stop evaluation at the first node.
100 */
101 #define XP_OPTIMIZED_FILTER_FIRST
102
103 /*
104 * XP_DEBUG_OBJ_USAGE:
105 * Internal flag to enable tracking of how much XPath objects have been
106 * created.
107 */
108 /* #define XP_DEBUG_OBJ_USAGE */
109
110 /*
111  * XPATH_MAX_STEPS:
112  * when compiling an XPath expression we arbitrary limit the maximum
113  * number of step operation in the compiled expression. 1000000 is
114  * an insanely large value which should never be reached under normal
115  * circumstances
116  */
117 #define XPATH_MAX_STEPS 1000000
118
119 /*
120  * XPATH_MAX_STACK_DEPTH:
121  * when evaluating an XPath expression we arbitrary limit the maximum
122  * number of object allowed to be pushed on the stack. 1000000 is
123  * an insanely large value which should never be reached under normal
124  * circumstances
125  */
126 #define XPATH_MAX_STACK_DEPTH 1000000
127
128 /*
129  * XPATH_MAX_NODESET_LENGTH:
130  * when evaluating an XPath expression nodesets are created and we
131  * arbitrary limit the maximum length of those node set. 10000000 is
132  * an insanely large value which should never be reached under normal
133  * circumstances, one would first need to construct an in memory tree
134  * with more than 10 millions nodes.
135  */
136 #define XPATH_MAX_NODESET_LENGTH 10000000
137
138 /*
139  * TODO:
140  * There are a few spots where some tests are done which depend upon ascii
141  * data.  These should be enhanced for full UTF8 support (see particularly
142  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
143  */
144
145 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
146 /**
147  * xmlXPathCmpNodesExt:
148  * @node1:  the first node
149  * @node2:  the second node
150  *
151  * Compare two nodes w.r.t document order.
152  * This one is optimized for handling of non-element nodes.
153  *
154  * Returns -2 in case of error 1 if first point < second point, 0 if
155  *         it's the same node, -1 otherwise
156  */
157 static int
158 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
159     int depth1, depth2;
160     int misc = 0, precedence1 = 0, precedence2 = 0;
161     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
162     xmlNodePtr cur, root;
163     ptrdiff_t l1, l2;
164
165     if ((node1 == NULL) || (node2 == NULL))
166         return(-2);
167
168     if (node1 == node2)
169         return(0);
170
171     /*
172      * a couple of optimizations which will avoid computations in most cases
173      */
174     switch (node1->type) {
175         case XML_ELEMENT_NODE:
176             if (node2->type == XML_ELEMENT_NODE) {
177                 if ((0 > (ptrdiff_t) node1->content) &&
178                     (0 > (ptrdiff_t) node2->content) &&
179                     (node1->doc == node2->doc))
180                 {
181                     l1 = -((ptrdiff_t) node1->content);
182                     l2 = -((ptrdiff_t) node2->content);
183                     if (l1 < l2)
184                         return(1);
185                     if (l1 > l2)
186                         return(-1);
187                 } else
188                     goto turtle_comparison;
189             }
190             break;
191         case XML_ATTRIBUTE_NODE:
192             precedence1 = 1; /* element is owner */
193             miscNode1 = node1;
194             node1 = node1->parent;
195             misc = 1;
196             break;
197         case XML_TEXT_NODE:
198         case XML_CDATA_SECTION_NODE:
199         case XML_COMMENT_NODE:
200         case XML_PI_NODE: {
201             miscNode1 = node1;
202             /*
203             * Find nearest element node.
204             */
205             if (node1->prev != NULL) {
206                 do {
207                     node1 = node1->prev;
208                     if (node1->type == XML_ELEMENT_NODE) {
209                         precedence1 = 3; /* element in prev-sibl axis */
210                         break;
211                     }
212                     if (node1->prev == NULL) {
213                         precedence1 = 2; /* element is parent */
214                         /*
215                         * URGENT TODO: Are there any cases, where the
216                         * parent of such a node is not an element node?
217                         */
218                         node1 = node1->parent;
219                         break;
220                     }
221                 } while (1);
222             } else {
223                 precedence1 = 2; /* element is parent */
224                 node1 = node1->parent;
225             }
226             if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
227                 (0 <= (ptrdiff_t) node1->content)) {
228                 /*
229                 * Fallback for whatever case.
230                 */
231                 node1 = miscNode1;
232                 precedence1 = 0;
233             } else
234                 misc = 1;
235         }
236             break;
237         case XML_NAMESPACE_DECL:
238             /*
239             * TODO: why do we return 1 for namespace nodes?
240             */
241             return(1);
242         default:
243             break;
244     }
245     switch (node2->type) {
246         case XML_ELEMENT_NODE:
247             break;
248         case XML_ATTRIBUTE_NODE:
249             precedence2 = 1; /* element is owner */
250             miscNode2 = node2;
251             node2 = node2->parent;
252             misc = 1;
253             break;
254         case XML_TEXT_NODE:
255         case XML_CDATA_SECTION_NODE:
256         case XML_COMMENT_NODE:
257         case XML_PI_NODE: {
258             miscNode2 = node2;
259             if (node2->prev != NULL) {
260                 do {
261                     node2 = node2->prev;
262                     if (node2->type == XML_ELEMENT_NODE) {
263                         precedence2 = 3; /* element in prev-sibl axis */
264                         break;
265                     }
266                     if (node2->prev == NULL) {
267                         precedence2 = 2; /* element is parent */
268                         node2 = node2->parent;
269                         break;
270                     }
271                 } while (1);
272             } else {
273                 precedence2 = 2; /* element is parent */
274                 node2 = node2->parent;
275             }
276             if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
277                 (0 <= (ptrdiff_t) node2->content))
278             {
279                 node2 = miscNode2;
280                 precedence2 = 0;
281             } else
282                 misc = 1;
283         }
284             break;
285         case XML_NAMESPACE_DECL:
286             return(1);
287         default:
288             break;
289     }
290     if (misc) {
291         if (node1 == node2) {
292             if (precedence1 == precedence2) {
293                 /*
294                 * The ugly case; but normally there aren't many
295                 * adjacent non-element nodes around.
296                 */
297                 cur = miscNode2->prev;
298                 while (cur != NULL) {
299                     if (cur == miscNode1)
300                         return(1);
301                     if (cur->type == XML_ELEMENT_NODE)
302                         return(-1);
303                     cur = cur->prev;
304                 }
305                 return (-1);
306             } else {
307                 /*
308                 * Evaluate based on higher precedence wrt to the element.
309                 * TODO: This assumes attributes are sorted before content.
310                 *   Is this 100% correct?
311                 */
312                 if (precedence1 < precedence2)
313                     return(1);
314                 else
315                     return(-1);
316             }
317         }
318         /*
319         * Special case: One of the helper-elements is contained by the other.
320         * <foo>
321         *   <node2>
322         *     <node1>Text-1(precedence1 == 2)</node1>
323         *   </node2>
324         *   Text-6(precedence2 == 3)
325         * </foo>
326         */
327         if ((precedence2 == 3) && (precedence1 > 1)) {
328             cur = node1->parent;
329             while (cur) {
330                 if (cur == node2)
331                     return(1);
332                 cur = cur->parent;
333             }
334         }
335         if ((precedence1 == 3) && (precedence2 > 1)) {
336             cur = node2->parent;
337             while (cur) {
338                 if (cur == node1)
339                     return(-1);
340                 cur = cur->parent;
341             }
342         }
343     }
344
345     /*
346      * Speedup using document order if availble.
347      */
348     if ((node1->type == XML_ELEMENT_NODE) &&
349         (node2->type == XML_ELEMENT_NODE) &&
350         (0 > (ptrdiff_t) node1->content) &&
351         (0 > (ptrdiff_t) node2->content) &&
352         (node1->doc == node2->doc)) {
353
354         l1 = -((ptrdiff_t) node1->content);
355         l2 = -((ptrdiff_t) node2->content);
356         if (l1 < l2)
357             return(1);
358         if (l1 > l2)
359             return(-1);
360     }
361
362 turtle_comparison:
363
364     if (node1 == node2->prev)
365         return(1);
366     if (node1 == node2->next)
367         return(-1);
368     /*
369      * compute depth to root
370      */
371     for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
372         if (cur->parent == node1)
373             return(1);
374         depth2++;
375     }
376     root = cur;
377     for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
378         if (cur->parent == node2)
379             return(-1);
380         depth1++;
381     }
382     /*
383      * Distinct document (or distinct entities :-( ) case.
384      */
385     if (root != cur) {
386         return(-2);
387     }
388     /*
389      * get the nearest common ancestor.
390      */
391     while (depth1 > depth2) {
392         depth1--;
393         node1 = node1->parent;
394     }
395     while (depth2 > depth1) {
396         depth2--;
397         node2 = node2->parent;
398     }
399     while (node1->parent != node2->parent) {
400         node1 = node1->parent;
401         node2 = node2->parent;
402         /* should not happen but just in case ... */
403         if ((node1 == NULL) || (node2 == NULL))
404             return(-2);
405     }
406     /*
407      * Find who's first.
408      */
409     if (node1 == node2->prev)
410         return(1);
411     if (node1 == node2->next)
412         return(-1);
413     /*
414      * Speedup using document order if availble.
415      */
416     if ((node1->type == XML_ELEMENT_NODE) &&
417         (node2->type == XML_ELEMENT_NODE) &&
418         (0 > (ptrdiff_t) node1->content) &&
419         (0 > (ptrdiff_t) node2->content) &&
420         (node1->doc == node2->doc)) {
421
422         l1 = -((ptrdiff_t) node1->content);
423         l2 = -((ptrdiff_t) node2->content);
424         if (l1 < l2)
425             return(1);
426         if (l1 > l2)
427             return(-1);
428     }
429
430     for (cur = node1->next;cur != NULL;cur = cur->next)
431         if (cur == node2)
432             return(1);
433     return(-1); /* assume there is no sibling list corruption */
434 }
435 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
436
437 /*
438  * Wrapper for the Timsort argorithm from timsort.h
439  */
440 #ifdef WITH_TIM_SORT
441 #define SORT_NAME libxml_domnode
442 #define SORT_TYPE xmlNodePtr
443 /**
444  * wrap_cmp:
445  * @x: a node
446  * @y: another node
447  *
448  * Comparison function for the Timsort implementation
449  *
450  * Returns -2 in case of error -1 if first point < second point, 0 if
451  *         it's the same node, +1 otherwise
452  */
453 static
454 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
455 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
456     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
457     {
458         int res = xmlXPathCmpNodesExt(x, y);
459         return res == -2 ? res : -res;
460     }
461 #else
462     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
463     {
464         int res = xmlXPathCmpNodes(x, y);
465         return res == -2 ? res : -res;
466     }
467 #endif
468 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
469 #include "timsort.h"
470 #endif /* WITH_TIM_SORT */
471
472 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
473
474 /************************************************************************
475  *                                                                      *
476  *                      Floating point stuff                            *
477  *                                                                      *
478  ************************************************************************/
479
480 #ifndef TRIO_REPLACE_STDIO
481 #define TRIO_PUBLIC static
482 #endif
483 #include "trionan.c"
484
485 /*
486  * The lack of portability of this section of the libc is annoying !
487  */
488 double xmlXPathNAN = 0;
489 double xmlXPathPINF = 1;
490 double xmlXPathNINF = -1;
491 static double xmlXPathNZERO = 0; /* not exported from headers */
492 static int xmlXPathInitialized = 0;
493
494 /**
495  * xmlXPathInit:
496  *
497  * Initialize the XPath environment
498  */
499 void
500 xmlXPathInit(void) {
501     if (xmlXPathInitialized) return;
502
503     xmlXPathPINF = trio_pinf();
504     xmlXPathNINF = trio_ninf();
505     xmlXPathNAN = trio_nan();
506     xmlXPathNZERO = trio_nzero();
507
508     xmlXPathInitialized = 1;
509 }
510
511 /**
512  * xmlXPathIsNaN:
513  * @val:  a double value
514  *
515  * Provides a portable isnan() function to detect whether a double
516  * is a NotaNumber. Based on trio code
517  * http://sourceforge.net/projects/ctrio/
518  *
519  * Returns 1 if the value is a NaN, 0 otherwise
520  */
521 int
522 xmlXPathIsNaN(double val) {
523     return(trio_isnan(val));
524 }
525
526 /**
527  * xmlXPathIsInf:
528  * @val:  a double value
529  *
530  * Provides a portable isinf() function to detect whether a double
531  * is a +Infinite or -Infinite. Based on trio code
532  * http://sourceforge.net/projects/ctrio/
533  *
534  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
535  */
536 int
537 xmlXPathIsInf(double val) {
538     return(trio_isinf(val));
539 }
540
541 #endif /* SCHEMAS or XPATH */
542 #ifdef LIBXML_XPATH_ENABLED
543 /**
544  * xmlXPathGetSign:
545  * @val:  a double value
546  *
547  * Provides a portable function to detect the sign of a double
548  * Modified from trio code
549  * http://sourceforge.net/projects/ctrio/
550  *
551  * Returns 1 if the value is Negative, 0 if positive
552  */
553 static int
554 xmlXPathGetSign(double val) {
555     return(trio_signbit(val));
556 }
557
558
559 /*
560  * TODO: when compatibility allows remove all "fake node libxslt" strings
561  *       the test should just be name[0] = ' '
562  */
563 #ifdef DEBUG_XPATH_EXPRESSION
564 #define DEBUG_STEP
565 #define DEBUG_EXPR
566 #define DEBUG_EVAL_COUNTS
567 #endif
568
569 static xmlNs xmlXPathXMLNamespaceStruct = {
570     NULL,
571     XML_NAMESPACE_DECL,
572     XML_XML_NAMESPACE,
573     BAD_CAST "xml",
574     NULL,
575     NULL
576 };
577 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
578 #ifndef LIBXML_THREAD_ENABLED
579 /*
580  * Optimizer is disabled only when threaded apps are detected while
581  * the library ain't compiled for thread safety.
582  */
583 static int xmlXPathDisableOptimizer = 0;
584 #endif
585
586 /************************************************************************
587  *                                                                      *
588  *                      Error handling routines                         *
589  *                                                                      *
590  ************************************************************************/
591
592 /**
593  * XP_ERRORNULL:
594  * @X:  the error code
595  *
596  * Macro to raise an XPath error and return NULL.
597  */
598 #define XP_ERRORNULL(X)                                                 \
599     { xmlXPathErr(ctxt, X); return(NULL); }
600
601 /*
602  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
603  */
604 static const char *xmlXPathErrorMessages[] = {
605     "Ok\n",
606     "Number encoding\n",
607     "Unfinished literal\n",
608     "Start of literal\n",
609     "Expected $ for variable reference\n",
610     "Undefined variable\n",
611     "Invalid predicate\n",
612     "Invalid expression\n",
613     "Missing closing curly brace\n",
614     "Unregistered function\n",
615     "Invalid operand\n",
616     "Invalid type\n",
617     "Invalid number of arguments\n",
618     "Invalid context size\n",
619     "Invalid context position\n",
620     "Memory allocation error\n",
621     "Syntax error\n",
622     "Resource error\n",
623     "Sub resource error\n",
624     "Undefined namespace prefix\n",
625     "Encoding error\n",
626     "Char out of XML range\n",
627     "Invalid or incomplete context\n",
628     "Stack usage error\n",
629     "Forbidden variable\n",
630     "?? Unknown error ??\n"     /* Must be last in the list! */
631 };
632 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
633                    sizeof(xmlXPathErrorMessages[0])) - 1)
634 /**
635  * xmlXPathErrMemory:
636  * @ctxt:  an XPath context
637  * @extra:  extra informations
638  *
639  * Handle a redefinition of attribute error
640  */
641 static void
642 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
643 {
644     if (ctxt != NULL) {
645         if (extra) {
646             xmlChar buf[200];
647
648             xmlStrPrintf(buf, 200,
649                          "Memory allocation failed : %s\n",
650                          extra);
651             ctxt->lastError.message = (char *) xmlStrdup(buf);
652         } else {
653             ctxt->lastError.message = (char *)
654                xmlStrdup(BAD_CAST "Memory allocation failed\n");
655         }
656         ctxt->lastError.domain = XML_FROM_XPATH;
657         ctxt->lastError.code = XML_ERR_NO_MEMORY;
658         if (ctxt->error != NULL)
659             ctxt->error(ctxt->userData, &ctxt->lastError);
660     } else {
661         if (extra)
662             __xmlRaiseError(NULL, NULL, NULL,
663                             NULL, NULL, XML_FROM_XPATH,
664                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
665                             extra, NULL, NULL, 0, 0,
666                             "Memory allocation failed : %s\n", extra);
667         else
668             __xmlRaiseError(NULL, NULL, NULL,
669                             NULL, NULL, XML_FROM_XPATH,
670                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
671                             NULL, NULL, NULL, 0, 0,
672                             "Memory allocation failed\n");
673     }
674 }
675
676 /**
677  * xmlXPathPErrMemory:
678  * @ctxt:  an XPath parser context
679  * @extra:  extra informations
680  *
681  * Handle a redefinition of attribute error
682  */
683 static void
684 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
685 {
686     if (ctxt == NULL)
687         xmlXPathErrMemory(NULL, extra);
688     else {
689         ctxt->error = XPATH_MEMORY_ERROR;
690         xmlXPathErrMemory(ctxt->context, extra);
691     }
692 }
693
694 /**
695  * xmlXPathErr:
696  * @ctxt:  a XPath parser context
697  * @error:  the error code
698  *
699  * Handle an XPath error
700  */
701 void
702 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
703 {
704     if ((error < 0) || (error > MAXERRNO))
705         error = MAXERRNO;
706     if (ctxt == NULL) {
707         __xmlRaiseError(NULL, NULL, NULL,
708                         NULL, NULL, XML_FROM_XPATH,
709                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
710                         XML_ERR_ERROR, NULL, 0,
711                         NULL, NULL, NULL, 0, 0,
712                         "%s", xmlXPathErrorMessages[error]);
713         return;
714     }
715     ctxt->error = error;
716     if (ctxt->context == NULL) {
717         __xmlRaiseError(NULL, NULL, NULL,
718                         NULL, NULL, XML_FROM_XPATH,
719                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
720                         XML_ERR_ERROR, NULL, 0,
721                         (const char *) ctxt->base, NULL, NULL,
722                         ctxt->cur - ctxt->base, 0,
723                         "%s", xmlXPathErrorMessages[error]);
724         return;
725     }
726
727     /* cleanup current last error */
728     xmlResetError(&ctxt->context->lastError);
729
730     ctxt->context->lastError.domain = XML_FROM_XPATH;
731     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
732                            XPATH_EXPRESSION_OK;
733     ctxt->context->lastError.level = XML_ERR_ERROR;
734     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
735     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
736     ctxt->context->lastError.node = ctxt->context->debugNode;
737     if (ctxt->context->error != NULL) {
738         ctxt->context->error(ctxt->context->userData,
739                              &ctxt->context->lastError);
740     } else {
741         __xmlRaiseError(NULL, NULL, NULL,
742                         NULL, ctxt->context->debugNode, XML_FROM_XPATH,
743                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
744                         XML_ERR_ERROR, NULL, 0,
745                         (const char *) ctxt->base, NULL, NULL,
746                         ctxt->cur - ctxt->base, 0,
747                         "%s", xmlXPathErrorMessages[error]);
748     }
749
750 }
751
752 /**
753  * xmlXPatherror:
754  * @ctxt:  the XPath Parser context
755  * @file:  the file name
756  * @line:  the line number
757  * @no:  the error number
758  *
759  * Formats an error message.
760  */
761 void
762 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
763               int line ATTRIBUTE_UNUSED, int no) {
764     xmlXPathErr(ctxt, no);
765 }
766
767 /************************************************************************
768  *                                                                      *
769  *                      Utilities                                       *
770  *                                                                      *
771  ************************************************************************/
772
773 /**
774  * xsltPointerList:
775  *
776  * Pointer-list for various purposes.
777  */
778 typedef struct _xmlPointerList xmlPointerList;
779 typedef xmlPointerList *xmlPointerListPtr;
780 struct _xmlPointerList {
781     void **items;
782     int number;
783     int size;
784 };
785 /*
786 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
787 * and here, we should make the functions public.
788 */
789 static int
790 xmlPointerListAddSize(xmlPointerListPtr list,
791                        void *item,
792                        int initialSize)
793 {
794     if (list->items == NULL) {
795         if (initialSize <= 0)
796             initialSize = 1;
797         list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
798         if (list->items == NULL) {
799             xmlXPathErrMemory(NULL,
800                 "xmlPointerListCreate: allocating item\n");
801             return(-1);
802         }
803         list->number = 0;
804         list->size = initialSize;
805     } else if (list->size <= list->number) {
806         if (list->size > 50000000) {
807             xmlXPathErrMemory(NULL,
808                 "xmlPointerListAddSize: re-allocating item\n");
809             return(-1);
810         }
811         list->size *= 2;
812         list->items = (void **) xmlRealloc(list->items,
813             list->size * sizeof(void *));
814         if (list->items == NULL) {
815             xmlXPathErrMemory(NULL,
816                 "xmlPointerListAddSize: re-allocating item\n");
817             list->size = 0;
818             return(-1);
819         }
820     }
821     list->items[list->number++] = item;
822     return(0);
823 }
824
825 /**
826  * xsltPointerListCreate:
827  *
828  * Creates an xsltPointerList structure.
829  *
830  * Returns a xsltPointerList structure or NULL in case of an error.
831  */
832 static xmlPointerListPtr
833 xmlPointerListCreate(int initialSize)
834 {
835     xmlPointerListPtr ret;
836
837     ret = xmlMalloc(sizeof(xmlPointerList));
838     if (ret == NULL) {
839         xmlXPathErrMemory(NULL,
840             "xmlPointerListCreate: allocating item\n");
841         return (NULL);
842     }
843     memset(ret, 0, sizeof(xmlPointerList));
844     if (initialSize > 0) {
845         xmlPointerListAddSize(ret, NULL, initialSize);
846         ret->number = 0;
847     }
848     return (ret);
849 }
850
851 /**
852  * xsltPointerListFree:
853  *
854  * Frees the xsltPointerList structure. This does not free
855  * the content of the list.
856  */
857 static void
858 xmlPointerListFree(xmlPointerListPtr list)
859 {
860     if (list == NULL)
861         return;
862     if (list->items != NULL)
863         xmlFree(list->items);
864     xmlFree(list);
865 }
866
867 /************************************************************************
868  *                                                                      *
869  *                      Parser Types                                    *
870  *                                                                      *
871  ************************************************************************/
872
873 /*
874  * Types are private:
875  */
876
877 typedef enum {
878     XPATH_OP_END=0,
879     XPATH_OP_AND,
880     XPATH_OP_OR,
881     XPATH_OP_EQUAL,
882     XPATH_OP_CMP,
883     XPATH_OP_PLUS,
884     XPATH_OP_MULT,
885     XPATH_OP_UNION,
886     XPATH_OP_ROOT,
887     XPATH_OP_NODE,
888     XPATH_OP_RESET, /* 10 */
889     XPATH_OP_COLLECT,
890     XPATH_OP_VALUE, /* 12 */
891     XPATH_OP_VARIABLE,
892     XPATH_OP_FUNCTION,
893     XPATH_OP_ARG,
894     XPATH_OP_PREDICATE,
895     XPATH_OP_FILTER, /* 17 */
896     XPATH_OP_SORT /* 18 */
897 #ifdef LIBXML_XPTR_ENABLED
898     ,XPATH_OP_RANGETO
899 #endif
900 } xmlXPathOp;
901
902 typedef enum {
903     AXIS_ANCESTOR = 1,
904     AXIS_ANCESTOR_OR_SELF,
905     AXIS_ATTRIBUTE,
906     AXIS_CHILD,
907     AXIS_DESCENDANT,
908     AXIS_DESCENDANT_OR_SELF,
909     AXIS_FOLLOWING,
910     AXIS_FOLLOWING_SIBLING,
911     AXIS_NAMESPACE,
912     AXIS_PARENT,
913     AXIS_PRECEDING,
914     AXIS_PRECEDING_SIBLING,
915     AXIS_SELF
916 } xmlXPathAxisVal;
917
918 typedef enum {
919     NODE_TEST_NONE = 0,
920     NODE_TEST_TYPE = 1,
921     NODE_TEST_PI = 2,
922     NODE_TEST_ALL = 3,
923     NODE_TEST_NS = 4,
924     NODE_TEST_NAME = 5
925 } xmlXPathTestVal;
926
927 typedef enum {
928     NODE_TYPE_NODE = 0,
929     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
930     NODE_TYPE_TEXT = XML_TEXT_NODE,
931     NODE_TYPE_PI = XML_PI_NODE
932 } xmlXPathTypeVal;
933
934 typedef struct _xmlXPathStepOp xmlXPathStepOp;
935 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
936 struct _xmlXPathStepOp {
937     xmlXPathOp op;              /* The identifier of the operation */
938     int ch1;                    /* First child */
939     int ch2;                    /* Second child */
940     int value;
941     int value2;
942     int value3;
943     void *value4;
944     void *value5;
945     xmlXPathFunction cache;
946     void *cacheURI;
947 };
948
949 struct _xmlXPathCompExpr {
950     int nbStep;                 /* Number of steps in this expression */
951     int maxStep;                /* Maximum number of steps allocated */
952     xmlXPathStepOp *steps;      /* ops for computation of this expression */
953     int last;                   /* index of last step in expression */
954     xmlChar *expr;              /* the expression being computed */
955     xmlDictPtr dict;            /* the dictionary to use if any */
956 #ifdef DEBUG_EVAL_COUNTS
957     int nb;
958     xmlChar *string;
959 #endif
960 #ifdef XPATH_STREAMING
961     xmlPatternPtr stream;
962 #endif
963 };
964
965 /************************************************************************
966  *                                                                      *
967  *                      Forward declarations                            *
968  *                                                                      *
969  ************************************************************************/
970 static void
971 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
972 static void
973 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
974 static int
975 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
976                         xmlXPathStepOpPtr op, xmlNodePtr *first);
977 static int
978 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
979                             xmlXPathStepOpPtr op,
980                             int isPredicate);
981
982 /************************************************************************
983  *                                                                      *
984  *                      Parser Type functions                           *
985  *                                                                      *
986  ************************************************************************/
987
988 /**
989  * xmlXPathNewCompExpr:
990  *
991  * Create a new Xpath component
992  *
993  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
994  */
995 static xmlXPathCompExprPtr
996 xmlXPathNewCompExpr(void) {
997     xmlXPathCompExprPtr cur;
998
999     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1000     if (cur == NULL) {
1001         xmlXPathErrMemory(NULL, "allocating component\n");
1002         return(NULL);
1003     }
1004     memset(cur, 0, sizeof(xmlXPathCompExpr));
1005     cur->maxStep = 10;
1006     cur->nbStep = 0;
1007     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1008                                            sizeof(xmlXPathStepOp));
1009     if (cur->steps == NULL) {
1010         xmlXPathErrMemory(NULL, "allocating steps\n");
1011         xmlFree(cur);
1012         return(NULL);
1013     }
1014     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1015     cur->last = -1;
1016 #ifdef DEBUG_EVAL_COUNTS
1017     cur->nb = 0;
1018 #endif
1019     return(cur);
1020 }
1021
1022 /**
1023  * xmlXPathFreeCompExpr:
1024  * @comp:  an XPATH comp
1025  *
1026  * Free up the memory allocated by @comp
1027  */
1028 void
1029 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1030 {
1031     xmlXPathStepOpPtr op;
1032     int i;
1033
1034     if (comp == NULL)
1035         return;
1036     if (comp->dict == NULL) {
1037         for (i = 0; i < comp->nbStep; i++) {
1038             op = &comp->steps[i];
1039             if (op->value4 != NULL) {
1040                 if (op->op == XPATH_OP_VALUE)
1041                     xmlXPathFreeObject(op->value4);
1042                 else
1043                     xmlFree(op->value4);
1044             }
1045             if (op->value5 != NULL)
1046                 xmlFree(op->value5);
1047         }
1048     } else {
1049         for (i = 0; i < comp->nbStep; i++) {
1050             op = &comp->steps[i];
1051             if (op->value4 != NULL) {
1052                 if (op->op == XPATH_OP_VALUE)
1053                     xmlXPathFreeObject(op->value4);
1054             }
1055         }
1056         xmlDictFree(comp->dict);
1057     }
1058     if (comp->steps != NULL) {
1059         xmlFree(comp->steps);
1060     }
1061 #ifdef DEBUG_EVAL_COUNTS
1062     if (comp->string != NULL) {
1063         xmlFree(comp->string);
1064     }
1065 #endif
1066 #ifdef XPATH_STREAMING
1067     if (comp->stream != NULL) {
1068         xmlFreePatternList(comp->stream);
1069     }
1070 #endif
1071     if (comp->expr != NULL) {
1072         xmlFree(comp->expr);
1073     }
1074
1075     xmlFree(comp);
1076 }
1077
1078 /**
1079  * xmlXPathCompExprAdd:
1080  * @comp:  the compiled expression
1081  * @ch1: first child index
1082  * @ch2: second child index
1083  * @op:  an op
1084  * @value:  the first int value
1085  * @value2:  the second int value
1086  * @value3:  the third int value
1087  * @value4:  the first string value
1088  * @value5:  the second string value
1089  *
1090  * Add a step to an XPath Compiled Expression
1091  *
1092  * Returns -1 in case of failure, the index otherwise
1093  */
1094 static int
1095 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1096    xmlXPathOp op, int value,
1097    int value2, int value3, void *value4, void *value5) {
1098     if (comp->nbStep >= comp->maxStep) {
1099         xmlXPathStepOp *real;
1100
1101         if (comp->maxStep >= XPATH_MAX_STEPS) {
1102             xmlXPathErrMemory(NULL, "adding step\n");
1103             return(-1);
1104         }
1105         comp->maxStep *= 2;
1106         real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1107                                       comp->maxStep * sizeof(xmlXPathStepOp));
1108         if (real == NULL) {
1109             comp->maxStep /= 2;
1110             xmlXPathErrMemory(NULL, "adding step\n");
1111             return(-1);
1112         }
1113         comp->steps = real;
1114     }
1115     comp->last = comp->nbStep;
1116     comp->steps[comp->nbStep].ch1 = ch1;
1117     comp->steps[comp->nbStep].ch2 = ch2;
1118     comp->steps[comp->nbStep].op = op;
1119     comp->steps[comp->nbStep].value = value;
1120     comp->steps[comp->nbStep].value2 = value2;
1121     comp->steps[comp->nbStep].value3 = value3;
1122     if ((comp->dict != NULL) &&
1123         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1124          (op == XPATH_OP_COLLECT))) {
1125         if (value4 != NULL) {
1126             comp->steps[comp->nbStep].value4 = (xmlChar *)
1127                 (void *)xmlDictLookup(comp->dict, value4, -1);
1128             xmlFree(value4);
1129         } else
1130             comp->steps[comp->nbStep].value4 = NULL;
1131         if (value5 != NULL) {
1132             comp->steps[comp->nbStep].value5 = (xmlChar *)
1133                 (void *)xmlDictLookup(comp->dict, value5, -1);
1134             xmlFree(value5);
1135         } else
1136             comp->steps[comp->nbStep].value5 = NULL;
1137     } else {
1138         comp->steps[comp->nbStep].value4 = value4;
1139         comp->steps[comp->nbStep].value5 = value5;
1140     }
1141     comp->steps[comp->nbStep].cache = NULL;
1142     return(comp->nbStep++);
1143 }
1144
1145 /**
1146  * xmlXPathCompSwap:
1147  * @comp:  the compiled expression
1148  * @op: operation index
1149  *
1150  * Swaps 2 operations in the compiled expression
1151  */
1152 static void
1153 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1154     int tmp;
1155
1156 #ifndef LIBXML_THREAD_ENABLED
1157     /*
1158      * Since this manipulates possibly shared variables, this is
1159      * disabled if one detects that the library is used in a multithreaded
1160      * application
1161      */
1162     if (xmlXPathDisableOptimizer)
1163         return;
1164 #endif
1165
1166     tmp = op->ch1;
1167     op->ch1 = op->ch2;
1168     op->ch2 = tmp;
1169 }
1170
1171 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)       \
1172     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),                       \
1173                         (op), (val), (val2), (val3), (val4), (val5))
1174 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)                 \
1175     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,               \
1176                         (op), (val), (val2), (val3), (val4), (val5))
1177
1178 #define PUSH_LEAVE_EXPR(op, val, val2)                                  \
1179 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1180
1181 #define PUSH_UNARY_EXPR(op, ch, val, val2)                              \
1182 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1183
1184 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)                       \
1185 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),                     \
1186                         (val), (val2), 0 ,NULL ,NULL)
1187
1188 /************************************************************************
1189  *                                                                      *
1190  *              XPath object cache structures                           *
1191  *                                                                      *
1192  ************************************************************************/
1193
1194 /* #define XP_DEFAULT_CACHE_ON */
1195
1196 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1197
1198 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1199 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1200 struct _xmlXPathContextCache {
1201     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1202     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1203     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1204     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1205     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1206     int maxNodeset;
1207     int maxString;
1208     int maxBoolean;
1209     int maxNumber;
1210     int maxMisc;
1211 #ifdef XP_DEBUG_OBJ_USAGE
1212     int dbgCachedAll;
1213     int dbgCachedNodeset;
1214     int dbgCachedString;
1215     int dbgCachedBool;
1216     int dbgCachedNumber;
1217     int dbgCachedPoint;
1218     int dbgCachedRange;
1219     int dbgCachedLocset;
1220     int dbgCachedUsers;
1221     int dbgCachedXSLTTree;
1222     int dbgCachedUndefined;
1223
1224
1225     int dbgReusedAll;
1226     int dbgReusedNodeset;
1227     int dbgReusedString;
1228     int dbgReusedBool;
1229     int dbgReusedNumber;
1230     int dbgReusedPoint;
1231     int dbgReusedRange;
1232     int dbgReusedLocset;
1233     int dbgReusedUsers;
1234     int dbgReusedXSLTTree;
1235     int dbgReusedUndefined;
1236
1237 #endif
1238 };
1239
1240 /************************************************************************
1241  *                                                                      *
1242  *              Debugging related functions                             *
1243  *                                                                      *
1244  ************************************************************************/
1245
1246 #define STRANGE                                                 \
1247     xmlGenericError(xmlGenericErrorContext,                             \
1248             "Internal error at %s:%d\n",                                \
1249             __FILE__, __LINE__);
1250
1251 #ifdef LIBXML_DEBUG_ENABLED
1252 static void
1253 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1254     int i;
1255     char shift[100];
1256
1257     for (i = 0;((i < depth) && (i < 25));i++)
1258         shift[2 * i] = shift[2 * i + 1] = ' ';
1259     shift[2 * i] = shift[2 * i + 1] = 0;
1260     if (cur == NULL) {
1261         fprintf(output, "%s", shift);
1262         fprintf(output, "Node is NULL !\n");
1263         return;
1264
1265     }
1266
1267     if ((cur->type == XML_DOCUMENT_NODE) ||
1268              (cur->type == XML_HTML_DOCUMENT_NODE)) {
1269         fprintf(output, "%s", shift);
1270         fprintf(output, " /\n");
1271     } else if (cur->type == XML_ATTRIBUTE_NODE)
1272         xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1273     else
1274         xmlDebugDumpOneNode(output, cur, depth);
1275 }
1276 static void
1277 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1278     xmlNodePtr tmp;
1279     int i;
1280     char shift[100];
1281
1282     for (i = 0;((i < depth) && (i < 25));i++)
1283         shift[2 * i] = shift[2 * i + 1] = ' ';
1284     shift[2 * i] = shift[2 * i + 1] = 0;
1285     if (cur == NULL) {
1286         fprintf(output, "%s", shift);
1287         fprintf(output, "Node is NULL !\n");
1288         return;
1289
1290     }
1291
1292     while (cur != NULL) {
1293         tmp = cur;
1294         cur = cur->next;
1295         xmlDebugDumpOneNode(output, tmp, depth);
1296     }
1297 }
1298
1299 static void
1300 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1301     int i;
1302     char shift[100];
1303
1304     for (i = 0;((i < depth) && (i < 25));i++)
1305         shift[2 * i] = shift[2 * i + 1] = ' ';
1306     shift[2 * i] = shift[2 * i + 1] = 0;
1307
1308     if (cur == NULL) {
1309         fprintf(output, "%s", shift);
1310         fprintf(output, "NodeSet is NULL !\n");
1311         return;
1312
1313     }
1314
1315     if (cur != NULL) {
1316         fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1317         for (i = 0;i < cur->nodeNr;i++) {
1318             fprintf(output, "%s", shift);
1319             fprintf(output, "%d", i + 1);
1320             xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1321         }
1322     }
1323 }
1324
1325 static void
1326 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1327     int i;
1328     char shift[100];
1329
1330     for (i = 0;((i < depth) && (i < 25));i++)
1331         shift[2 * i] = shift[2 * i + 1] = ' ';
1332     shift[2 * i] = shift[2 * i + 1] = 0;
1333
1334     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1335         fprintf(output, "%s", shift);
1336         fprintf(output, "Value Tree is NULL !\n");
1337         return;
1338
1339     }
1340
1341     fprintf(output, "%s", shift);
1342     fprintf(output, "%d", i + 1);
1343     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1344 }
1345 #if defined(LIBXML_XPTR_ENABLED)
1346 static void
1347 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1348     int i;
1349     char shift[100];
1350
1351     for (i = 0;((i < depth) && (i < 25));i++)
1352         shift[2 * i] = shift[2 * i + 1] = ' ';
1353     shift[2 * i] = shift[2 * i + 1] = 0;
1354
1355     if (cur == NULL) {
1356         fprintf(output, "%s", shift);
1357         fprintf(output, "LocationSet is NULL !\n");
1358         return;
1359
1360     }
1361
1362     for (i = 0;i < cur->locNr;i++) {
1363         fprintf(output, "%s", shift);
1364         fprintf(output, "%d : ", i + 1);
1365         xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1366     }
1367 }
1368 #endif /* LIBXML_XPTR_ENABLED */
1369
1370 /**
1371  * xmlXPathDebugDumpObject:
1372  * @output:  the FILE * to dump the output
1373  * @cur:  the object to inspect
1374  * @depth:  indentation level
1375  *
1376  * Dump the content of the object for debugging purposes
1377  */
1378 void
1379 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1380     int i;
1381     char shift[100];
1382
1383     if (output == NULL) return;
1384
1385     for (i = 0;((i < depth) && (i < 25));i++)
1386         shift[2 * i] = shift[2 * i + 1] = ' ';
1387     shift[2 * i] = shift[2 * i + 1] = 0;
1388
1389
1390     fprintf(output, "%s", shift);
1391
1392     if (cur == NULL) {
1393         fprintf(output, "Object is empty (NULL)\n");
1394         return;
1395     }
1396     switch(cur->type) {
1397         case XPATH_UNDEFINED:
1398             fprintf(output, "Object is uninitialized\n");
1399             break;
1400         case XPATH_NODESET:
1401             fprintf(output, "Object is a Node Set :\n");
1402             xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1403             break;
1404         case XPATH_XSLT_TREE:
1405             fprintf(output, "Object is an XSLT value tree :\n");
1406             xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1407             break;
1408         case XPATH_BOOLEAN:
1409             fprintf(output, "Object is a Boolean : ");
1410             if (cur->boolval) fprintf(output, "true\n");
1411             else fprintf(output, "false\n");
1412             break;
1413         case XPATH_NUMBER:
1414             switch (xmlXPathIsInf(cur->floatval)) {
1415             case 1:
1416                 fprintf(output, "Object is a number : Infinity\n");
1417                 break;
1418             case -1:
1419                 fprintf(output, "Object is a number : -Infinity\n");
1420                 break;
1421             default:
1422                 if (xmlXPathIsNaN(cur->floatval)) {
1423                     fprintf(output, "Object is a number : NaN\n");
1424                 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1425                     fprintf(output, "Object is a number : 0\n");
1426                 } else {
1427                     fprintf(output, "Object is a number : %0g\n", cur->floatval);
1428                 }
1429             }
1430             break;
1431         case XPATH_STRING:
1432             fprintf(output, "Object is a string : ");
1433             xmlDebugDumpString(output, cur->stringval);
1434             fprintf(output, "\n");
1435             break;
1436         case XPATH_POINT:
1437             fprintf(output, "Object is a point : index %d in node", cur->index);
1438             xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1439             fprintf(output, "\n");
1440             break;
1441         case XPATH_RANGE:
1442             if ((cur->user2 == NULL) ||
1443                 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1444                 fprintf(output, "Object is a collapsed range :\n");
1445                 fprintf(output, "%s", shift);
1446                 if (cur->index >= 0)
1447                     fprintf(output, "index %d in ", cur->index);
1448                 fprintf(output, "node\n");
1449                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1450                                       depth + 1);
1451             } else  {
1452                 fprintf(output, "Object is a range :\n");
1453                 fprintf(output, "%s", shift);
1454                 fprintf(output, "From ");
1455                 if (cur->index >= 0)
1456                     fprintf(output, "index %d in ", cur->index);
1457                 fprintf(output, "node\n");
1458                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1459                                       depth + 1);
1460                 fprintf(output, "%s", shift);
1461                 fprintf(output, "To ");
1462                 if (cur->index2 >= 0)
1463                     fprintf(output, "index %d in ", cur->index2);
1464                 fprintf(output, "node\n");
1465                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1466                                       depth + 1);
1467                 fprintf(output, "\n");
1468             }
1469             break;
1470         case XPATH_LOCATIONSET:
1471 #if defined(LIBXML_XPTR_ENABLED)
1472             fprintf(output, "Object is a Location Set:\n");
1473             xmlXPathDebugDumpLocationSet(output,
1474                     (xmlLocationSetPtr) cur->user, depth);
1475 #endif
1476             break;
1477         case XPATH_USERS:
1478             fprintf(output, "Object is user defined\n");
1479             break;
1480     }
1481 }
1482
1483 static void
1484 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1485                              xmlXPathStepOpPtr op, int depth) {
1486     int i;
1487     char shift[100];
1488
1489     for (i = 0;((i < depth) && (i < 25));i++)
1490         shift[2 * i] = shift[2 * i + 1] = ' ';
1491     shift[2 * i] = shift[2 * i + 1] = 0;
1492
1493     fprintf(output, "%s", shift);
1494     if (op == NULL) {
1495         fprintf(output, "Step is NULL\n");
1496         return;
1497     }
1498     switch (op->op) {
1499         case XPATH_OP_END:
1500             fprintf(output, "END"); break;
1501         case XPATH_OP_AND:
1502             fprintf(output, "AND"); break;
1503         case XPATH_OP_OR:
1504             fprintf(output, "OR"); break;
1505         case XPATH_OP_EQUAL:
1506              if (op->value)
1507                  fprintf(output, "EQUAL =");
1508              else
1509                  fprintf(output, "EQUAL !=");
1510              break;
1511         case XPATH_OP_CMP:
1512              if (op->value)
1513                  fprintf(output, "CMP <");
1514              else
1515                  fprintf(output, "CMP >");
1516              if (!op->value2)
1517                  fprintf(output, "=");
1518              break;
1519         case XPATH_OP_PLUS:
1520              if (op->value == 0)
1521                  fprintf(output, "PLUS -");
1522              else if (op->value == 1)
1523                  fprintf(output, "PLUS +");
1524              else if (op->value == 2)
1525                  fprintf(output, "PLUS unary -");
1526              else if (op->value == 3)
1527                  fprintf(output, "PLUS unary - -");
1528              break;
1529         case XPATH_OP_MULT:
1530              if (op->value == 0)
1531                  fprintf(output, "MULT *");
1532              else if (op->value == 1)
1533                  fprintf(output, "MULT div");
1534              else
1535                  fprintf(output, "MULT mod");
1536              break;
1537         case XPATH_OP_UNION:
1538              fprintf(output, "UNION"); break;
1539         case XPATH_OP_ROOT:
1540              fprintf(output, "ROOT"); break;
1541         case XPATH_OP_NODE:
1542              fprintf(output, "NODE"); break;
1543         case XPATH_OP_RESET:
1544              fprintf(output, "RESET"); break;
1545         case XPATH_OP_SORT:
1546              fprintf(output, "SORT"); break;
1547         case XPATH_OP_COLLECT: {
1548             xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1549             xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1550             xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1551             const xmlChar *prefix = op->value4;
1552             const xmlChar *name = op->value5;
1553
1554             fprintf(output, "COLLECT ");
1555             switch (axis) {
1556                 case AXIS_ANCESTOR:
1557                     fprintf(output, " 'ancestors' "); break;
1558                 case AXIS_ANCESTOR_OR_SELF:
1559                     fprintf(output, " 'ancestors-or-self' "); break;
1560                 case AXIS_ATTRIBUTE:
1561                     fprintf(output, " 'attributes' "); break;
1562                 case AXIS_CHILD:
1563                     fprintf(output, " 'child' "); break;
1564                 case AXIS_DESCENDANT:
1565                     fprintf(output, " 'descendant' "); break;
1566                 case AXIS_DESCENDANT_OR_SELF:
1567                     fprintf(output, " 'descendant-or-self' "); break;
1568                 case AXIS_FOLLOWING:
1569                     fprintf(output, " 'following' "); break;
1570                 case AXIS_FOLLOWING_SIBLING:
1571                     fprintf(output, " 'following-siblings' "); break;
1572                 case AXIS_NAMESPACE:
1573                     fprintf(output, " 'namespace' "); break;
1574                 case AXIS_PARENT:
1575                     fprintf(output, " 'parent' "); break;
1576                 case AXIS_PRECEDING:
1577                     fprintf(output, " 'preceding' "); break;
1578                 case AXIS_PRECEDING_SIBLING:
1579                     fprintf(output, " 'preceding-sibling' "); break;
1580                 case AXIS_SELF:
1581                     fprintf(output, " 'self' "); break;
1582             }
1583             switch (test) {
1584                 case NODE_TEST_NONE:
1585                     fprintf(output, "'none' "); break;
1586                 case NODE_TEST_TYPE:
1587                     fprintf(output, "'type' "); break;
1588                 case NODE_TEST_PI:
1589                     fprintf(output, "'PI' "); break;
1590                 case NODE_TEST_ALL:
1591                     fprintf(output, "'all' "); break;
1592                 case NODE_TEST_NS:
1593                     fprintf(output, "'namespace' "); break;
1594                 case NODE_TEST_NAME:
1595                     fprintf(output, "'name' "); break;
1596             }
1597             switch (type) {
1598                 case NODE_TYPE_NODE:
1599                     fprintf(output, "'node' "); break;
1600                 case NODE_TYPE_COMMENT:
1601                     fprintf(output, "'comment' "); break;
1602                 case NODE_TYPE_TEXT:
1603                     fprintf(output, "'text' "); break;
1604                 case NODE_TYPE_PI:
1605                     fprintf(output, "'PI' "); break;
1606             }
1607             if (prefix != NULL)
1608                 fprintf(output, "%s:", prefix);
1609             if (name != NULL)
1610                 fprintf(output, "%s", (const char *) name);
1611             break;
1612
1613         }
1614         case XPATH_OP_VALUE: {
1615             xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1616
1617             fprintf(output, "ELEM ");
1618             xmlXPathDebugDumpObject(output, object, 0);
1619             goto finish;
1620         }
1621         case XPATH_OP_VARIABLE: {
1622             const xmlChar *prefix = op->value5;
1623             const xmlChar *name = op->value4;
1624
1625             if (prefix != NULL)
1626                 fprintf(output, "VARIABLE %s:%s", prefix, name);
1627             else
1628                 fprintf(output, "VARIABLE %s", name);
1629             break;
1630         }
1631         case XPATH_OP_FUNCTION: {
1632             int nbargs = op->value;
1633             const xmlChar *prefix = op->value5;
1634             const xmlChar *name = op->value4;
1635
1636             if (prefix != NULL)
1637                 fprintf(output, "FUNCTION %s:%s(%d args)",
1638                         prefix, name, nbargs);
1639             else
1640                 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1641             break;
1642         }
1643         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1644         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1645         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1646 #ifdef LIBXML_XPTR_ENABLED
1647         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1648 #endif
1649         default:
1650         fprintf(output, "UNKNOWN %d\n", op->op); return;
1651     }
1652     fprintf(output, "\n");
1653 finish:
1654     if (op->ch1 >= 0)
1655         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1656     if (op->ch2 >= 0)
1657         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1658 }
1659
1660 /**
1661  * xmlXPathDebugDumpCompExpr:
1662  * @output:  the FILE * for the output
1663  * @comp:  the precompiled XPath expression
1664  * @depth:  the indentation level.
1665  *
1666  * Dumps the tree of the compiled XPath expression.
1667  */
1668 void
1669 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1670                           int depth) {
1671     int i;
1672     char shift[100];
1673
1674     if ((output == NULL) || (comp == NULL)) return;
1675
1676     for (i = 0;((i < depth) && (i < 25));i++)
1677         shift[2 * i] = shift[2 * i + 1] = ' ';
1678     shift[2 * i] = shift[2 * i + 1] = 0;
1679
1680     fprintf(output, "%s", shift);
1681
1682 #ifdef XPATH_STREAMING
1683     if (comp->stream) {
1684         fprintf(output, "Streaming Expression\n");
1685     } else
1686 #endif
1687     {
1688         fprintf(output, "Compiled Expression : %d elements\n",
1689                 comp->nbStep);
1690         i = comp->last;
1691         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1692     }
1693 }
1694
1695 #ifdef XP_DEBUG_OBJ_USAGE
1696
1697 /*
1698 * XPath object usage related debugging variables.
1699 */
1700 static int xmlXPathDebugObjCounterUndefined = 0;
1701 static int xmlXPathDebugObjCounterNodeset = 0;
1702 static int xmlXPathDebugObjCounterBool = 0;
1703 static int xmlXPathDebugObjCounterNumber = 0;
1704 static int xmlXPathDebugObjCounterString = 0;
1705 static int xmlXPathDebugObjCounterPoint = 0;
1706 static int xmlXPathDebugObjCounterRange = 0;
1707 static int xmlXPathDebugObjCounterLocset = 0;
1708 static int xmlXPathDebugObjCounterUsers = 0;
1709 static int xmlXPathDebugObjCounterXSLTTree = 0;
1710 static int xmlXPathDebugObjCounterAll = 0;
1711
1712 static int xmlXPathDebugObjTotalUndefined = 0;
1713 static int xmlXPathDebugObjTotalNodeset = 0;
1714 static int xmlXPathDebugObjTotalBool = 0;
1715 static int xmlXPathDebugObjTotalNumber = 0;
1716 static int xmlXPathDebugObjTotalString = 0;
1717 static int xmlXPathDebugObjTotalPoint = 0;
1718 static int xmlXPathDebugObjTotalRange = 0;
1719 static int xmlXPathDebugObjTotalLocset = 0;
1720 static int xmlXPathDebugObjTotalUsers = 0;
1721 static int xmlXPathDebugObjTotalXSLTTree = 0;
1722 static int xmlXPathDebugObjTotalAll = 0;
1723
1724 static int xmlXPathDebugObjMaxUndefined = 0;
1725 static int xmlXPathDebugObjMaxNodeset = 0;
1726 static int xmlXPathDebugObjMaxBool = 0;
1727 static int xmlXPathDebugObjMaxNumber = 0;
1728 static int xmlXPathDebugObjMaxString = 0;
1729 static int xmlXPathDebugObjMaxPoint = 0;
1730 static int xmlXPathDebugObjMaxRange = 0;
1731 static int xmlXPathDebugObjMaxLocset = 0;
1732 static int xmlXPathDebugObjMaxUsers = 0;
1733 static int xmlXPathDebugObjMaxXSLTTree = 0;
1734 static int xmlXPathDebugObjMaxAll = 0;
1735
1736 /* REVISIT TODO: Make this static when committing */
1737 static void
1738 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1739 {
1740     if (ctxt != NULL) {
1741         if (ctxt->cache != NULL) {
1742             xmlXPathContextCachePtr cache =
1743                 (xmlXPathContextCachePtr) ctxt->cache;
1744
1745             cache->dbgCachedAll = 0;
1746             cache->dbgCachedNodeset = 0;
1747             cache->dbgCachedString = 0;
1748             cache->dbgCachedBool = 0;
1749             cache->dbgCachedNumber = 0;
1750             cache->dbgCachedPoint = 0;
1751             cache->dbgCachedRange = 0;
1752             cache->dbgCachedLocset = 0;
1753             cache->dbgCachedUsers = 0;
1754             cache->dbgCachedXSLTTree = 0;
1755             cache->dbgCachedUndefined = 0;
1756
1757             cache->dbgReusedAll = 0;
1758             cache->dbgReusedNodeset = 0;
1759             cache->dbgReusedString = 0;
1760             cache->dbgReusedBool = 0;
1761             cache->dbgReusedNumber = 0;
1762             cache->dbgReusedPoint = 0;
1763             cache->dbgReusedRange = 0;
1764             cache->dbgReusedLocset = 0;
1765             cache->dbgReusedUsers = 0;
1766             cache->dbgReusedXSLTTree = 0;
1767             cache->dbgReusedUndefined = 0;
1768         }
1769     }
1770
1771     xmlXPathDebugObjCounterUndefined = 0;
1772     xmlXPathDebugObjCounterNodeset = 0;
1773     xmlXPathDebugObjCounterBool = 0;
1774     xmlXPathDebugObjCounterNumber = 0;
1775     xmlXPathDebugObjCounterString = 0;
1776     xmlXPathDebugObjCounterPoint = 0;
1777     xmlXPathDebugObjCounterRange = 0;
1778     xmlXPathDebugObjCounterLocset = 0;
1779     xmlXPathDebugObjCounterUsers = 0;
1780     xmlXPathDebugObjCounterXSLTTree = 0;
1781     xmlXPathDebugObjCounterAll = 0;
1782
1783     xmlXPathDebugObjTotalUndefined = 0;
1784     xmlXPathDebugObjTotalNodeset = 0;
1785     xmlXPathDebugObjTotalBool = 0;
1786     xmlXPathDebugObjTotalNumber = 0;
1787     xmlXPathDebugObjTotalString = 0;
1788     xmlXPathDebugObjTotalPoint = 0;
1789     xmlXPathDebugObjTotalRange = 0;
1790     xmlXPathDebugObjTotalLocset = 0;
1791     xmlXPathDebugObjTotalUsers = 0;
1792     xmlXPathDebugObjTotalXSLTTree = 0;
1793     xmlXPathDebugObjTotalAll = 0;
1794
1795     xmlXPathDebugObjMaxUndefined = 0;
1796     xmlXPathDebugObjMaxNodeset = 0;
1797     xmlXPathDebugObjMaxBool = 0;
1798     xmlXPathDebugObjMaxNumber = 0;
1799     xmlXPathDebugObjMaxString = 0;
1800     xmlXPathDebugObjMaxPoint = 0;
1801     xmlXPathDebugObjMaxRange = 0;
1802     xmlXPathDebugObjMaxLocset = 0;
1803     xmlXPathDebugObjMaxUsers = 0;
1804     xmlXPathDebugObjMaxXSLTTree = 0;
1805     xmlXPathDebugObjMaxAll = 0;
1806
1807 }
1808
1809 static void
1810 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1811                               xmlXPathObjectType objType)
1812 {
1813     int isCached = 0;
1814
1815     if (ctxt != NULL) {
1816         if (ctxt->cache != NULL) {
1817             xmlXPathContextCachePtr cache =
1818                 (xmlXPathContextCachePtr) ctxt->cache;
1819
1820             isCached = 1;
1821
1822             cache->dbgReusedAll++;
1823             switch (objType) {
1824                 case XPATH_UNDEFINED:
1825                     cache->dbgReusedUndefined++;
1826                     break;
1827                 case XPATH_NODESET:
1828                     cache->dbgReusedNodeset++;
1829                     break;
1830                 case XPATH_BOOLEAN:
1831                     cache->dbgReusedBool++;
1832                     break;
1833                 case XPATH_NUMBER:
1834                     cache->dbgReusedNumber++;
1835                     break;
1836                 case XPATH_STRING:
1837                     cache->dbgReusedString++;
1838                     break;
1839                 case XPATH_POINT:
1840                     cache->dbgReusedPoint++;
1841                     break;
1842                 case XPATH_RANGE:
1843                     cache->dbgReusedRange++;
1844                     break;
1845                 case XPATH_LOCATIONSET:
1846                     cache->dbgReusedLocset++;
1847                     break;
1848                 case XPATH_USERS:
1849                     cache->dbgReusedUsers++;
1850                     break;
1851                 case XPATH_XSLT_TREE:
1852                     cache->dbgReusedXSLTTree++;
1853                     break;
1854                 default:
1855                     break;
1856             }
1857         }
1858     }
1859
1860     switch (objType) {
1861         case XPATH_UNDEFINED:
1862             if (! isCached)
1863                 xmlXPathDebugObjTotalUndefined++;
1864             xmlXPathDebugObjCounterUndefined++;
1865             if (xmlXPathDebugObjCounterUndefined >
1866                 xmlXPathDebugObjMaxUndefined)
1867                 xmlXPathDebugObjMaxUndefined =
1868                     xmlXPathDebugObjCounterUndefined;
1869             break;
1870         case XPATH_NODESET:
1871             if (! isCached)
1872                 xmlXPathDebugObjTotalNodeset++;
1873             xmlXPathDebugObjCounterNodeset++;
1874             if (xmlXPathDebugObjCounterNodeset >
1875                 xmlXPathDebugObjMaxNodeset)
1876                 xmlXPathDebugObjMaxNodeset =
1877                     xmlXPathDebugObjCounterNodeset;
1878             break;
1879         case XPATH_BOOLEAN:
1880             if (! isCached)
1881                 xmlXPathDebugObjTotalBool++;
1882             xmlXPathDebugObjCounterBool++;
1883             if (xmlXPathDebugObjCounterBool >
1884                 xmlXPathDebugObjMaxBool)
1885                 xmlXPathDebugObjMaxBool =
1886                     xmlXPathDebugObjCounterBool;
1887             break;
1888         case XPATH_NUMBER:
1889             if (! isCached)
1890                 xmlXPathDebugObjTotalNumber++;
1891             xmlXPathDebugObjCounterNumber++;
1892             if (xmlXPathDebugObjCounterNumber >
1893                 xmlXPathDebugObjMaxNumber)
1894                 xmlXPathDebugObjMaxNumber =
1895                     xmlXPathDebugObjCounterNumber;
1896             break;
1897         case XPATH_STRING:
1898             if (! isCached)
1899                 xmlXPathDebugObjTotalString++;
1900             xmlXPathDebugObjCounterString++;
1901             if (xmlXPathDebugObjCounterString >
1902                 xmlXPathDebugObjMaxString)
1903                 xmlXPathDebugObjMaxString =
1904                     xmlXPathDebugObjCounterString;
1905             break;
1906         case XPATH_POINT:
1907             if (! isCached)
1908                 xmlXPathDebugObjTotalPoint++;
1909             xmlXPathDebugObjCounterPoint++;
1910             if (xmlXPathDebugObjCounterPoint >
1911                 xmlXPathDebugObjMaxPoint)
1912                 xmlXPathDebugObjMaxPoint =
1913                     xmlXPathDebugObjCounterPoint;
1914             break;
1915         case XPATH_RANGE:
1916             if (! isCached)
1917                 xmlXPathDebugObjTotalRange++;
1918             xmlXPathDebugObjCounterRange++;
1919             if (xmlXPathDebugObjCounterRange >
1920                 xmlXPathDebugObjMaxRange)
1921                 xmlXPathDebugObjMaxRange =
1922                     xmlXPathDebugObjCounterRange;
1923             break;
1924         case XPATH_LOCATIONSET:
1925             if (! isCached)
1926                 xmlXPathDebugObjTotalLocset++;
1927             xmlXPathDebugObjCounterLocset++;
1928             if (xmlXPathDebugObjCounterLocset >
1929                 xmlXPathDebugObjMaxLocset)
1930                 xmlXPathDebugObjMaxLocset =
1931                     xmlXPathDebugObjCounterLocset;
1932             break;
1933         case XPATH_USERS:
1934             if (! isCached)
1935                 xmlXPathDebugObjTotalUsers++;
1936             xmlXPathDebugObjCounterUsers++;
1937             if (xmlXPathDebugObjCounterUsers >
1938                 xmlXPathDebugObjMaxUsers)
1939                 xmlXPathDebugObjMaxUsers =
1940                     xmlXPathDebugObjCounterUsers;
1941             break;
1942         case XPATH_XSLT_TREE:
1943             if (! isCached)
1944                 xmlXPathDebugObjTotalXSLTTree++;
1945             xmlXPathDebugObjCounterXSLTTree++;
1946             if (xmlXPathDebugObjCounterXSLTTree >
1947                 xmlXPathDebugObjMaxXSLTTree)
1948                 xmlXPathDebugObjMaxXSLTTree =
1949                     xmlXPathDebugObjCounterXSLTTree;
1950             break;
1951         default:
1952             break;
1953     }
1954     if (! isCached)
1955         xmlXPathDebugObjTotalAll++;
1956     xmlXPathDebugObjCounterAll++;
1957     if (xmlXPathDebugObjCounterAll >
1958         xmlXPathDebugObjMaxAll)
1959         xmlXPathDebugObjMaxAll =
1960             xmlXPathDebugObjCounterAll;
1961 }
1962
1963 static void
1964 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1965                               xmlXPathObjectType objType)
1966 {
1967     int isCached = 0;
1968
1969     if (ctxt != NULL) {
1970         if (ctxt->cache != NULL) {
1971             xmlXPathContextCachePtr cache =
1972                 (xmlXPathContextCachePtr) ctxt->cache;
1973
1974             isCached = 1;
1975
1976             cache->dbgCachedAll++;
1977             switch (objType) {
1978                 case XPATH_UNDEFINED:
1979                     cache->dbgCachedUndefined++;
1980                     break;
1981                 case XPATH_NODESET:
1982                     cache->dbgCachedNodeset++;
1983                     break;
1984                 case XPATH_BOOLEAN:
1985                     cache->dbgCachedBool++;
1986                     break;
1987                 case XPATH_NUMBER:
1988                     cache->dbgCachedNumber++;
1989                     break;
1990                 case XPATH_STRING:
1991                     cache->dbgCachedString++;
1992                     break;
1993                 case XPATH_POINT:
1994                     cache->dbgCachedPoint++;
1995                     break;
1996                 case XPATH_RANGE:
1997                     cache->dbgCachedRange++;
1998                     break;
1999                 case XPATH_LOCATIONSET:
2000                     cache->dbgCachedLocset++;
2001                     break;
2002                 case XPATH_USERS:
2003                     cache->dbgCachedUsers++;
2004                     break;
2005                 case XPATH_XSLT_TREE:
2006                     cache->dbgCachedXSLTTree++;
2007                     break;
2008                 default:
2009                     break;
2010             }
2011
2012         }
2013     }
2014     switch (objType) {
2015         case XPATH_UNDEFINED:
2016             xmlXPathDebugObjCounterUndefined--;
2017             break;
2018         case XPATH_NODESET:
2019             xmlXPathDebugObjCounterNodeset--;
2020             break;
2021         case XPATH_BOOLEAN:
2022             xmlXPathDebugObjCounterBool--;
2023             break;
2024         case XPATH_NUMBER:
2025             xmlXPathDebugObjCounterNumber--;
2026             break;
2027         case XPATH_STRING:
2028             xmlXPathDebugObjCounterString--;
2029             break;
2030         case XPATH_POINT:
2031             xmlXPathDebugObjCounterPoint--;
2032             break;
2033         case XPATH_RANGE:
2034             xmlXPathDebugObjCounterRange--;
2035             break;
2036         case XPATH_LOCATIONSET:
2037             xmlXPathDebugObjCounterLocset--;
2038             break;
2039         case XPATH_USERS:
2040             xmlXPathDebugObjCounterUsers--;
2041             break;
2042         case XPATH_XSLT_TREE:
2043             xmlXPathDebugObjCounterXSLTTree--;
2044             break;
2045         default:
2046             break;
2047     }
2048     xmlXPathDebugObjCounterAll--;
2049 }
2050
2051 /* REVISIT TODO: Make this static when committing */
2052 static void
2053 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2054 {
2055     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2056         reqXSLTTree, reqUndefined;
2057     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2058         caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2059     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2060         reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2061     int leftObjs = xmlXPathDebugObjCounterAll;
2062
2063     reqAll = xmlXPathDebugObjTotalAll;
2064     reqNodeset = xmlXPathDebugObjTotalNodeset;
2065     reqString = xmlXPathDebugObjTotalString;
2066     reqBool = xmlXPathDebugObjTotalBool;
2067     reqNumber = xmlXPathDebugObjTotalNumber;
2068     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2069     reqUndefined = xmlXPathDebugObjTotalUndefined;
2070
2071     printf("# XPath object usage:\n");
2072
2073     if (ctxt != NULL) {
2074         if (ctxt->cache != NULL) {
2075             xmlXPathContextCachePtr cache =
2076                 (xmlXPathContextCachePtr) ctxt->cache;
2077
2078             reAll = cache->dbgReusedAll;
2079             reqAll += reAll;
2080             reNodeset = cache->dbgReusedNodeset;
2081             reqNodeset += reNodeset;
2082             reString = cache->dbgReusedString;
2083             reqString += reString;
2084             reBool = cache->dbgReusedBool;
2085             reqBool += reBool;
2086             reNumber = cache->dbgReusedNumber;
2087             reqNumber += reNumber;
2088             reXSLTTree = cache->dbgReusedXSLTTree;
2089             reqXSLTTree += reXSLTTree;
2090             reUndefined = cache->dbgReusedUndefined;
2091             reqUndefined += reUndefined;
2092
2093             caAll = cache->dbgCachedAll;
2094             caBool = cache->dbgCachedBool;
2095             caNodeset = cache->dbgCachedNodeset;
2096             caString = cache->dbgCachedString;
2097             caNumber = cache->dbgCachedNumber;
2098             caXSLTTree = cache->dbgCachedXSLTTree;
2099             caUndefined = cache->dbgCachedUndefined;
2100
2101             if (cache->nodesetObjs)
2102                 leftObjs -= cache->nodesetObjs->number;
2103             if (cache->stringObjs)
2104                 leftObjs -= cache->stringObjs->number;
2105             if (cache->booleanObjs)
2106                 leftObjs -= cache->booleanObjs->number;
2107             if (cache->numberObjs)
2108                 leftObjs -= cache->numberObjs->number;
2109             if (cache->miscObjs)
2110                 leftObjs -= cache->miscObjs->number;
2111         }
2112     }
2113
2114     printf("# all\n");
2115     printf("#   total  : %d\n", reqAll);
2116     printf("#   left  : %d\n", leftObjs);
2117     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2118     printf("#   reused : %d\n", reAll);
2119     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2120
2121     printf("# node-sets\n");
2122     printf("#   total  : %d\n", reqNodeset);
2123     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2124     printf("#   reused : %d\n", reNodeset);
2125     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2126
2127     printf("# strings\n");
2128     printf("#   total  : %d\n", reqString);
2129     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2130     printf("#   reused : %d\n", reString);
2131     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2132
2133     printf("# booleans\n");
2134     printf("#   total  : %d\n", reqBool);
2135     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2136     printf("#   reused : %d\n", reBool);
2137     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2138
2139     printf("# numbers\n");
2140     printf("#   total  : %d\n", reqNumber);
2141     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2142     printf("#   reused : %d\n", reNumber);
2143     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2144
2145     printf("# XSLT result tree fragments\n");
2146     printf("#   total  : %d\n", reqXSLTTree);
2147     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2148     printf("#   reused : %d\n", reXSLTTree);
2149     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2150
2151     printf("# undefined\n");
2152     printf("#   total  : %d\n", reqUndefined);
2153     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2154     printf("#   reused : %d\n", reUndefined);
2155     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2156
2157 }
2158
2159 #endif /* XP_DEBUG_OBJ_USAGE */
2160
2161 #endif /* LIBXML_DEBUG_ENABLED */
2162
2163 /************************************************************************
2164  *                                                                      *
2165  *                      XPath object caching                            *
2166  *                                                                      *
2167  ************************************************************************/
2168
2169 /**
2170  * xmlXPathNewCache:
2171  *
2172  * Create a new object cache
2173  *
2174  * Returns the xmlXPathCache just allocated.
2175  */
2176 static xmlXPathContextCachePtr
2177 xmlXPathNewCache(void)
2178 {
2179     xmlXPathContextCachePtr ret;
2180
2181     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2182     if (ret == NULL) {
2183         xmlXPathErrMemory(NULL, "creating object cache\n");
2184         return(NULL);
2185     }
2186     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2187     ret->maxNodeset = 100;
2188     ret->maxString = 100;
2189     ret->maxBoolean = 100;
2190     ret->maxNumber = 100;
2191     ret->maxMisc = 100;
2192     return(ret);
2193 }
2194
2195 static void
2196 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2197 {
2198     int i;
2199     xmlXPathObjectPtr obj;
2200
2201     if (list == NULL)
2202         return;
2203
2204     for (i = 0; i < list->number; i++) {
2205         obj = list->items[i];
2206         /*
2207         * Note that it is already assured that we don't need to
2208         * look out for namespace nodes in the node-set.
2209         */
2210         if (obj->nodesetval != NULL) {
2211             if (obj->nodesetval->nodeTab != NULL)
2212                 xmlFree(obj->nodesetval->nodeTab);
2213             xmlFree(obj->nodesetval);
2214         }
2215         xmlFree(obj);
2216 #ifdef XP_DEBUG_OBJ_USAGE
2217         xmlXPathDebugObjCounterAll--;
2218 #endif
2219     }
2220     xmlPointerListFree(list);
2221 }
2222
2223 static void
2224 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2225 {
2226     if (cache == NULL)
2227         return;
2228     if (cache->nodesetObjs)
2229         xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2230     if (cache->stringObjs)
2231         xmlXPathCacheFreeObjectList(cache->stringObjs);
2232     if (cache->booleanObjs)
2233         xmlXPathCacheFreeObjectList(cache->booleanObjs);
2234     if (cache->numberObjs)
2235         xmlXPathCacheFreeObjectList(cache->numberObjs);
2236     if (cache->miscObjs)
2237         xmlXPathCacheFreeObjectList(cache->miscObjs);
2238     xmlFree(cache);
2239 }
2240
2241 /**
2242  * xmlXPathContextSetCache:
2243  *
2244  * @ctxt:  the XPath context
2245  * @active: enables/disables (creates/frees) the cache
2246  * @value: a value with semantics dependant on @options
2247  * @options: options (currently only the value 0 is used)
2248  *
2249  * Creates/frees an object cache on the XPath context.
2250  * If activates XPath objects (xmlXPathObject) will be cached internally
2251  * to be reused.
2252  * @options:
2253  *   0: This will set the XPath object caching:
2254  *      @value:
2255  *        This will set the maximum number of XPath objects
2256  *        to be cached per slot
2257  *        There are 5 slots for: node-set, string, number, boolean, and
2258  *        misc objects. Use <0 for the default number (100).
2259  *   Other values for @options have currently no effect.
2260  *
2261  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2262  */
2263 int
2264 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2265                         int active,
2266                         int value,
2267                         int options)
2268 {
2269     if (ctxt == NULL)
2270         return(-1);
2271     if (active) {
2272         xmlXPathContextCachePtr cache;
2273
2274         if (ctxt->cache == NULL) {
2275             ctxt->cache = xmlXPathNewCache();
2276             if (ctxt->cache == NULL)
2277                 return(-1);
2278         }
2279         cache = (xmlXPathContextCachePtr) ctxt->cache;
2280         if (options == 0) {
2281             if (value < 0)
2282                 value = 100;
2283             cache->maxNodeset = value;
2284             cache->maxString = value;
2285             cache->maxNumber = value;
2286             cache->maxBoolean = value;
2287             cache->maxMisc = value;
2288         }
2289     } else if (ctxt->cache != NULL) {
2290         xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2291         ctxt->cache = NULL;
2292     }
2293     return(0);
2294 }
2295
2296 /**
2297  * xmlXPathCacheWrapNodeSet:
2298  * @ctxt: the XPath context
2299  * @val:  the NodePtr value
2300  *
2301  * This is the cached version of xmlXPathWrapNodeSet().
2302  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2303  *
2304  * Returns the created or reused object.
2305  */
2306 static xmlXPathObjectPtr
2307 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2308 {
2309     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2310         xmlXPathContextCachePtr cache =
2311             (xmlXPathContextCachePtr) ctxt->cache;
2312
2313         if ((cache->miscObjs != NULL) &&
2314             (cache->miscObjs->number != 0))
2315         {
2316             xmlXPathObjectPtr ret;
2317
2318             ret = (xmlXPathObjectPtr)
2319                 cache->miscObjs->items[--cache->miscObjs->number];
2320             ret->type = XPATH_NODESET;
2321             ret->nodesetval = val;
2322 #ifdef XP_DEBUG_OBJ_USAGE
2323             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2324 #endif
2325             return(ret);
2326         }
2327     }
2328
2329     return(xmlXPathWrapNodeSet(val));
2330
2331 }
2332
2333 /**
2334  * xmlXPathCacheWrapString:
2335  * @ctxt: the XPath context
2336  * @val:  the xmlChar * value
2337  *
2338  * This is the cached version of xmlXPathWrapString().
2339  * Wraps the @val string into an XPath object.
2340  *
2341  * Returns the created or reused object.
2342  */
2343 static xmlXPathObjectPtr
2344 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2345 {
2346     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2347         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2348
2349         if ((cache->stringObjs != NULL) &&
2350             (cache->stringObjs->number != 0))
2351         {
2352
2353             xmlXPathObjectPtr ret;
2354
2355             ret = (xmlXPathObjectPtr)
2356                 cache->stringObjs->items[--cache->stringObjs->number];
2357             ret->type = XPATH_STRING;
2358             ret->stringval = val;
2359 #ifdef XP_DEBUG_OBJ_USAGE
2360             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2361 #endif
2362             return(ret);
2363         } else if ((cache->miscObjs != NULL) &&
2364             (cache->miscObjs->number != 0))
2365         {
2366             xmlXPathObjectPtr ret;
2367             /*
2368             * Fallback to misc-cache.
2369             */
2370             ret = (xmlXPathObjectPtr)
2371                 cache->miscObjs->items[--cache->miscObjs->number];
2372
2373             ret->type = XPATH_STRING;
2374             ret->stringval = val;
2375 #ifdef XP_DEBUG_OBJ_USAGE
2376             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2377 #endif
2378             return(ret);
2379         }
2380     }
2381     return(xmlXPathWrapString(val));
2382 }
2383
2384 /**
2385  * xmlXPathCacheNewNodeSet:
2386  * @ctxt: the XPath context
2387  * @val:  the NodePtr value
2388  *
2389  * This is the cached version of xmlXPathNewNodeSet().
2390  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2391  * it with the single Node @val
2392  *
2393  * Returns the created or reused object.
2394  */
2395 static xmlXPathObjectPtr
2396 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2397 {
2398     if ((ctxt != NULL) && (ctxt->cache)) {
2399         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2400
2401         if ((cache->nodesetObjs != NULL) &&
2402             (cache->nodesetObjs->number != 0))
2403         {
2404             xmlXPathObjectPtr ret;
2405             /*
2406             * Use the nodset-cache.
2407             */
2408             ret = (xmlXPathObjectPtr)
2409                 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2410             ret->type = XPATH_NODESET;
2411             ret->boolval = 0;
2412             if (val) {
2413                 if ((ret->nodesetval->nodeMax == 0) ||
2414                     (val->type == XML_NAMESPACE_DECL))
2415                 {
2416                     xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2417                 } else {
2418                     ret->nodesetval->nodeTab[0] = val;
2419                     ret->nodesetval->nodeNr = 1;
2420                 }
2421             }
2422 #ifdef XP_DEBUG_OBJ_USAGE
2423             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2424 #endif
2425             return(ret);
2426         } else if ((cache->miscObjs != NULL) &&
2427             (cache->miscObjs->number != 0))
2428         {
2429             xmlXPathObjectPtr ret;
2430             /*
2431             * Fallback to misc-cache.
2432             */
2433
2434             ret = (xmlXPathObjectPtr)
2435                 cache->miscObjs->items[--cache->miscObjs->number];
2436
2437             ret->type = XPATH_NODESET;
2438             ret->boolval = 0;
2439             ret->nodesetval = xmlXPathNodeSetCreate(val);
2440             if (ret->nodesetval == NULL) {
2441                 ctxt->lastError.domain = XML_FROM_XPATH;
2442                 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2443                 return(NULL);
2444             }
2445 #ifdef XP_DEBUG_OBJ_USAGE
2446             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2447 #endif
2448             return(ret);
2449         }
2450     }
2451     return(xmlXPathNewNodeSet(val));
2452 }
2453
2454 /**
2455  * xmlXPathCacheNewCString:
2456  * @ctxt: the XPath context
2457  * @val:  the char * value
2458  *
2459  * This is the cached version of xmlXPathNewCString().
2460  * Acquire an xmlXPathObjectPtr of type string and of value @val
2461  *
2462  * Returns the created or reused object.
2463  */
2464 static xmlXPathObjectPtr
2465 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2466 {
2467     if ((ctxt != NULL) && (ctxt->cache)) {
2468         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2469
2470         if ((cache->stringObjs != NULL) &&
2471             (cache->stringObjs->number != 0))
2472         {
2473             xmlXPathObjectPtr ret;
2474
2475             ret = (xmlXPathObjectPtr)
2476                 cache->stringObjs->items[--cache->stringObjs->number];
2477
2478             ret->type = XPATH_STRING;
2479             ret->stringval = xmlStrdup(BAD_CAST val);
2480 #ifdef XP_DEBUG_OBJ_USAGE
2481             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2482 #endif
2483             return(ret);
2484         } else if ((cache->miscObjs != NULL) &&
2485             (cache->miscObjs->number != 0))
2486         {
2487             xmlXPathObjectPtr ret;
2488
2489             ret = (xmlXPathObjectPtr)
2490                 cache->miscObjs->items[--cache->miscObjs->number];
2491
2492             ret->type = XPATH_STRING;
2493             ret->stringval = xmlStrdup(BAD_CAST val);
2494 #ifdef XP_DEBUG_OBJ_USAGE
2495             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2496 #endif
2497             return(ret);
2498         }
2499     }
2500     return(xmlXPathNewCString(val));
2501 }
2502
2503 /**
2504  * xmlXPathCacheNewString:
2505  * @ctxt: the XPath context
2506  * @val:  the xmlChar * value
2507  *
2508  * This is the cached version of xmlXPathNewString().
2509  * Acquire an xmlXPathObjectPtr of type string and of value @val
2510  *
2511  * Returns the created or reused object.
2512  */
2513 static xmlXPathObjectPtr
2514 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2515 {
2516     if ((ctxt != NULL) && (ctxt->cache)) {
2517         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2518
2519         if ((cache->stringObjs != NULL) &&
2520             (cache->stringObjs->number != 0))
2521         {
2522             xmlXPathObjectPtr ret;
2523
2524             ret = (xmlXPathObjectPtr)
2525                 cache->stringObjs->items[--cache->stringObjs->number];
2526             ret->type = XPATH_STRING;
2527             if (val != NULL)
2528                 ret->stringval = xmlStrdup(val);
2529             else
2530                 ret->stringval = xmlStrdup((const xmlChar *)"");
2531 #ifdef XP_DEBUG_OBJ_USAGE
2532             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2533 #endif
2534             return(ret);
2535         } else if ((cache->miscObjs != NULL) &&
2536             (cache->miscObjs->number != 0))
2537         {
2538             xmlXPathObjectPtr ret;
2539
2540             ret = (xmlXPathObjectPtr)
2541                 cache->miscObjs->items[--cache->miscObjs->number];
2542
2543             ret->type = XPATH_STRING;
2544             if (val != NULL)
2545                 ret->stringval = xmlStrdup(val);
2546             else
2547                 ret->stringval = xmlStrdup((const xmlChar *)"");
2548 #ifdef XP_DEBUG_OBJ_USAGE
2549             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2550 #endif
2551             return(ret);
2552         }
2553     }
2554     return(xmlXPathNewString(val));
2555 }
2556
2557 /**
2558  * xmlXPathCacheNewBoolean:
2559  * @ctxt: the XPath context
2560  * @val:  the boolean value
2561  *
2562  * This is the cached version of xmlXPathNewBoolean().
2563  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2564  *
2565  * Returns the created or reused object.
2566  */
2567 static xmlXPathObjectPtr
2568 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2569 {
2570     if ((ctxt != NULL) && (ctxt->cache)) {
2571         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2572
2573         if ((cache->booleanObjs != NULL) &&
2574             (cache->booleanObjs->number != 0))
2575         {
2576             xmlXPathObjectPtr ret;
2577
2578             ret = (xmlXPathObjectPtr)
2579                 cache->booleanObjs->items[--cache->booleanObjs->number];
2580             ret->type = XPATH_BOOLEAN;
2581             ret->boolval = (val != 0);
2582 #ifdef XP_DEBUG_OBJ_USAGE
2583             xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2584 #endif
2585             return(ret);
2586         } else if ((cache->miscObjs != NULL) &&
2587             (cache->miscObjs->number != 0))
2588         {
2589             xmlXPathObjectPtr ret;
2590
2591             ret = (xmlXPathObjectPtr)
2592                 cache->miscObjs->items[--cache->miscObjs->number];
2593
2594             ret->type = XPATH_BOOLEAN;
2595             ret->boolval = (val != 0);
2596 #ifdef XP_DEBUG_OBJ_USAGE
2597             xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2598 #endif
2599             return(ret);
2600         }
2601     }
2602     return(xmlXPathNewBoolean(val));
2603 }
2604
2605 /**
2606  * xmlXPathCacheNewFloat:
2607  * @ctxt: the XPath context
2608  * @val:  the double value
2609  *
2610  * This is the cached version of xmlXPathNewFloat().
2611  * Acquires an xmlXPathObjectPtr of type double and of value @val
2612  *
2613  * Returns the created or reused object.
2614  */
2615 static xmlXPathObjectPtr
2616 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2617 {
2618      if ((ctxt != NULL) && (ctxt->cache)) {
2619         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2620
2621         if ((cache->numberObjs != NULL) &&
2622             (cache->numberObjs->number != 0))
2623         {
2624             xmlXPathObjectPtr ret;
2625
2626             ret = (xmlXPathObjectPtr)
2627                 cache->numberObjs->items[--cache->numberObjs->number];
2628             ret->type = XPATH_NUMBER;
2629             ret->floatval = val;
2630 #ifdef XP_DEBUG_OBJ_USAGE
2631             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2632 #endif
2633             return(ret);
2634         } else if ((cache->miscObjs != NULL) &&
2635             (cache->miscObjs->number != 0))
2636         {
2637             xmlXPathObjectPtr ret;
2638
2639             ret = (xmlXPathObjectPtr)
2640                 cache->miscObjs->items[--cache->miscObjs->number];
2641
2642             ret->type = XPATH_NUMBER;
2643             ret->floatval = val;
2644 #ifdef XP_DEBUG_OBJ_USAGE
2645             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2646 #endif
2647             return(ret);
2648         }
2649     }
2650     return(xmlXPathNewFloat(val));
2651 }
2652
2653 /**
2654  * xmlXPathCacheConvertString:
2655  * @ctxt: the XPath context
2656  * @val:  an XPath object
2657  *
2658  * This is the cached version of xmlXPathConvertString().
2659  * Converts an existing object to its string() equivalent
2660  *
2661  * Returns a created or reused object, the old one is freed (cached)
2662  *         (or the operation is done directly on @val)
2663  */
2664
2665 static xmlXPathObjectPtr
2666 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2667     xmlChar *res = NULL;
2668
2669     if (val == NULL)
2670         return(xmlXPathCacheNewCString(ctxt, ""));
2671
2672     switch (val->type) {
2673     case XPATH_UNDEFINED:
2674 #ifdef DEBUG_EXPR
2675         xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2676 #endif
2677         break;
2678     case XPATH_NODESET:
2679     case XPATH_XSLT_TREE:
2680         res = xmlXPathCastNodeSetToString(val->nodesetval);
2681         break;
2682     case XPATH_STRING:
2683         return(val);
2684     case XPATH_BOOLEAN:
2685         res = xmlXPathCastBooleanToString(val->boolval);
2686         break;
2687     case XPATH_NUMBER:
2688         res = xmlXPathCastNumberToString(val->floatval);
2689         break;
2690     case XPATH_USERS:
2691     case XPATH_POINT:
2692     case XPATH_RANGE:
2693     case XPATH_LOCATIONSET:
2694         TODO;
2695         break;
2696     }
2697     xmlXPathReleaseObject(ctxt, val);
2698     if (res == NULL)
2699         return(xmlXPathCacheNewCString(ctxt, ""));
2700     return(xmlXPathCacheWrapString(ctxt, res));
2701 }
2702
2703 /**
2704  * xmlXPathCacheObjectCopy:
2705  * @ctxt: the XPath context
2706  * @val:  the original object
2707  *
2708  * This is the cached version of xmlXPathObjectCopy().
2709  * Acquire a copy of a given object
2710  *
2711  * Returns a created or reused created object.
2712  */
2713 static xmlXPathObjectPtr
2714 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2715 {
2716     if (val == NULL)
2717         return(NULL);
2718
2719     if (XP_HAS_CACHE(ctxt)) {
2720         switch (val->type) {
2721             case XPATH_NODESET:
2722                 return(xmlXPathCacheWrapNodeSet(ctxt,
2723                     xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2724             case XPATH_STRING:
2725                 return(xmlXPathCacheNewString(ctxt, val->stringval));
2726             case XPATH_BOOLEAN:
2727                 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2728             case XPATH_NUMBER:
2729                 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2730             default:
2731                 break;
2732         }
2733     }
2734     return(xmlXPathObjectCopy(val));
2735 }
2736
2737 /**
2738  * xmlXPathCacheConvertBoolean:
2739  * @ctxt: the XPath context
2740  * @val:  an XPath object
2741  *
2742  * This is the cached version of xmlXPathConvertBoolean().
2743  * Converts an existing object to its boolean() equivalent
2744  *
2745  * Returns a created or reused object, the old one is freed (or the operation
2746  *         is done directly on @val)
2747  */
2748 static xmlXPathObjectPtr
2749 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2750     xmlXPathObjectPtr ret;
2751
2752     if (val == NULL)
2753         return(xmlXPathCacheNewBoolean(ctxt, 0));
2754     if (val->type == XPATH_BOOLEAN)
2755         return(val);
2756     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2757     xmlXPathReleaseObject(ctxt, val);
2758     return(ret);
2759 }
2760
2761 /**
2762  * xmlXPathCacheConvertNumber:
2763  * @ctxt: the XPath context
2764  * @val:  an XPath object
2765  *
2766  * This is the cached version of xmlXPathConvertNumber().
2767  * Converts an existing object to its number() equivalent
2768  *
2769  * Returns a created or reused object, the old one is freed (or the operation
2770  *         is done directly on @val)
2771  */
2772 static xmlXPathObjectPtr
2773 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774     xmlXPathObjectPtr ret;
2775
2776     if (val == NULL)
2777         return(xmlXPathCacheNewFloat(ctxt, 0.0));
2778     if (val->type == XPATH_NUMBER)
2779         return(val);
2780     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2781     xmlXPathReleaseObject(ctxt, val);
2782     return(ret);
2783 }
2784
2785 /************************************************************************
2786  *                                                                      *
2787  *              Parser stacks related functions and macros              *
2788  *                                                                      *
2789  ************************************************************************/
2790
2791 /**
2792  * xmlXPathSetFrame:
2793  * @ctxt: an XPath parser context
2794  *
2795  * Set the callee evaluation frame
2796  *
2797  * Returns the previous frame value to be restored once done
2798  */
2799 static int
2800 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2801     int ret;
2802
2803     if (ctxt == NULL)
2804         return(0);
2805     ret = ctxt->valueFrame;
2806     ctxt->valueFrame = ctxt->valueNr;
2807     return(ret);
2808 }
2809
2810 /**
2811  * xmlXPathPopFrame:
2812  * @ctxt: an XPath parser context
2813  * @frame: the previous frame value
2814  *
2815  * Remove the callee evaluation frame
2816  */
2817 static void
2818 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2819     if (ctxt == NULL)
2820         return;
2821     if (ctxt->valueNr < ctxt->valueFrame) {
2822         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2823     }
2824     ctxt->valueFrame = frame;
2825 }
2826
2827 /**
2828  * valuePop:
2829  * @ctxt: an XPath evaluation context
2830  *
2831  * Pops the top XPath object from the value stack
2832  *
2833  * Returns the XPath object just removed
2834  */
2835 xmlXPathObjectPtr
2836 valuePop(xmlXPathParserContextPtr ctxt)
2837 {
2838     xmlXPathObjectPtr ret;
2839
2840     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2841         return (NULL);
2842
2843     if (ctxt->valueNr <= ctxt->valueFrame) {
2844         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2845         return (NULL);
2846     }
2847
2848     ctxt->valueNr--;
2849     if (ctxt->valueNr > 0)
2850         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2851     else
2852         ctxt->value = NULL;
2853     ret = ctxt->valueTab[ctxt->valueNr];
2854     ctxt->valueTab[ctxt->valueNr] = NULL;
2855     return (ret);
2856 }
2857 /**
2858  * valuePush:
2859  * @ctxt:  an XPath evaluation context
2860  * @value:  the XPath object
2861  *
2862  * Pushes a new XPath object on top of the value stack
2863  *
2864  * returns the number of items on the value stack
2865  */
2866 int
2867 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2868 {
2869     if ((ctxt == NULL) || (value == NULL)) return(-1);
2870     if (ctxt->valueNr >= ctxt->valueMax) {
2871         xmlXPathObjectPtr *tmp;
2872
2873         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2874             xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2875             ctxt->error = XPATH_MEMORY_ERROR;
2876             return (0);
2877         }
2878         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2879                                              2 * ctxt->valueMax *
2880                                              sizeof(ctxt->valueTab[0]));
2881         if (tmp == NULL) {
2882             xmlXPathErrMemory(NULL, "pushing value\n");
2883             ctxt->error = XPATH_MEMORY_ERROR;
2884             return (0);
2885         }
2886         ctxt->valueMax *= 2;
2887         ctxt->valueTab = tmp;
2888     }
2889     ctxt->valueTab[ctxt->valueNr] = value;
2890     ctxt->value = value;
2891     return (ctxt->valueNr++);
2892 }
2893
2894 /**
2895  * xmlXPathPopBoolean:
2896  * @ctxt:  an XPath parser context
2897  *
2898  * Pops a boolean from the stack, handling conversion if needed.
2899  * Check error with #xmlXPathCheckError.
2900  *
2901  * Returns the boolean
2902  */
2903 int
2904 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2905     xmlXPathObjectPtr obj;
2906     int ret;
2907
2908     obj = valuePop(ctxt);
2909     if (obj == NULL) {
2910         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2911         return(0);
2912     }
2913     if (obj->type != XPATH_BOOLEAN)
2914         ret = xmlXPathCastToBoolean(obj);
2915     else
2916         ret = obj->boolval;
2917     xmlXPathReleaseObject(ctxt->context, obj);
2918     return(ret);
2919 }
2920
2921 /**
2922  * xmlXPathPopNumber:
2923  * @ctxt:  an XPath parser context
2924  *
2925  * Pops a number from the stack, handling conversion if needed.
2926  * Check error with #xmlXPathCheckError.
2927  *
2928  * Returns the number
2929  */
2930 double
2931 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2932     xmlXPathObjectPtr obj;
2933     double ret;
2934
2935     obj = valuePop(ctxt);
2936     if (obj == NULL) {
2937         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2938         return(0);
2939     }
2940     if (obj->type != XPATH_NUMBER)
2941         ret = xmlXPathCastToNumber(obj);
2942     else
2943         ret = obj->floatval;
2944     xmlXPathReleaseObject(ctxt->context, obj);
2945     return(ret);
2946 }
2947
2948 /**
2949  * xmlXPathPopString:
2950  * @ctxt:  an XPath parser context
2951  *
2952  * Pops a string from the stack, handling conversion if needed.
2953  * Check error with #xmlXPathCheckError.
2954  *
2955  * Returns the string
2956  */
2957 xmlChar *
2958 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2959     xmlXPathObjectPtr obj;
2960     xmlChar * ret;
2961
2962     obj = valuePop(ctxt);
2963     if (obj == NULL) {
2964         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2965         return(NULL);
2966     }
2967     ret = xmlXPathCastToString(obj);    /* this does required strdup */
2968     /* TODO: needs refactoring somewhere else */
2969     if (obj->stringval == ret)
2970         obj->stringval = NULL;
2971     xmlXPathReleaseObject(ctxt->context, obj);
2972     return(ret);
2973 }
2974
2975 /**
2976  * xmlXPathPopNodeSet:
2977  * @ctxt:  an XPath parser context
2978  *
2979  * Pops a node-set from the stack, handling conversion if needed.
2980  * Check error with #xmlXPathCheckError.
2981  *
2982  * Returns the node-set
2983  */
2984 xmlNodeSetPtr
2985 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2986     xmlXPathObjectPtr obj;
2987     xmlNodeSetPtr ret;
2988
2989     if (ctxt == NULL) return(NULL);
2990     if (ctxt->value == NULL) {
2991         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2992         return(NULL);
2993     }
2994     if (!xmlXPathStackIsNodeSet(ctxt)) {
2995         xmlXPathSetTypeError(ctxt);
2996         return(NULL);
2997     }
2998     obj = valuePop(ctxt);
2999     ret = obj->nodesetval;
3000 #if 0
3001     /* to fix memory leak of not clearing obj->user */
3002     if (obj->boolval && obj->user != NULL)
3003         xmlFreeNodeList((xmlNodePtr) obj->user);
3004 #endif
3005     obj->nodesetval = NULL;
3006     xmlXPathReleaseObject(ctxt->context, obj);
3007     return(ret);
3008 }
3009
3010 /**
3011  * xmlXPathPopExternal:
3012  * @ctxt:  an XPath parser context
3013  *
3014  * Pops an external object from the stack, handling conversion if needed.
3015  * Check error with #xmlXPathCheckError.
3016  *
3017  * Returns the object
3018  */
3019 void *
3020 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3021     xmlXPathObjectPtr obj;
3022     void * ret;
3023
3024     if ((ctxt == NULL) || (ctxt->value == NULL)) {
3025         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3026         return(NULL);
3027     }
3028     if (ctxt->value->type != XPATH_USERS) {
3029         xmlXPathSetTypeError(ctxt);
3030         return(NULL);
3031     }
3032     obj = valuePop(ctxt);
3033     ret = obj->user;
3034     obj->user = NULL;
3035     xmlXPathReleaseObject(ctxt->context, obj);
3036     return(ret);
3037 }
3038
3039 /*
3040  * Macros for accessing the content. Those should be used only by the parser,
3041  * and not exported.
3042  *
3043  * Dirty macros, i.e. one need to make assumption on the context to use them
3044  *
3045  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3046  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3047  *           in ISO-Latin or UTF-8.
3048  *           This should be used internally by the parser
3049  *           only to compare to ASCII values otherwise it would break when
3050  *           running with UTF-8 encoding.
3051  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3052  *           to compare on ASCII based substring.
3053  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3054  *           strings within the parser.
3055  *   CURRENT Returns the current char value, with the full decoding of
3056  *           UTF-8 if we are using this mode. It returns an int.
3057  *   NEXT    Skip to the next character, this does the proper decoding
3058  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3059  *           It returns the pointer to the current xmlChar.
3060  */
3061
3062 #define CUR (*ctxt->cur)
3063 #define SKIP(val) ctxt->cur += (val)
3064 #define NXT(val) ctxt->cur[(val)]
3065 #define CUR_PTR ctxt->cur
3066 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3067
3068 #define COPY_BUF(l,b,i,v)                                              \
3069     if (l == 1) b[i++] = (xmlChar) v;                                  \
3070     else i += xmlCopyChar(l,&b[i],v)
3071
3072 #define NEXTL(l)  ctxt->cur += l
3073
3074 #define SKIP_BLANKS                                                     \
3075     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3076
3077 #define CURRENT (*ctxt->cur)
3078 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3079
3080
3081 #ifndef DBL_DIG
3082 #define DBL_DIG 16
3083 #endif
3084 #ifndef DBL_EPSILON
3085 #define DBL_EPSILON 1E-9
3086 #endif
3087
3088 #define UPPER_DOUBLE 1E9
3089 #define LOWER_DOUBLE 1E-5
3090 #define LOWER_DOUBLE_EXP 5
3091
3092 #define INTEGER_DIGITS DBL_DIG
3093 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3094 #define EXPONENT_DIGITS (3 + 2)
3095
3096 /**
3097  * xmlXPathFormatNumber:
3098  * @number:     number to format
3099  * @buffer:     output buffer
3100  * @buffersize: size of output buffer
3101  *
3102  * Convert the number into a string representation.
3103  */
3104 static void
3105 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3106 {
3107     switch (xmlXPathIsInf(number)) {
3108     case 1:
3109         if (buffersize > (int)sizeof("Infinity"))
3110             snprintf(buffer, buffersize, "Infinity");
3111         break;
3112     case -1:
3113         if (buffersize > (int)sizeof("-Infinity"))
3114             snprintf(buffer, buffersize, "-Infinity");
3115         break;
3116     default:
3117         if (xmlXPathIsNaN(number)) {
3118             if (buffersize > (int)sizeof("NaN"))
3119                 snprintf(buffer, buffersize, "NaN");
3120         } else if (number == 0 && xmlXPathGetSign(number) != 0) {
3121             snprintf(buffer, buffersize, "0");
3122         } else if ((number > INT_MIN) && (number < INT_MAX) &&
3123                    (number == (int) number)) {
3124             char work[30];
3125             char *ptr, *cur;
3126             int value = (int) number;
3127
3128             ptr = &buffer[0];
3129             if (value == 0) {
3130                 *ptr++ = '0';
3131             } else {
3132                 snprintf(work, 29, "%d", value);
3133                 cur = &work[0];
3134                 while ((*cur) && (ptr - buffer < buffersize)) {
3135                     *ptr++ = *cur++;
3136                 }
3137             }
3138             if (ptr - buffer < buffersize) {
3139                 *ptr = 0;
3140             } else if (buffersize > 0) {
3141                 ptr--;
3142                 *ptr = 0;
3143             }
3144         } else {
3145             /*
3146               For the dimension of work,
3147                   DBL_DIG is number of significant digits
3148                   EXPONENT is only needed for "scientific notation"
3149                   3 is sign, decimal point, and terminating zero
3150                   LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3151               Note that this dimension is slightly (a few characters)
3152               larger than actually necessary.
3153             */
3154             char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3155             int integer_place, fraction_place;
3156             char *ptr;
3157             char *after_fraction;
3158             double absolute_value;
3159             int size;
3160
3161             absolute_value = fabs(number);
3162
3163             /*
3164              * First choose format - scientific or regular floating point.
3165              * In either case, result is in work, and after_fraction points
3166              * just past the fractional part.
3167             */
3168             if ( ((absolute_value > UPPER_DOUBLE) ||
3169                   (absolute_value < LOWER_DOUBLE)) &&
3170                  (absolute_value != 0.0) ) {
3171                 /* Use scientific notation */
3172                 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3173                 fraction_place = DBL_DIG - 1;
3174                 size = snprintf(work, sizeof(work),"%*.*e",
3175                          integer_place, fraction_place, number);
3176                 while ((size > 0) && (work[size] != 'e')) size--;
3177
3178             }
3179             else {
3180                 /* Use regular notation */
3181                 if (absolute_value > 0.0) {
3182                     integer_place = (int)log10(absolute_value);
3183                     if (integer_place > 0)
3184                         fraction_place = DBL_DIG - integer_place - 1;
3185                     else
3186                         fraction_place = DBL_DIG - integer_place;
3187                 } else {
3188                     fraction_place = 1;
3189                 }
3190                 size = snprintf(work, sizeof(work), "%0.*f",
3191                                 fraction_place, number);
3192             }
3193
3194             /* Remove leading spaces sometimes inserted by snprintf */
3195             while (work[0] == ' ') {
3196                 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3197                 size--;
3198             }
3199
3200             /* Remove fractional trailing zeroes */
3201             after_fraction = work + size;
3202             ptr = after_fraction;
3203             while (*(--ptr) == '0')
3204                 ;
3205             if (*ptr != '.')
3206                 ptr++;
3207             while ((*ptr++ = *after_fraction++) != 0);
3208
3209             /* Finally copy result back to caller */
3210             size = strlen(work) + 1;
3211             if (size > buffersize) {
3212                 work[buffersize - 1] = 0;
3213                 size = buffersize;
3214             }
3215             memmove(buffer, work, size);
3216         }
3217         break;
3218     }
3219 }
3220
3221
3222 /************************************************************************
3223  *                                                                      *
3224  *                      Routines to handle NodeSets                     *
3225  *                                                                      *
3226  ************************************************************************/
3227
3228 /**
3229  * xmlXPathOrderDocElems:
3230  * @doc:  an input document
3231  *
3232  * Call this routine to speed up XPath computation on static documents.
3233  * This stamps all the element nodes with the document order
3234  * Like for line information, the order is kept in the element->content
3235  * field, the value stored is actually - the node number (starting at -1)
3236  * to be able to differentiate from line numbers.
3237  *
3238  * Returns the number of elements found in the document or -1 in case
3239  *    of error.
3240  */
3241 long
3242 xmlXPathOrderDocElems(xmlDocPtr doc) {
3243     ptrdiff_t count = 0;
3244     xmlNodePtr cur;
3245
3246     if (doc == NULL)
3247         return(-1);
3248     cur = doc->children;
3249     while (cur != NULL) {
3250         if (cur->type == XML_ELEMENT_NODE) {
3251             cur->content = (void *) (-(++count));
3252             if (cur->children != NULL) {
3253                 cur = cur->children;
3254                 continue;
3255             }
3256         }
3257         if (cur->next != NULL) {
3258             cur = cur->next;
3259             continue;
3260         }
3261         do {
3262             cur = cur->parent;
3263             if (cur == NULL)
3264                 break;
3265             if (cur == (xmlNodePtr) doc) {
3266                 cur = NULL;
3267                 break;
3268             }
3269             if (cur->next != NULL) {
3270                 cur = cur->next;
3271                 break;
3272             }
3273         } while (cur != NULL);
3274     }
3275     return((long) count);
3276 }
3277
3278 /**
3279  * xmlXPathCmpNodes:
3280  * @node1:  the first node
3281  * @node2:  the second node
3282  *
3283  * Compare two nodes w.r.t document order
3284  *
3285  * Returns -2 in case of error 1 if first point < second point, 0 if
3286  *         it's the same node, -1 otherwise
3287  */
3288 int
3289 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3290     int depth1, depth2;
3291     int attr1 = 0, attr2 = 0;
3292     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3293     xmlNodePtr cur, root;
3294
3295     if ((node1 == NULL) || (node2 == NULL))
3296         return(-2);
3297     /*
3298      * a couple of optimizations which will avoid computations in most cases
3299      */
3300     if (node1 == node2)         /* trivial case */
3301         return(0);
3302     if (node1->type == XML_ATTRIBUTE_NODE) {
3303         attr1 = 1;
3304         attrNode1 = node1;
3305         node1 = node1->parent;
3306     }
3307     if (node2->type == XML_ATTRIBUTE_NODE) {
3308         attr2 = 1;
3309         attrNode2 = node2;
3310         node2 = node2->parent;
3311     }
3312     if (node1 == node2) {
3313         if (attr1 == attr2) {
3314             /* not required, but we keep attributes in order */
3315             if (attr1 != 0) {
3316                 cur = attrNode2->prev;
3317                 while (cur != NULL) {
3318                     if (cur == attrNode1)
3319                         return (1);
3320                     cur = cur->prev;
3321                 }
3322                 return (-1);
3323             }
3324             return(0);
3325         }
3326         if (attr2 == 1)
3327             return(1);
3328         return(-1);
3329     }
3330     if ((node1->type == XML_NAMESPACE_DECL) ||
3331         (node2->type == XML_NAMESPACE_DECL))
3332         return(1);
3333     if (node1 == node2->prev)
3334         return(1);
3335     if (node1 == node2->next)
3336         return(-1);
3337
3338     /*
3339      * Speedup using document order if availble.
3340      */
3341     if ((node1->type == XML_ELEMENT_NODE) &&
3342         (node2->type == XML_ELEMENT_NODE) &&
3343         (0 > (ptrdiff_t) node1->content) &&
3344         (0 > (ptrdiff_t) node2->content) &&
3345         (node1->doc == node2->doc)) {
3346         ptrdiff_t l1, l2;
3347
3348         l1 = -((ptrdiff_t) node1->content);
3349         l2 = -((ptrdiff_t) node2->content);
3350         if (l1 < l2)
3351             return(1);
3352         if (l1 > l2)
3353             return(-1);
3354     }
3355
3356     /*
3357      * compute depth to root
3358      */
3359     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3360         if (cur->parent == node1)
3361             return(1);
3362         depth2++;
3363     }
3364     root = cur;
3365     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3366         if (cur->parent == node2)
3367             return(-1);
3368         depth1++;
3369     }
3370     /*
3371      * Distinct document (or distinct entities :-( ) case.
3372      */
3373     if (root != cur) {
3374         return(-2);
3375     }
3376     /*
3377      * get the nearest common ancestor.
3378      */
3379     while (depth1 > depth2) {
3380         depth1--;
3381         node1 = node1->parent;
3382     }
3383     while (depth2 > depth1) {
3384         depth2--;
3385         node2 = node2->parent;
3386     }
3387     while (node1->parent != node2->parent) {
3388         node1 = node1->parent;
3389         node2 = node2->parent;
3390         /* should not happen but just in case ... */
3391         if ((node1 == NULL) || (node2 == NULL))
3392             return(-2);
3393     }
3394     /*
3395      * Find who's first.
3396      */
3397     if (node1 == node2->prev)
3398         return(1);
3399     if (node1 == node2->next)
3400         return(-1);
3401     /*
3402      * Speedup using document order if availble.
3403      */
3404     if ((node1->type == XML_ELEMENT_NODE) &&
3405         (node2->type == XML_ELEMENT_NODE) &&
3406         (0 > (ptrdiff_t) node1->content) &&
3407         (0 > (ptrdiff_t) node2->content) &&
3408         (node1->doc == node2->doc)) {
3409         ptrdiff_t l1, l2;
3410
3411         l1 = -((ptrdiff_t) node1->content);
3412         l2 = -((ptrdiff_t) node2->content);
3413         if (l1 < l2)
3414             return(1);
3415         if (l1 > l2)
3416             return(-1);
3417     }
3418
3419     for (cur = node1->next;cur != NULL;cur = cur->next)
3420         if (cur == node2)
3421             return(1);
3422     return(-1); /* assume there is no sibling list corruption */
3423 }
3424
3425 /**
3426  * xmlXPathNodeSetSort:
3427  * @set:  the node set
3428  *
3429  * Sort the node set in document order
3430  */
3431 void
3432 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3433 #ifndef WITH_TIM_SORT
3434     int i, j, incr, len;
3435     xmlNodePtr tmp;
3436 #endif
3437
3438     if (set == NULL)
3439         return;
3440
3441 #ifndef WITH_TIM_SORT
3442     /*
3443      * Use the old Shell's sort implementation to sort the node-set
3444      * Timsort ought to be quite faster
3445      */
3446     len = set->nodeNr;
3447     for (incr = len / 2; incr > 0; incr /= 2) {
3448         for (i = incr; i < len; i++) {
3449             j = i - incr;
3450             while (j >= 0) {
3451 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3452                 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3453                         set->nodeTab[j + incr]) == -1)
3454 #else
3455                 if (xmlXPathCmpNodes(set->nodeTab[j],
3456                         set->nodeTab[j + incr]) == -1)
3457 #endif
3458                 {
3459                     tmp = set->nodeTab[j];
3460                     set->nodeTab[j] = set->nodeTab[j + incr];
3461                     set->nodeTab[j + incr] = tmp;
3462                     j -= incr;
3463                 } else
3464                     break;
3465             }
3466         }
3467     }
3468 #else /* WITH_TIM_SORT */
3469     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3470 #endif /* WITH_TIM_SORT */
3471 }
3472
3473 #define XML_NODESET_DEFAULT     10
3474 /**
3475  * xmlXPathNodeSetDupNs:
3476  * @node:  the parent node of the namespace XPath node
3477  * @ns:  the libxml namespace declaration node.
3478  *
3479  * Namespace node in libxml don't match the XPath semantic. In a node set
3480  * the namespace nodes are duplicated and the next pointer is set to the
3481  * parent node in the XPath semantic.
3482  *
3483  * Returns the newly created object.
3484  */
3485 static xmlNodePtr
3486 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3487     xmlNsPtr cur;
3488
3489     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3490         return(NULL);
3491     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3492         return((xmlNodePtr) ns);
3493
3494     /*
3495      * Allocate a new Namespace and fill the fields.
3496      */
3497     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3498     if (cur == NULL) {
3499         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3500         return(NULL);
3501     }
3502     memset(cur, 0, sizeof(xmlNs));
3503     cur->type = XML_NAMESPACE_DECL;
3504     if (ns->href != NULL)
3505         cur->href = xmlStrdup(ns->href);
3506     if (ns->prefix != NULL)
3507         cur->prefix = xmlStrdup(ns->prefix);
3508     cur->next = (xmlNsPtr) node;
3509     return((xmlNodePtr) cur);
3510 }
3511
3512 /**
3513  * xmlXPathNodeSetFreeNs:
3514  * @ns:  the XPath namespace node found in a nodeset.
3515  *
3516  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3517  * the namespace nodes are duplicated and the next pointer is set to the
3518  * parent node in the XPath semantic. Check if such a node needs to be freed
3519  */
3520 void
3521 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3522     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3523         return;
3524
3525     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3526         if (ns->href != NULL)
3527             xmlFree((xmlChar *)ns->href);
3528         if (ns->prefix != NULL)
3529             xmlFree((xmlChar *)ns->prefix);
3530         xmlFree(ns);
3531     }
3532 }
3533
3534 /**
3535  * xmlXPathNodeSetCreate:
3536  * @val:  an initial xmlNodePtr, or NULL
3537  *
3538  * Create a new xmlNodeSetPtr of type double and of value @val
3539  *
3540  * Returns the newly created object.
3541  */
3542 xmlNodeSetPtr
3543 xmlXPathNodeSetCreate(xmlNodePtr val) {
3544     xmlNodeSetPtr ret;
3545
3546     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3547     if (ret == NULL) {
3548         xmlXPathErrMemory(NULL, "creating nodeset\n");
3549         return(NULL);
3550     }
3551     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3552     if (val != NULL) {
3553         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3554                                              sizeof(xmlNodePtr));
3555         if (ret->nodeTab == NULL) {
3556             xmlXPathErrMemory(NULL, "creating nodeset\n");
3557             xmlFree(ret);
3558             return(NULL);
3559         }
3560         memset(ret->nodeTab, 0 ,
3561                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3562         ret->nodeMax = XML_NODESET_DEFAULT;
3563         if (val->type == XML_NAMESPACE_DECL) {
3564             xmlNsPtr ns = (xmlNsPtr) val;
3565
3566             ret->nodeTab[ret->nodeNr++] =
3567                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3568         } else
3569             ret->nodeTab[ret->nodeNr++] = val;
3570     }
3571     return(ret);
3572 }
3573
3574 /**
3575  * xmlXPathNodeSetCreateSize:
3576  * @size:  the initial size of the set
3577  *
3578  * Create a new xmlNodeSetPtr of type double and of value @val
3579  *
3580  * Returns the newly created object.
3581  */
3582 static xmlNodeSetPtr
3583 xmlXPathNodeSetCreateSize(int size) {
3584     xmlNodeSetPtr ret;
3585
3586     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3587     if (ret == NULL) {
3588         xmlXPathErrMemory(NULL, "creating nodeset\n");
3589         return(NULL);
3590     }
3591     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3592     if (size < XML_NODESET_DEFAULT)
3593         size = XML_NODESET_DEFAULT;
3594     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3595     if (ret->nodeTab == NULL) {
3596         xmlXPathErrMemory(NULL, "creating nodeset\n");
3597         xmlFree(ret);
3598         return(NULL);
3599     }
3600     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3601     ret->nodeMax = size;
3602     return(ret);
3603 }
3604
3605 /**
3606  * xmlXPathNodeSetContains:
3607  * @cur:  the node-set
3608  * @val:  the node
3609  *
3610  * checks whether @cur contains @val
3611  *
3612  * Returns true (1) if @cur contains @val, false (0) otherwise
3613  */
3614 int
3615 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3616     int i;
3617
3618     if ((cur == NULL) || (val == NULL)) return(0);
3619     if (val->type == XML_NAMESPACE_DECL) {
3620         for (i = 0; i < cur->nodeNr; i++) {
3621             if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3622                 xmlNsPtr ns1, ns2;
3623
3624                 ns1 = (xmlNsPtr) val;
3625                 ns2 = (xmlNsPtr) cur->nodeTab[i];
3626                 if (ns1 == ns2)
3627                     return(1);
3628                 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3629                     (xmlStrEqual(ns1->prefix, ns2->prefix)))
3630                     return(1);
3631             }
3632         }
3633     } else {
3634         for (i = 0; i < cur->nodeNr; i++) {
3635             if (cur->nodeTab[i] == val)
3636                 return(1);
3637         }
3638     }
3639     return(0);
3640 }
3641
3642 /**
3643  * xmlXPathNodeSetAddNs:
3644  * @cur:  the initial node set
3645  * @node:  the hosting node
3646  * @ns:  a the namespace node
3647  *
3648  * add a new namespace node to an existing NodeSet
3649  *
3650  * Returns 0 in case of success and -1 in case of error
3651  */
3652 int
3653 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3654     int i;
3655
3656
3657     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3658         (ns->type != XML_NAMESPACE_DECL) ||
3659         (node->type != XML_ELEMENT_NODE))
3660         return(-1);
3661
3662     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3663     /*
3664      * prevent duplicates
3665      */
3666     for (i = 0;i < cur->nodeNr;i++) {
3667         if ((cur->nodeTab[i] != NULL) &&
3668             (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3669             (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3670             (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3671             return(0);
3672     }
3673
3674     /*
3675      * grow the nodeTab if needed
3676      */
3677     if (cur->nodeMax == 0) {
3678         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3679                                              sizeof(xmlNodePtr));
3680         if (cur->nodeTab == NULL) {
3681             xmlXPathErrMemory(NULL, "growing nodeset\n");
3682             return(-1);
3683         }
3684         memset(cur->nodeTab, 0 ,
3685                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3686         cur->nodeMax = XML_NODESET_DEFAULT;
3687     } else if (cur->nodeNr == cur->nodeMax) {
3688         xmlNodePtr *temp;
3689
3690         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3691             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3692             return(-1);
3693         }
3694         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3695                                       sizeof(xmlNodePtr));
3696         if (temp == NULL) {
3697             xmlXPathErrMemory(NULL, "growing nodeset\n");
3698             return(-1);
3699         }
3700         cur->nodeMax *= 2;
3701         cur->nodeTab = temp;
3702     }
3703     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3704     return(0);
3705 }
3706
3707 /**
3708  * xmlXPathNodeSetAdd:
3709  * @cur:  the initial node set
3710  * @val:  a new xmlNodePtr
3711  *
3712  * add a new xmlNodePtr to an existing NodeSet
3713  *
3714  * Returns 0 in case of success, and -1 in case of error
3715  */
3716 int
3717 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3718     int i;
3719
3720     if ((cur == NULL) || (val == NULL)) return(-1);
3721
3722     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3723     /*
3724      * prevent duplicates
3725      */
3726     for (i = 0;i < cur->nodeNr;i++)
3727         if (cur->nodeTab[i] == val) return(0);
3728
3729     /*
3730      * grow the nodeTab if needed
3731      */
3732     if (cur->nodeMax == 0) {
3733         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3734                                              sizeof(xmlNodePtr));
3735         if (cur->nodeTab == NULL) {
3736             xmlXPathErrMemory(NULL, "growing nodeset\n");
3737             return(-1);
3738         }
3739         memset(cur->nodeTab, 0 ,
3740                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3741         cur->nodeMax = XML_NODESET_DEFAULT;
3742     } else if (cur->nodeNr == cur->nodeMax) {
3743         xmlNodePtr *temp;
3744
3745         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3746             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3747             return(-1);
3748         }
3749         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3750                                       sizeof(xmlNodePtr));
3751         if (temp == NULL) {
3752             xmlXPathErrMemory(NULL, "growing nodeset\n");
3753             return(-1);
3754         }
3755         cur->nodeMax *= 2;
3756         cur->nodeTab = temp;
3757     }
3758     if (val->type == XML_NAMESPACE_DECL) {
3759         xmlNsPtr ns = (xmlNsPtr) val;
3760
3761         cur->nodeTab[cur->nodeNr++] =
3762             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3763     } else
3764         cur->nodeTab[cur->nodeNr++] = val;
3765     return(0);
3766 }
3767
3768 /**
3769  * xmlXPathNodeSetAddUnique:
3770  * @cur:  the initial node set
3771  * @val:  a new xmlNodePtr
3772  *
3773  * add a new xmlNodePtr to an existing NodeSet, optimized version
3774  * when we are sure the node is not already in the set.
3775  *
3776  * Returns 0 in case of success and -1 in case of failure
3777  */
3778 int
3779 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3780     if ((cur == NULL) || (val == NULL)) return(-1);
3781
3782     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3783     /*
3784      * grow the nodeTab if needed
3785      */
3786     if (cur->nodeMax == 0) {
3787         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3788                                              sizeof(xmlNodePtr));
3789         if (cur->nodeTab == NULL) {
3790             xmlXPathErrMemory(NULL, "growing nodeset\n");
3791             return(-1);
3792         }
3793         memset(cur->nodeTab, 0 ,
3794                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3795         cur->nodeMax = XML_NODESET_DEFAULT;
3796     } else if (cur->nodeNr == cur->nodeMax) {
3797         xmlNodePtr *temp;
3798
3799         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3800             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3801             return(-1);
3802         }
3803         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3804                                       sizeof(xmlNodePtr));
3805         if (temp == NULL) {
3806             xmlXPathErrMemory(NULL, "growing nodeset\n");
3807             return(-1);
3808         }
3809         cur->nodeTab = temp;
3810         cur->nodeMax *= 2;
3811     }
3812     if (val->type == XML_NAMESPACE_DECL) {
3813         xmlNsPtr ns = (xmlNsPtr) val;
3814
3815         cur->nodeTab[cur->nodeNr++] =
3816             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3817     } else
3818         cur->nodeTab[cur->nodeNr++] = val;
3819     return(0);
3820 }
3821
3822 /**
3823  * xmlXPathNodeSetMerge:
3824  * @val1:  the first NodeSet or NULL
3825  * @val2:  the second NodeSet
3826  *
3827  * Merges two nodesets, all nodes from @val2 are added to @val1
3828  * if @val1 is NULL, a new set is created and copied from @val2
3829  *
3830  * Returns @val1 once extended or NULL in case of error.
3831  */
3832 xmlNodeSetPtr
3833 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3834     int i, j, initNr, skip;
3835     xmlNodePtr n1, n2;
3836
3837     if (val2 == NULL) return(val1);
3838     if (val1 == NULL) {
3839         val1 = xmlXPathNodeSetCreate(NULL);
3840     if (val1 == NULL)
3841         return (NULL);
3842 #if 0
3843         /*
3844         * TODO: The optimization won't work in every case, since
3845         *  those nasty namespace nodes need to be added with
3846         *  xmlXPathNodeSetDupNs() to the set; thus a pure
3847         *  memcpy is not possible.
3848         *  If there was a flag on the nodesetval, indicating that
3849         *  some temporary nodes are in, that would be helpfull.
3850         */
3851         /*
3852         * Optimization: Create an equally sized node-set
3853         * and memcpy the content.
3854         */
3855         val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3856         if (val1 == NULL)
3857             return(NULL);
3858         if (val2->nodeNr != 0) {
3859             if (val2->nodeNr == 1)
3860                 *(val1->nodeTab) = *(val2->nodeTab);
3861             else {
3862                 memcpy(val1->nodeTab, val2->nodeTab,
3863                     val2->nodeNr * sizeof(xmlNodePtr));
3864             }
3865             val1->nodeNr = val2->nodeNr;
3866         }
3867         return(val1);
3868 #endif
3869     }
3870
3871     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3872     initNr = val1->nodeNr;
3873
3874     for (i = 0;i < val2->nodeNr;i++) {
3875         n2 = val2->nodeTab[i];
3876         /*
3877          * check against duplicates
3878          */
3879         skip = 0;
3880         for (j = 0; j < initNr; j++) {
3881             n1 = val1->nodeTab[j];
3882             if (n1 == n2) {
3883                 skip = 1;
3884                 break;
3885             } else if ((n1->type == XML_NAMESPACE_DECL) &&
3886                        (n2->type == XML_NAMESPACE_DECL)) {
3887                 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3888                     (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3889                         ((xmlNsPtr) n2)->prefix)))
3890                 {
3891                     skip = 1;
3892                     break;
3893                 }
3894             }
3895         }
3896         if (skip)
3897             continue;
3898
3899         /*
3900          * grow the nodeTab if needed
3901          */
3902         if (val1->nodeMax == 0) {
3903             val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3904                                                     sizeof(xmlNodePtr));
3905             if (val1->nodeTab == NULL) {
3906                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3907                 return(NULL);
3908             }
3909             memset(val1->nodeTab, 0 ,
3910                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3911             val1->nodeMax = XML_NODESET_DEFAULT;
3912         } else if (val1->nodeNr == val1->nodeMax) {
3913             xmlNodePtr *temp;
3914
3915             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3916                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3917                 return(NULL);
3918             }
3919             temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3920                                              sizeof(xmlNodePtr));
3921             if (temp == NULL) {
3922                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3923                 return(NULL);
3924             }
3925             val1->nodeTab = temp;
3926             val1->nodeMax *= 2;
3927         }
3928         if (n2->type == XML_NAMESPACE_DECL) {
3929             xmlNsPtr ns = (xmlNsPtr) n2;
3930
3931             val1->nodeTab[val1->nodeNr++] =
3932                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3933         } else
3934             val1->nodeTab[val1->nodeNr++] = n2;
3935     }
3936
3937     return(val1);
3938 }
3939
3940
3941 /**
3942  * xmlXPathNodeSetMergeAndClear:
3943  * @set1:  the first NodeSet or NULL
3944  * @set2:  the second NodeSet
3945  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3946  *
3947  * Merges two nodesets, all nodes from @set2 are added to @set1
3948  * if @set1 is NULL, a new set is created and copied from @set2.
3949  * Checks for duplicate nodes. Clears set2.
3950  *
3951  * Returns @set1 once extended or NULL in case of error.
3952  */
3953 static xmlNodeSetPtr
3954 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3955                              int hasNullEntries)
3956 {
3957     if ((set1 == NULL) && (hasNullEntries == 0)) {
3958         /*
3959         * Note that doing a memcpy of the list, namespace nodes are
3960         * just assigned to set1, since set2 is cleared anyway.
3961         */
3962         set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3963         if (set1 == NULL)
3964             return(NULL);
3965         if (set2->nodeNr != 0) {
3966             memcpy(set1->nodeTab, set2->nodeTab,
3967                 set2->nodeNr * sizeof(xmlNodePtr));
3968             set1->nodeNr = set2->nodeNr;
3969         }
3970     } else {
3971         int i, j, initNbSet1;
3972         xmlNodePtr n1, n2;
3973
3974         if (set1 == NULL)
3975             set1 = xmlXPathNodeSetCreate(NULL);
3976         if (set1 == NULL)
3977             return (NULL);
3978
3979         initNbSet1 = set1->nodeNr;
3980         for (i = 0;i < set2->nodeNr;i++) {
3981             n2 = set2->nodeTab[i];
3982             /*
3983             * Skip NULLed entries.
3984             */
3985             if (n2 == NULL)
3986                 continue;
3987             /*
3988             * Skip duplicates.
3989             */
3990             for (j = 0; j < initNbSet1; j++) {
3991                 n1 = set1->nodeTab[j];
3992                 if (n1 == n2) {
3993                     goto skip_node;
3994                 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3995                     (n2->type == XML_NAMESPACE_DECL))
3996                 {
3997                     if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3998                         (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3999                         ((xmlNsPtr) n2)->prefix)))
4000                     {
4001                         /*
4002                         * Free the namespace node.
4003                         */
4004                         set2->nodeTab[i] = NULL;
4005                         xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
4006                         goto skip_node;
4007                     }
4008                 }
4009             }
4010             /*
4011             * grow the nodeTab if needed
4012             */
4013             if (set1->nodeMax == 0) {
4014                 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4015                     XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4016                 if (set1->nodeTab == NULL) {
4017                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4018                     return(NULL);
4019                 }
4020                 memset(set1->nodeTab, 0,
4021                     XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4022                 set1->nodeMax = XML_NODESET_DEFAULT;
4023             } else if (set1->nodeNr >= set1->nodeMax) {
4024                 xmlNodePtr *temp;
4025
4026                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4027                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4028                     return(NULL);
4029                 }
4030                 temp = (xmlNodePtr *) xmlRealloc(
4031                     set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4032                 if (temp == NULL) {
4033                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4034                     return(NULL);
4035                 }
4036                 set1->nodeTab = temp;
4037                 set1->nodeMax *= 2;
4038             }
4039             set1->nodeTab[set1->nodeNr++] = n2;
4040 skip_node:
4041             {}
4042         }
4043     }
4044     set2->nodeNr = 0;
4045     return(set1);
4046 }
4047
4048 /**
4049  * xmlXPathNodeSetMergeAndClearNoDupls:
4050  * @set1:  the first NodeSet or NULL
4051  * @set2:  the second NodeSet
4052  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4053  *
4054  * Merges two nodesets, all nodes from @set2 are added to @set1
4055  * if @set1 is NULL, a new set is created and copied from @set2.
4056  * Doesn't chack for duplicate nodes. Clears set2.
4057  *
4058  * Returns @set1 once extended or NULL in case of error.
4059  */
4060 static xmlNodeSetPtr
4061 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4062                                     int hasNullEntries)
4063 {
4064     if (set2 == NULL)
4065         return(set1);
4066     if ((set1 == NULL) && (hasNullEntries == 0)) {
4067         /*
4068         * Note that doing a memcpy of the list, namespace nodes are
4069         * just assigned to set1, since set2 is cleared anyway.
4070         */
4071         set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4072         if (set1 == NULL)
4073             return(NULL);
4074         if (set2->nodeNr != 0) {
4075             memcpy(set1->nodeTab, set2->nodeTab,
4076                 set2->nodeNr * sizeof(xmlNodePtr));
4077             set1->nodeNr = set2->nodeNr;
4078         }
4079     } else {
4080         int i;
4081         xmlNodePtr n2;
4082
4083         if (set1 == NULL)
4084             set1 = xmlXPathNodeSetCreate(NULL);
4085         if (set1 == NULL)
4086             return (NULL);
4087
4088         for (i = 0;i < set2->nodeNr;i++) {
4089             n2 = set2->nodeTab[i];
4090             /*
4091             * Skip NULLed entries.
4092             */
4093             if (n2 == NULL)
4094                 continue;
4095             if (set1->nodeMax == 0) {
4096                 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4097                     XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4098                 if (set1->nodeTab == NULL) {
4099                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4100                     return(NULL);
4101                 }
4102                 memset(set1->nodeTab, 0,
4103                     XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4104                 set1->nodeMax = XML_NODESET_DEFAULT;
4105             } else if (set1->nodeNr >= set1->nodeMax) {
4106                 xmlNodePtr *temp;
4107
4108                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4109                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4110                     return(NULL);
4111                 }
4112                 temp = (xmlNodePtr *) xmlRealloc(
4113                     set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4114                 if (temp == NULL) {
4115                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4116                     return(NULL);
4117                 }
4118                 set1->nodeTab = temp;
4119                 set1->nodeMax *= 2;
4120             }
4121             set1->nodeTab[set1->nodeNr++] = n2;
4122         }
4123     }
4124     set2->nodeNr = 0;
4125     return(set1);
4126 }
4127
4128 /**
4129  * xmlXPathNodeSetDel:
4130  * @cur:  the initial node set
4131  * @val:  an xmlNodePtr
4132  *
4133  * Removes an xmlNodePtr from an existing NodeSet
4134  */
4135 void
4136 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4137     int i;
4138
4139     if (cur == NULL) return;
4140     if (val == NULL) return;
4141
4142     /*
4143      * find node in nodeTab
4144      */
4145     for (i = 0;i < cur->nodeNr;i++)
4146         if (cur->nodeTab[i] == val) break;
4147
4148     if (i >= cur->nodeNr) {     /* not found */
4149 #ifdef DEBUG
4150         xmlGenericError(xmlGenericErrorContext,
4151                 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4152                 val->name);
4153 #endif
4154         return;
4155     }
4156     if ((cur->nodeTab[i] != NULL) &&
4157         (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4158         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4159     cur->nodeNr--;
4160     for (;i < cur->nodeNr;i++)
4161         cur->nodeTab[i] = cur->nodeTab[i + 1];
4162     cur->nodeTab[cur->nodeNr] = NULL;
4163 }
4164
4165 /**
4166  * xmlXPathNodeSetRemove:
4167  * @cur:  the initial node set
4168  * @val:  the index to remove
4169  *
4170  * Removes an entry from an existing NodeSet list.
4171  */
4172 void
4173 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4174     if (cur == NULL) return;
4175     if (val >= cur->nodeNr) return;
4176     if ((cur->nodeTab[val] != NULL) &&
4177         (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4178         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4179     cur->nodeNr--;
4180     for (;val < cur->nodeNr;val++)
4181         cur->nodeTab[val] = cur->nodeTab[val + 1];
4182     cur->nodeTab[cur->nodeNr] = NULL;
4183 }
4184
4185 /**
4186  * xmlXPathFreeNodeSet:
4187  * @obj:  the xmlNodeSetPtr to free
4188  *
4189  * Free the NodeSet compound (not the actual nodes !).
4190  */
4191 void
4192 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4193     if (obj == NULL) return;
4194     if (obj->nodeTab != NULL) {
4195         int i;
4196
4197         /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4198         for (i = 0;i < obj->nodeNr;i++)
4199             if ((obj->nodeTab[i] != NULL) &&
4200                 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4201                 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4202         xmlFree(obj->nodeTab);
4203     }
4204     xmlFree(obj);
4205 }
4206
4207 /**
4208  * xmlXPathNodeSetClearFromPos:
4209  * @set: the node set to be cleared
4210  * @pos: the start position to clear from
4211  *
4212  * Clears the list from temporary XPath objects (e.g. namespace nodes
4213  * are feed) starting with the entry at @pos, but does *not* free the list
4214  * itself. Sets the length of the list to @pos.
4215  */
4216 static void
4217 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4218 {
4219     if ((set == NULL) || (pos >= set->nodeNr))
4220         return;
4221     else if ((hasNsNodes)) {
4222         int i;
4223         xmlNodePtr node;
4224
4225         for (i = pos; i < set->nodeNr; i++) {
4226             node = set->nodeTab[i];
4227             if ((node != NULL) &&
4228                 (node->type == XML_NAMESPACE_DECL))
4229                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4230         }
4231     }
4232     set->nodeNr = pos;
4233 }
4234
4235 /**
4236  * xmlXPathNodeSetClear:
4237  * @set:  the node set to clear
4238  *
4239  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4240  * are feed), but does *not* free the list itself. Sets the length of the
4241  * list to 0.
4242  */
4243 static void
4244 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4245 {
4246     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4247 }
4248
4249 /**
4250  * xmlXPathNodeSetKeepLast:
4251  * @set: the node set to be cleared
4252  *
4253  * Move the last node to the first position and clear temporary XPath objects
4254  * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4255  * to 1.
4256  */
4257 static void
4258 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4259 {
4260     int i;
4261     xmlNodePtr node;
4262
4263     if ((set == NULL) || (set->nodeNr <= 1))
4264         return;
4265     for (i = 0; i < set->nodeNr - 1; i++) {
4266         node = set->nodeTab[i];
4267         if ((node != NULL) &&
4268             (node->type == XML_NAMESPACE_DECL))
4269             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4270     }
4271     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4272     set->nodeNr = 1;
4273 }
4274
4275 /**
4276  * xmlXPathFreeValueTree:
4277  * @obj:  the xmlNodeSetPtr to free
4278  *
4279  * Free the NodeSet compound and the actual tree, this is different
4280  * from xmlXPathFreeNodeSet()
4281  */
4282 static void
4283 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4284     int i;
4285
4286     if (obj == NULL) return;
4287
4288     if (obj->nodeTab != NULL) {
4289         for (i = 0;i < obj->nodeNr;i++) {
4290             if (obj->nodeTab[i] != NULL) {
4291                 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4292                     xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4293                 } else {
4294                     xmlFreeNodeList(obj->nodeTab[i]);
4295                 }
4296             }
4297         }
4298         xmlFree(obj->nodeTab);
4299     }
4300     xmlFree(obj);
4301 }
4302
4303 #if defined(DEBUG) || defined(DEBUG_STEP)
4304 /**
4305  * xmlGenericErrorContextNodeSet:
4306  * @output:  a FILE * for the output
4307  * @obj:  the xmlNodeSetPtr to display
4308  *
4309  * Quick display of a NodeSet
4310  */
4311 void
4312 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4313     int i;
4314
4315     if (output == NULL) output = xmlGenericErrorContext;
4316     if (obj == NULL)  {
4317         fprintf(output, "NodeSet == NULL !\n");
4318         return;
4319     }
4320     if (obj->nodeNr == 0) {
4321         fprintf(output, "NodeSet is empty\n");
4322         return;
4323     }
4324     if (obj->nodeTab == NULL) {
4325         fprintf(output, " nodeTab == NULL !\n");
4326         return;
4327     }
4328     for (i = 0; i < obj->nodeNr; i++) {
4329         if (obj->nodeTab[i] == NULL) {
4330             fprintf(output, " NULL !\n");
4331             return;
4332         }
4333         if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4334             (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4335             fprintf(output, " /");
4336         else if (obj->nodeTab[i]->name == NULL)
4337             fprintf(output, " noname!");
4338         else fprintf(output, " %s", obj->nodeTab[i]->name);
4339     }
4340     fprintf(output, "\n");
4341 }
4342 #endif
4343
4344 /**
4345  * xmlXPathNewNodeSet:
4346  * @val:  the NodePtr value
4347  *
4348  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4349  * it with the single Node @val
4350  *
4351  * Returns the newly created object.
4352  */
4353 xmlXPathObjectPtr
4354 xmlXPathNewNodeSet(xmlNodePtr val) {
4355     xmlXPathObjectPtr ret;
4356
4357     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4358     if (ret == NULL) {
4359         xmlXPathErrMemory(NULL, "creating nodeset\n");
4360         return(NULL);
4361     }
4362     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4363     ret->type = XPATH_NODESET;
4364     ret->boolval = 0;
4365     ret->nodesetval = xmlXPathNodeSetCreate(val);
4366     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4367 #ifdef XP_DEBUG_OBJ_USAGE
4368     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4369 #endif
4370     return(ret);
4371 }
4372
4373 /**
4374  * xmlXPathNewValueTree:
4375  * @val:  the NodePtr value
4376  *
4377  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4378  * it with the tree root @val
4379  *
4380  * Returns the newly created object.
4381  */
4382 xmlXPathObjectPtr
4383 xmlXPathNewValueTree(xmlNodePtr val) {
4384     xmlXPathObjectPtr ret;
4385
4386     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4387     if (ret == NULL) {
4388         xmlXPathErrMemory(NULL, "creating result value tree\n");
4389         return(NULL);
4390     }
4391     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4392     ret->type = XPATH_XSLT_TREE;
4393     ret->boolval = 1;
4394     ret->user = (void *) val;
4395     ret->nodesetval = xmlXPathNodeSetCreate(val);
4396 #ifdef XP_DEBUG_OBJ_USAGE
4397     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4398 #endif
4399     return(ret);
4400 }
4401
4402 /**
4403  * xmlXPathNewNodeSetList:
4404  * @val:  an existing NodeSet
4405  *
4406  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4407  * it with the Nodeset @val
4408  *
4409  * Returns the newly created object.
4410  */
4411 xmlXPathObjectPtr
4412 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4413 {
4414     xmlXPathObjectPtr ret;
4415     int i;
4416
4417     if (val == NULL)
4418         ret = NULL;
4419     else if (val->nodeTab == NULL)
4420         ret = xmlXPathNewNodeSet(NULL);
4421     else {
4422         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4423         if (ret) {
4424             for (i = 1; i < val->nodeNr; ++i) {
4425                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4426                     < 0) break;
4427             }
4428         }
4429     }
4430
4431     return (ret);
4432 }
4433
4434 /**
4435  * xmlXPathWrapNodeSet:
4436  * @val:  the NodePtr value
4437  *
4438  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4439  *
4440  * Returns the newly created object.
4441  */
4442 xmlXPathObjectPtr
4443 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4444     xmlXPathObjectPtr ret;
4445
4446     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4447     if (ret == NULL) {
4448         xmlXPathErrMemory(NULL, "creating node set object\n");
4449         return(NULL);
4450     }
4451     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4452     ret->type = XPATH_NODESET;
4453     ret->nodesetval = val;
4454 #ifdef XP_DEBUG_OBJ_USAGE
4455     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4456 #endif
4457     return(ret);
4458 }
4459
4460 /**
4461  * xmlXPathFreeNodeSetList:
4462  * @obj:  an existing NodeSetList object
4463  *
4464  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4465  * the list contrary to xmlXPathFreeObject().
4466  */
4467 void
4468 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4469     if (obj == NULL) return;
4470 #ifdef XP_DEBUG_OBJ_USAGE
4471     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4472 #endif
4473     xmlFree(obj);
4474 }
4475
4476 /**
4477  * xmlXPathDifference:
4478  * @nodes1:  a node-set
4479  * @nodes2:  a node-set
4480  *
4481  * Implements the EXSLT - Sets difference() function:
4482  *    node-set set:difference (node-set, node-set)
4483  *
4484  * Returns the difference between the two node sets, or nodes1 if
4485  *         nodes2 is empty
4486  */
4487 xmlNodeSetPtr
4488 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4489     xmlNodeSetPtr ret;
4490     int i, l1;
4491     xmlNodePtr cur;
4492
4493     if (xmlXPathNodeSetIsEmpty(nodes2))
4494         return(nodes1);
4495
4496     ret = xmlXPathNodeSetCreate(NULL);
4497     if (xmlXPathNodeSetIsEmpty(nodes1))
4498         return(ret);
4499
4500     l1 = xmlXPathNodeSetGetLength(nodes1);
4501
4502     for (i = 0; i < l1; i++) {
4503         cur = xmlXPathNodeSetItem(nodes1, i);
4504         if (!xmlXPathNodeSetContains(nodes2, cur)) {
4505             if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4506                 break;
4507         }
4508     }
4509     return(ret);
4510 }
4511
4512 /**
4513  * xmlXPathIntersection:
4514  * @nodes1:  a node-set
4515  * @nodes2:  a node-set
4516  *
4517  * Implements the EXSLT - Sets intersection() function:
4518  *    node-set set:intersection (node-set, node-set)
4519  *
4520  * Returns a node set comprising the nodes that are within both the
4521  *         node sets passed as arguments
4522  */
4523 xmlNodeSetPtr
4524 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4525     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4526     int i, l1;
4527     xmlNodePtr cur;
4528
4529     if (ret == NULL)
4530         return(ret);
4531     if (xmlXPathNodeSetIsEmpty(nodes1))
4532         return(ret);
4533     if (xmlXPathNodeSetIsEmpty(nodes2))
4534         return(ret);
4535
4536     l1 = xmlXPathNodeSetGetLength(nodes1);
4537
4538     for (i = 0; i < l1; i++) {
4539         cur = xmlXPathNodeSetItem(nodes1, i);
4540         if (xmlXPathNodeSetContains(nodes2, cur)) {
4541             if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4542                 break;
4543         }
4544     }
4545     return(ret);
4546 }
4547
4548 /**
4549  * xmlXPathDistinctSorted:
4550  * @nodes:  a node-set, sorted by document order
4551  *
4552  * Implements the EXSLT - Sets distinct() function:
4553  *    node-set set:distinct (node-set)
4554  *
4555  * Returns a subset of the nodes contained in @nodes, or @nodes if
4556  *         it is empty
4557  */
4558 xmlNodeSetPtr
4559 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4560     xmlNodeSetPtr ret;
4561     xmlHashTablePtr hash;
4562     int i, l;
4563     xmlChar * strval;
4564     xmlNodePtr cur;
4565
4566     if (xmlXPathNodeSetIsEmpty(nodes))
4567         return(nodes);
4568
4569     ret = xmlXPathNodeSetCreate(NULL);
4570     if (ret == NULL)
4571         return(ret);
4572     l = xmlXPathNodeSetGetLength(nodes);
4573     hash = xmlHashCreate (l);
4574     for (i = 0; i < l; i++) {
4575         cur = xmlXPathNodeSetItem(nodes, i);
4576         strval = xmlXPathCastNodeToString(cur);
4577         if (xmlHashLookup(hash, strval) == NULL) {
4578             xmlHashAddEntry(hash, strval, strval);
4579             if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4580                 break;
4581         } else {
4582             xmlFree(strval);
4583         }
4584     }
4585     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4586     return(ret);
4587 }
4588
4589 /**
4590  * xmlXPathDistinct:
4591  * @nodes:  a node-set
4592  *
4593  * Implements the EXSLT - Sets distinct() function:
4594  *    node-set set:distinct (node-set)
4595  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4596  * is called with the sorted node-set
4597  *
4598  * Returns a subset of the nodes contained in @nodes, or @nodes if
4599  *         it is empty
4600  */
4601 xmlNodeSetPtr
4602 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4603     if (xmlXPathNodeSetIsEmpty(nodes))
4604         return(nodes);
4605
4606     xmlXPathNodeSetSort(nodes);
4607     return(xmlXPathDistinctSorted(nodes));
4608 }
4609
4610 /**
4611  * xmlXPathHasSameNodes:
4612  * @nodes1:  a node-set
4613  * @nodes2:  a node-set
4614  *
4615  * Implements the EXSLT - Sets has-same-nodes function:
4616  *    boolean set:has-same-node(node-set, node-set)
4617  *
4618  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4619  *         otherwise
4620  */
4621 int
4622 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4623     int i, l;
4624     xmlNodePtr cur;
4625
4626     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4627         xmlXPathNodeSetIsEmpty(nodes2))
4628         return(0);
4629
4630     l = xmlXPathNodeSetGetLength(nodes1);
4631     for (i = 0; i < l; i++) {
4632         cur = xmlXPathNodeSetItem(nodes1, i);
4633         if (xmlXPathNodeSetContains(nodes2, cur))
4634             return(1);
4635     }
4636     return(0);
4637 }
4638
4639 /**
4640  * xmlXPathNodeLeadingSorted:
4641  * @nodes: a node-set, sorted by document order
4642  * @node: a node
4643  *
4644  * Implements the EXSLT - Sets leading() function:
4645  *    node-set set:leading (node-set, node-set)
4646  *
4647  * Returns the nodes in @nodes that precede @node in document order,
4648  *         @nodes if @node is NULL or an empty node-set if @nodes
4649  *         doesn't contain @node
4650  */
4651 xmlNodeSetPtr
4652 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4653     int i, l;
4654     xmlNodePtr cur;
4655     xmlNodeSetPtr ret;
4656
4657     if (node == NULL)
4658         return(nodes);
4659
4660     ret = xmlXPathNodeSetCreate(NULL);
4661     if (ret == NULL)
4662         return(ret);
4663     if (xmlXPathNodeSetIsEmpty(nodes) ||
4664         (!xmlXPathNodeSetContains(nodes, node)))
4665         return(ret);
4666
4667     l = xmlXPathNodeSetGetLength(nodes);
4668     for (i = 0; i < l; i++) {
4669         cur = xmlXPathNodeSetItem(nodes, i);
4670         if (cur == node)
4671             break;
4672         if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4673             break;
4674     }
4675     return(ret);
4676 }
4677
4678 /**
4679  * xmlXPathNodeLeading:
4680  * @nodes:  a node-set
4681  * @node:  a node
4682  *
4683  * Implements the EXSLT - Sets leading() function:
4684  *    node-set set:leading (node-set, node-set)
4685  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4686  * is called.
4687  *
4688  * Returns the nodes in @nodes that precede @node in document order,
4689  *         @nodes if @node is NULL or an empty node-set if @nodes
4690  *         doesn't contain @node
4691  */
4692 xmlNodeSetPtr
4693 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4694     xmlXPathNodeSetSort(nodes);
4695     return(xmlXPathNodeLeadingSorted(nodes, node));
4696 }
4697
4698 /**
4699  * xmlXPathLeadingSorted:
4700  * @nodes1:  a node-set, sorted by document order
4701  * @nodes2:  a node-set, sorted by document order
4702  *
4703  * Implements the EXSLT - Sets leading() function:
4704  *    node-set set:leading (node-set, node-set)
4705  *
4706  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4707  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4708  *         an empty node-set if @nodes1 doesn't contain @nodes2
4709  */
4710 xmlNodeSetPtr
4711 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4712     if (xmlXPathNodeSetIsEmpty(nodes2))
4713         return(nodes1);
4714     return(xmlXPathNodeLeadingSorted(nodes1,
4715                                      xmlXPathNodeSetItem(nodes2, 1)));
4716 }
4717
4718 /**
4719  * xmlXPathLeading:
4720  * @nodes1:  a node-set
4721  * @nodes2:  a node-set
4722  *
4723  * Implements the EXSLT - Sets leading() function:
4724  *    node-set set:leading (node-set, node-set)
4725  * @nodes1 and @nodes2 are sorted by document order, then
4726  * #exslSetsLeadingSorted is called.
4727  *
4728  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4729  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4730  *         an empty node-set if @nodes1 doesn't contain @nodes2
4731  */
4732 xmlNodeSetPtr
4733 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4734     if (xmlXPathNodeSetIsEmpty(nodes2))
4735         return(nodes1);
4736     if (xmlXPathNodeSetIsEmpty(nodes1))
4737         return(xmlXPathNodeSetCreate(NULL));
4738     xmlXPathNodeSetSort(nodes1);
4739     xmlXPathNodeSetSort(nodes2);
4740     return(xmlXPathNodeLeadingSorted(nodes1,
4741                                      xmlXPathNodeSetItem(nodes2, 1)));
4742 }
4743
4744 /**
4745  * xmlXPathNodeTrailingSorted:
4746  * @nodes: a node-set, sorted by document order
4747  * @node: a node
4748  *
4749  * Implements the EXSLT - Sets trailing() function:
4750  *    node-set set:trailing (node-set, node-set)
4751  *
4752  * Returns the nodes in @nodes that follow @node in document order,
4753  *         @nodes if @node is NULL or an empty node-set if @nodes
4754  *         doesn't contain @node
4755  */
4756 xmlNodeSetPtr
4757 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4758     int i, l;
4759     xmlNodePtr cur;
4760     xmlNodeSetPtr ret;
4761
4762     if (node == NULL)
4763         return(nodes);
4764
4765     ret = xmlXPathNodeSetCreate(NULL);
4766     if (ret == NULL)
4767         return(ret);
4768     if (xmlXPathNodeSetIsEmpty(nodes) ||
4769         (!xmlXPathNodeSetContains(nodes, node)))
4770         return(ret);
4771
4772     l = xmlXPathNodeSetGetLength(nodes);
4773     for (i = l - 1; i >= 0; i--) {
4774         cur = xmlXPathNodeSetItem(nodes, i);
4775         if (cur == node)
4776             break;
4777         if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4778             break;
4779     }
4780     xmlXPathNodeSetSort(ret);   /* bug 413451 */
4781     return(ret);
4782 }
4783
4784 /**
4785  * xmlXPathNodeTrailing:
4786  * @nodes:  a node-set
4787  * @node:  a node
4788  *
4789  * Implements the EXSLT - Sets trailing() function:
4790  *    node-set set:trailing (node-set, node-set)
4791  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4792  * is called.
4793  *
4794  * Returns the nodes in @nodes that follow @node in document order,
4795  *         @nodes if @node is NULL or an empty node-set if @nodes
4796  *         doesn't contain @node
4797  */
4798 xmlNodeSetPtr
4799 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4800     xmlXPathNodeSetSort(nodes);
4801     return(xmlXPathNodeTrailingSorted(nodes, node));
4802 }
4803
4804 /**
4805  * xmlXPathTrailingSorted:
4806  * @nodes1:  a node-set, sorted by document order
4807  * @nodes2:  a node-set, sorted by document order
4808  *
4809  * Implements the EXSLT - Sets trailing() function:
4810  *    node-set set:trailing (node-set, node-set)
4811  *
4812  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4813  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4814  *         an empty node-set if @nodes1 doesn't contain @nodes2
4815  */
4816 xmlNodeSetPtr
4817 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4818     if (xmlXPathNodeSetIsEmpty(nodes2))
4819         return(nodes1);
4820     return(xmlXPathNodeTrailingSorted(nodes1,
4821                                       xmlXPathNodeSetItem(nodes2, 0)));
4822 }
4823
4824 /**
4825  * xmlXPathTrailing:
4826  * @nodes1:  a node-set
4827  * @nodes2:  a node-set
4828  *
4829  * Implements the EXSLT - Sets trailing() function:
4830  *    node-set set:trailing (node-set, node-set)
4831  * @nodes1 and @nodes2 are sorted by document order, then
4832  * #xmlXPathTrailingSorted is called.
4833  *
4834  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4835  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4836  *         an empty node-set if @nodes1 doesn't contain @nodes2
4837  */
4838 xmlNodeSetPtr
4839 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4840     if (xmlXPathNodeSetIsEmpty(nodes2))
4841         return(nodes1);
4842     if (xmlXPathNodeSetIsEmpty(nodes1))
4843         return(xmlXPathNodeSetCreate(NULL));
4844     xmlXPathNodeSetSort(nodes1);
4845     xmlXPathNodeSetSort(nodes2);
4846     return(xmlXPathNodeTrailingSorted(nodes1,
4847                                       xmlXPathNodeSetItem(nodes2, 0)));
4848 }
4849
4850 /************************************************************************
4851  *                                                                      *
4852  *              Routines to handle extra functions                      *
4853  *                                                                      *
4854  ************************************************************************/
4855
4856 /**
4857  * xmlXPathRegisterFunc:
4858  * @ctxt:  the XPath context
4859  * @name:  the function name
4860  * @f:  the function implementation or NULL
4861  *
4862  * Register a new function. If @f is NULL it unregisters the function
4863  *
4864  * Returns 0 in case of success, -1 in case of error
4865  */
4866 int
4867 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4868                      xmlXPathFunction f) {
4869     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4870 }
4871
4872 /**
4873  * xmlXPathRegisterFuncNS:
4874  * @ctxt:  the XPath context
4875  * @name:  the function name
4876  * @ns_uri:  the function namespace URI
4877  * @f:  the function implementation or NULL
4878  *
4879  * Register a new function. If @f is NULL it unregisters the function
4880  *
4881  * Returns 0 in case of success, -1 in case of error
4882  */
4883 int
4884 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4885                        const xmlChar *ns_uri, xmlXPathFunction f) {
4886     if (ctxt == NULL)
4887         return(-1);
4888     if (name == NULL)
4889         return(-1);
4890
4891     if (ctxt->funcHash == NULL)
4892         ctxt->funcHash = xmlHashCreate(0);
4893     if (ctxt->funcHash == NULL)
4894         return(-1);
4895     if (f == NULL)
4896         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4897     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4898 }
4899
4900 /**
4901  * xmlXPathRegisterFuncLookup:
4902  * @ctxt:  the XPath context
4903  * @f:  the lookup function
4904  * @funcCtxt:  the lookup data
4905  *
4906  * Registers an external mechanism to do function lookup.
4907  */
4908 void
4909 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4910                             xmlXPathFuncLookupFunc f,
4911                             void *funcCtxt) {
4912     if (ctxt == NULL)
4913         return;
4914     ctxt->funcLookupFunc = f;
4915     ctxt->funcLookupData = funcCtxt;
4916 }
4917
4918 /**
4919  * xmlXPathFunctionLookup:
4920  * @ctxt:  the XPath context
4921  * @name:  the function name
4922  *
4923  * Search in the Function array of the context for the given
4924  * function.
4925  *
4926  * Returns the xmlXPathFunction or NULL if not found
4927  */
4928 xmlXPathFunction
4929 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4930     if (ctxt == NULL)
4931         return (NULL);
4932
4933     if (ctxt->funcLookupFunc != NULL) {
4934         xmlXPathFunction ret;
4935         xmlXPathFuncLookupFunc f;
4936
4937         f = ctxt->funcLookupFunc;
4938         ret = f(ctxt->funcLookupData, name, NULL);
4939         if (ret != NULL)
4940             return(ret);
4941     }
4942     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4943 }
4944
4945 /**
4946  * xmlXPathFunctionLookupNS:
4947  * @ctxt:  the XPath context
4948  * @name:  the function name
4949  * @ns_uri:  the function namespace URI
4950  *
4951  * Search in the Function array of the context for the given
4952  * function.
4953  *
4954  * Returns the xmlXPathFunction or NULL if not found
4955  */
4956 xmlXPathFunction
4957 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4958                          const xmlChar *ns_uri) {
4959     xmlXPathFunction ret;
4960
4961     if (ctxt == NULL)
4962         return(NULL);
4963     if (name == NULL)
4964         return(NULL);
4965
4966     if (ctxt->funcLookupFunc != NULL) {
4967         xmlXPathFuncLookupFunc f;
4968
4969         f = ctxt->funcLookupFunc;
4970         ret = f(ctxt->funcLookupData, name, ns_uri);
4971         if (ret != NULL)
4972             return(ret);
4973     }
4974
4975     if (ctxt->funcHash == NULL)
4976         return(NULL);
4977
4978     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4979     return(ret);
4980 }
4981
4982 /**
4983  * xmlXPathRegisteredFuncsCleanup:
4984  * @ctxt:  the XPath context
4985  *
4986  * Cleanup the XPath context data associated to registered functions
4987  */
4988 void
4989 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4990     if (ctxt == NULL)
4991         return;
4992
4993     xmlHashFree(ctxt->funcHash, NULL);
4994     ctxt->funcHash = NULL;
4995 }
4996
4997 /************************************************************************
4998  *                                                                      *
4999  *                      Routines to handle Variables                    *
5000  *                                                                      *
5001  ************************************************************************/
5002
5003 /**
5004  * xmlXPathRegisterVariable:
5005  * @ctxt:  the XPath context
5006  * @name:  the variable name
5007  * @value:  the variable value or NULL
5008  *
5009  * Register a new variable value. If @value is NULL it unregisters
5010  * the variable
5011  *
5012  * Returns 0 in case of success, -1 in case of error
5013  */
5014 int
5015 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5016                          xmlXPathObjectPtr value) {
5017     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5018 }
5019
5020 /**
5021  * xmlXPathRegisterVariableNS:
5022  * @ctxt:  the XPath context
5023  * @name:  the variable name
5024  * @ns_uri:  the variable namespace URI
5025  * @value:  the variable value or NULL
5026  *
5027  * Register a new variable value. If @value is NULL it unregisters
5028  * the variable
5029  *
5030  * Returns 0 in case of success, -1 in case of error
5031  */
5032 int
5033 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5034                            const xmlChar *ns_uri,
5035                            xmlXPathObjectPtr value) {
5036     if (ctxt == NULL)
5037         return(-1);
5038     if (name == NULL)
5039         return(-1);
5040
5041     if (ctxt->varHash == NULL)
5042         ctxt->varHash = xmlHashCreate(0);
5043     if (ctxt->varHash == NULL)
5044         return(-1);
5045     if (value == NULL)
5046         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5047                                    (xmlHashDeallocator)xmlXPathFreeObject));
5048     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5049                                (void *) value,
5050                                (xmlHashDeallocator)xmlXPathFreeObject));
5051 }
5052
5053 /**
5054  * xmlXPathRegisterVariableLookup:
5055  * @ctxt:  the XPath context
5056  * @f:  the lookup function
5057  * @data:  the lookup data
5058  *
5059  * register an external mechanism to do variable lookup
5060  */
5061 void
5062 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5063          xmlXPathVariableLookupFunc f, void *data) {
5064     if (ctxt == NULL)
5065         return;
5066     ctxt->varLookupFunc = f;
5067     ctxt->varLookupData = data;
5068 }
5069
5070 /**
5071  * xmlXPathVariableLookup:
5072  * @ctxt:  the XPath context
5073  * @name:  the variable name
5074  *
5075  * Search in the Variable array of the context for the given
5076  * variable value.
5077  *
5078  * Returns a copy of the value or NULL if not found
5079  */
5080 xmlXPathObjectPtr
5081 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5082     if (ctxt == NULL)
5083         return(NULL);
5084
5085     if (ctxt->varLookupFunc != NULL) {
5086         xmlXPathObjectPtr ret;
5087
5088         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5089                 (ctxt->varLookupData, name, NULL);
5090         return(ret);
5091     }
5092     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5093 }
5094
5095 /**
5096  * xmlXPathVariableLookupNS:
5097  * @ctxt:  the XPath context
5098  * @name:  the variable name
5099  * @ns_uri:  the variable namespace URI
5100  *
5101  * Search in the Variable array of the context for the given
5102  * variable value.
5103  *
5104  * Returns the a copy of the value or NULL if not found
5105  */
5106 xmlXPathObjectPtr
5107 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5108                          const xmlChar *ns_uri) {
5109     if (ctxt == NULL)
5110         return(NULL);
5111
5112     if (ctxt->varLookupFunc != NULL) {
5113         xmlXPathObjectPtr ret;
5114
5115         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5116                 (ctxt->varLookupData, name, ns_uri);
5117         if (ret != NULL) return(ret);
5118     }
5119
5120     if (ctxt->varHash == NULL)
5121         return(NULL);
5122     if (name == NULL)
5123         return(NULL);
5124
5125     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5126                 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5127 }
5128
5129 /**
5130  * xmlXPathRegisteredVariablesCleanup:
5131  * @ctxt:  the XPath context
5132  *
5133  * Cleanup the XPath context data associated to registered variables
5134  */
5135 void
5136 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5137     if (ctxt == NULL)
5138         return;
5139
5140     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5141     ctxt->varHash = NULL;
5142 }
5143
5144 /**
5145  * xmlXPathRegisterNs:
5146  * @ctxt:  the XPath context
5147  * @prefix:  the namespace prefix cannot be NULL or empty string
5148  * @ns_uri:  the namespace name
5149  *
5150  * Register a new namespace. If @ns_uri is NULL it unregisters
5151  * the namespace
5152  *
5153  * Returns 0 in case of success, -1 in case of error
5154  */
5155 int
5156 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5157                            const xmlChar *ns_uri) {
5158     if (ctxt == NULL)
5159         return(-1);
5160     if (prefix == NULL)
5161         return(-1);
5162     if (prefix[0] == 0)
5163         return(-1);
5164
5165     if (ctxt->nsHash == NULL)
5166         ctxt->nsHash = xmlHashCreate(10);
5167     if (ctxt->nsHash == NULL)
5168         return(-1);
5169     if (ns_uri == NULL)
5170         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5171                                   (xmlHashDeallocator)xmlFree));
5172     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5173                               (xmlHashDeallocator)xmlFree));
5174 }
5175
5176 /**
5177  * xmlXPathNsLookup:
5178  * @ctxt:  the XPath context
5179  * @prefix:  the namespace prefix value
5180  *
5181  * Search in the namespace declaration array of the context for the given
5182  * namespace name associated to the given prefix
5183  *
5184  * Returns the value or NULL if not found
5185  */
5186 const xmlChar *
5187 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5188     if (ctxt == NULL)
5189         return(NULL);
5190     if (prefix == NULL)
5191         return(NULL);
5192
5193 #ifdef XML_XML_NAMESPACE
5194     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5195         return(XML_XML_NAMESPACE);
5196 #endif
5197
5198     if (ctxt->namespaces != NULL) {
5199         int i;
5200
5201         for (i = 0;i < ctxt->nsNr;i++) {
5202             if ((ctxt->namespaces[i] != NULL) &&
5203                 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5204                 return(ctxt->namespaces[i]->href);
5205         }
5206     }
5207
5208     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5209 }
5210
5211 /**
5212  * xmlXPathRegisteredNsCleanup:
5213  * @ctxt:  the XPath context
5214  *
5215  * Cleanup the XPath context data associated to registered variables
5216  */
5217 void
5218 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5219     if (ctxt == NULL)
5220         return;
5221
5222     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5223     ctxt->nsHash = NULL;
5224 }
5225
5226 /************************************************************************
5227  *                                                                      *
5228  *                      Routines to handle Values                       *
5229  *                                                                      *
5230  ************************************************************************/
5231
5232 /* Allocations are terrible, one needs to optimize all this !!! */
5233
5234 /**
5235  * xmlXPathNewFloat:
5236  * @val:  the double value
5237  *
5238  * Create a new xmlXPathObjectPtr of type double and of value @val
5239  *
5240  * Returns the newly created object.
5241  */
5242 xmlXPathObjectPtr
5243 xmlXPathNewFloat(double val) {
5244     xmlXPathObjectPtr ret;
5245
5246     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247     if (ret == NULL) {
5248         xmlXPathErrMemory(NULL, "creating float object\n");
5249         return(NULL);
5250     }
5251     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5252     ret->type = XPATH_NUMBER;
5253     ret->floatval = val;
5254 #ifdef XP_DEBUG_OBJ_USAGE
5255     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5256 #endif
5257     return(ret);
5258 }
5259
5260 /**
5261  * xmlXPathNewBoolean:
5262  * @val:  the boolean value
5263  *
5264  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5265  *
5266  * Returns the newly created object.
5267  */
5268 xmlXPathObjectPtr
5269 xmlXPathNewBoolean(int val) {
5270     xmlXPathObjectPtr ret;
5271
5272     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5273     if (ret == NULL) {
5274         xmlXPathErrMemory(NULL, "creating boolean object\n");
5275         return(NULL);
5276     }
5277     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5278     ret->type = XPATH_BOOLEAN;
5279     ret->boolval = (val != 0);
5280 #ifdef XP_DEBUG_OBJ_USAGE
5281     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5282 #endif
5283     return(ret);
5284 }
5285
5286 /**
5287  * xmlXPathNewString:
5288  * @val:  the xmlChar * value
5289  *
5290  * Create a new xmlXPathObjectPtr of type string and of value @val
5291  *
5292  * Returns the newly created object.
5293  */
5294 xmlXPathObjectPtr
5295 xmlXPathNewString(const xmlChar *val) {
5296     xmlXPathObjectPtr ret;
5297
5298     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5299     if (ret == NULL) {
5300         xmlXPathErrMemory(NULL, "creating string object\n");
5301         return(NULL);
5302     }
5303     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5304     ret->type = XPATH_STRING;
5305     if (val != NULL)
5306         ret->stringval = xmlStrdup(val);
5307     else
5308         ret->stringval = xmlStrdup((const xmlChar *)"");
5309 #ifdef XP_DEBUG_OBJ_USAGE
5310     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5311 #endif
5312     return(ret);
5313 }
5314
5315 /**
5316  * xmlXPathWrapString:
5317  * @val:  the xmlChar * value
5318  *
5319  * Wraps the @val string into an XPath object.
5320  *
5321  * Returns the newly created object.
5322  */
5323 xmlXPathObjectPtr
5324 xmlXPathWrapString (xmlChar *val) {
5325     xmlXPathObjectPtr ret;
5326
5327     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5328     if (ret == NULL) {
5329         xmlXPathErrMemory(NULL, "creating string object\n");
5330         return(NULL);
5331     }
5332     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5333     ret->type = XPATH_STRING;
5334     ret->stringval = val;
5335 #ifdef XP_DEBUG_OBJ_USAGE
5336     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5337 #endif
5338     return(ret);
5339 }
5340
5341 /**
5342  * xmlXPathNewCString:
5343  * @val:  the char * value
5344  *
5345  * Create a new xmlXPathObjectPtr of type string and of value @val
5346  *
5347  * Returns the newly created object.
5348  */
5349 xmlXPathObjectPtr
5350 xmlXPathNewCString(const char *val) {
5351     xmlXPathObjectPtr ret;
5352
5353     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5354     if (ret == NULL) {
5355         xmlXPathErrMemory(NULL, "creating string object\n");
5356         return(NULL);
5357     }
5358     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5359     ret->type = XPATH_STRING;
5360     ret->stringval = xmlStrdup(BAD_CAST val);
5361 #ifdef XP_DEBUG_OBJ_USAGE
5362     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5363 #endif
5364     return(ret);
5365 }
5366
5367 /**
5368  * xmlXPathWrapCString:
5369  * @val:  the char * value
5370  *
5371  * Wraps a string into an XPath object.
5372  *
5373  * Returns the newly created object.
5374  */
5375 xmlXPathObjectPtr
5376 xmlXPathWrapCString (char * val) {
5377     return(xmlXPathWrapString((xmlChar *)(val)));
5378 }
5379
5380 /**
5381  * xmlXPathWrapExternal:
5382  * @val:  the user data
5383  *
5384  * Wraps the @val data into an XPath object.
5385  *
5386  * Returns the newly created object.
5387  */
5388 xmlXPathObjectPtr
5389 xmlXPathWrapExternal (void *val) {
5390     xmlXPathObjectPtr ret;
5391
5392     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5393     if (ret == NULL) {
5394         xmlXPathErrMemory(NULL, "creating user object\n");
5395         return(NULL);
5396     }
5397     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5398     ret->type = XPATH_USERS;
5399     ret->user = val;
5400 #ifdef XP_DEBUG_OBJ_USAGE
5401     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5402 #endif
5403     return(ret);
5404 }
5405
5406 /**
5407  * xmlXPathObjectCopy:
5408  * @val:  the original object
5409  *
5410  * allocate a new copy of a given object
5411  *
5412  * Returns the newly created object.
5413  */
5414 xmlXPathObjectPtr
5415 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5416     xmlXPathObjectPtr ret;
5417
5418     if (val == NULL)
5419         return(NULL);
5420
5421     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5422     if (ret == NULL) {
5423         xmlXPathErrMemory(NULL, "copying object\n");
5424         return(NULL);
5425     }
5426     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5427 #ifdef XP_DEBUG_OBJ_USAGE
5428     xmlXPathDebugObjUsageRequested(NULL, val->type);
5429 #endif
5430     switch (val->type) {
5431         case XPATH_BOOLEAN:
5432         case XPATH_NUMBER:
5433         case XPATH_POINT:
5434         case XPATH_RANGE:
5435             break;
5436         case XPATH_STRING:
5437             ret->stringval = xmlStrdup(val->stringval);
5438             break;
5439         case XPATH_XSLT_TREE:
5440 #if 0
5441 /*
5442   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5443   this previous handling is no longer correct, and can cause some serious
5444   problems (ref. bug 145547)
5445 */
5446             if ((val->nodesetval != NULL) &&
5447                 (val->nodesetval->nodeTab != NULL)) {
5448                 xmlNodePtr cur, tmp;
5449                 xmlDocPtr top;
5450
5451                 ret->boolval = 1;
5452                 top =  xmlNewDoc(NULL);
5453                 top->name = (char *)
5454                     xmlStrdup(val->nodesetval->nodeTab[0]->name);
5455                 ret->user = top;
5456                 if (top != NULL) {
5457                     top->doc = top;
5458                     cur = val->nodesetval->nodeTab[0]->children;
5459                     while (cur != NULL) {
5460                         tmp = xmlDocCopyNode(cur, top, 1);
5461                         xmlAddChild((xmlNodePtr) top, tmp);
5462                         cur = cur->next;
5463                     }
5464                 }
5465
5466                 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5467             } else
5468                 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5469             /* Deallocate the copied tree value */
5470             break;
5471 #endif
5472         case XPATH_NODESET:
5473             ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5474             /* Do not deallocate the copied tree value */
5475             ret->boolval = 0;
5476             break;
5477         case XPATH_LOCATIONSET:
5478 #ifdef LIBXML_XPTR_ENABLED
5479         {
5480             xmlLocationSetPtr loc = val->user;
5481             ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5482             break;
5483         }
5484 #endif
5485         case XPATH_USERS:
5486             ret->user = val->user;
5487             break;
5488         case XPATH_UNDEFINED:
5489             xmlGenericError(xmlGenericErrorContext,
5490                     "xmlXPathObjectCopy: unsupported type %d\n",
5491                     val->type);
5492             break;
5493     }
5494     return(ret);
5495 }
5496
5497 /**
5498  * xmlXPathFreeObject:
5499  * @obj:  the object to free
5500  *
5501  * Free up an xmlXPathObjectPtr object.
5502  */
5503 void
5504 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5505     if (obj == NULL) return;
5506     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5507         if (obj->boolval) {
5508 #if 0
5509             if (obj->user != NULL) {
5510                 xmlXPathFreeNodeSet(obj->nodesetval);
5511                 xmlFreeNodeList((xmlNodePtr) obj->user);
5512             } else
5513 #endif
5514             obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5515             if (obj->nodesetval != NULL)
5516                 xmlXPathFreeValueTree(obj->nodesetval);
5517         } else {
5518             if (obj->nodesetval != NULL)
5519                 xmlXPathFreeNodeSet(obj->nodesetval);
5520         }
5521 #ifdef LIBXML_XPTR_ENABLED
5522     } else if (obj->type == XPATH_LOCATIONSET) {
5523         if (obj->user != NULL)
5524             xmlXPtrFreeLocationSet(obj->user);
5525 #endif
5526     } else if (obj->type == XPATH_STRING) {
5527         if (obj->stringval != NULL)
5528             xmlFree(obj->stringval);
5529     }
5530 #ifdef XP_DEBUG_OBJ_USAGE
5531     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5532 #endif
5533     xmlFree(obj);
5534 }
5535
5536 /**
5537  * xmlXPathReleaseObject:
5538  * @obj:  the xmlXPathObjectPtr to free or to cache
5539  *
5540  * Depending on the state of the cache this frees the given
5541  * XPath object or stores it in the cache.
5542  */
5543 static void
5544 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5545 {
5546 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5547         sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5548     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5549
5550 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5551
5552     if (obj == NULL)
5553         return;
5554     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5555          xmlXPathFreeObject(obj);
5556     } else {
5557         xmlXPathContextCachePtr cache =
5558             (xmlXPathContextCachePtr) ctxt->cache;
5559
5560         switch (obj->type) {
5561             case XPATH_NODESET:
5562             case XPATH_XSLT_TREE:
5563                 if (obj->nodesetval != NULL) {
5564                     if (obj->boolval) {
5565                         /*
5566                         * It looks like the @boolval is used for
5567                         * evaluation if this an XSLT Result Tree Fragment.
5568                         * TODO: Check if this assumption is correct.
5569                         */
5570                         obj->type = XPATH_XSLT_TREE; /* just for debugging */
5571                         xmlXPathFreeValueTree(obj->nodesetval);
5572                         obj->nodesetval = NULL;
5573                     } else if ((obj->nodesetval->nodeMax <= 40) &&
5574                         (XP_CACHE_WANTS(cache->nodesetObjs,
5575                                         cache->maxNodeset)))
5576                     {
5577                         XP_CACHE_ADD(cache->nodesetObjs, obj);
5578                         goto obj_cached;
5579                     } else {
5580                         xmlXPathFreeNodeSet(obj->nodesetval);
5581                         obj->nodesetval = NULL;
5582                     }
5583                 }
5584                 break;
5585             case XPATH_STRING:
5586                 if (obj->stringval != NULL)
5587                     xmlFree(obj->stringval);
5588
5589                 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5590                     XP_CACHE_ADD(cache->stringObjs, obj);
5591                     goto obj_cached;
5592                 }
5593                 break;
5594             case XPATH_BOOLEAN:
5595                 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5596                     XP_CACHE_ADD(cache->booleanObjs, obj);
5597                     goto obj_cached;
5598                 }
5599                 break;
5600             case XPATH_NUMBER:
5601                 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5602                     XP_CACHE_ADD(cache->numberObjs, obj);
5603                     goto obj_cached;
5604                 }
5605                 break;
5606 #ifdef LIBXML_XPTR_ENABLED
5607             case XPATH_LOCATIONSET:
5608                 if (obj->user != NULL) {
5609                     xmlXPtrFreeLocationSet(obj->user);
5610                 }
5611                 goto free_obj;
5612 #endif
5613             default:
5614                 goto free_obj;
5615         }
5616
5617         /*
5618         * Fallback to adding to the misc-objects slot.
5619         */
5620         if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5621             XP_CACHE_ADD(cache->miscObjs, obj);
5622         } else
5623             goto free_obj;
5624
5625 obj_cached:
5626
5627 #ifdef XP_DEBUG_OBJ_USAGE
5628         xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5629 #endif
5630
5631         if (obj->nodesetval != NULL) {
5632             xmlNodeSetPtr tmpset = obj->nodesetval;
5633
5634             /*
5635             * TODO: Due to those nasty ns-nodes, we need to traverse
5636             *  the list and free the ns-nodes.
5637             * URGENT TODO: Check if it's actually slowing things down.
5638             *  Maybe we shouldn't try to preserve the list.
5639             */
5640             if (tmpset->nodeNr > 1) {
5641                 int i;
5642                 xmlNodePtr node;
5643
5644                 for (i = 0; i < tmpset->nodeNr; i++) {
5645                     node = tmpset->nodeTab[i];
5646                     if ((node != NULL) &&
5647                         (node->type == XML_NAMESPACE_DECL))
5648                     {
5649                         xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5650                     }
5651                 }
5652             } else if (tmpset->nodeNr == 1) {
5653                 if ((tmpset->nodeTab[0] != NULL) &&
5654                     (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5655                     xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5656             }
5657             tmpset->nodeNr = 0;
5658             memset(obj, 0, sizeof(xmlXPathObject));
5659             obj->nodesetval = tmpset;
5660         } else
5661             memset(obj, 0, sizeof(xmlXPathObject));
5662
5663         return;
5664
5665 free_obj:
5666         /*
5667         * Cache is full; free the object.
5668         */
5669         if (obj->nodesetval != NULL)
5670             xmlXPathFreeNodeSet(obj->nodesetval);
5671 #ifdef XP_DEBUG_OBJ_USAGE
5672         xmlXPathDebugObjUsageReleased(NULL, obj->type);
5673 #endif
5674         xmlFree(obj);
5675     }
5676     return;
5677 }
5678
5679
5680 /************************************************************************
5681  *                                                                      *
5682  *                      Type Casting Routines                           *
5683  *                                                                      *
5684  ************************************************************************/
5685
5686 /**
5687  * xmlXPathCastBooleanToString:
5688  * @val:  a boolean
5689  *
5690  * Converts a boolean to its string value.
5691  *
5692  * Returns a newly allocated string.
5693  */
5694 xmlChar *
5695 xmlXPathCastBooleanToString (int val) {
5696     xmlChar *ret;
5697     if (val)
5698         ret = xmlStrdup((const xmlChar *) "true");
5699     else
5700         ret = xmlStrdup((const xmlChar *) "false");
5701     return(ret);
5702 }
5703
5704 /**
5705  * xmlXPathCastNumberToString:
5706  * @val:  a number
5707  *
5708  * Converts a number to its string value.
5709  *
5710  * Returns a newly allocated string.
5711  */
5712 xmlChar *
5713 xmlXPathCastNumberToString (double val) {
5714     xmlChar *ret;
5715     switch (xmlXPathIsInf(val)) {
5716     case 1:
5717         ret = xmlStrdup((const xmlChar *) "Infinity");
5718         break;
5719     case -1:
5720         ret = xmlStrdup((const xmlChar *) "-Infinity");
5721         break;
5722     default:
5723         if (xmlXPathIsNaN(val)) {
5724             ret = xmlStrdup((const xmlChar *) "NaN");
5725         } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5726             ret = xmlStrdup((const xmlChar *) "0");
5727         } else {
5728             /* could be improved */
5729             char buf[100];
5730             xmlXPathFormatNumber(val, buf, 99);
5731             buf[99] = 0;
5732             ret = xmlStrdup((const xmlChar *) buf);
5733         }
5734     }
5735     return(ret);
5736 }
5737
5738 /**
5739  * xmlXPathCastNodeToString:
5740  * @node:  a node
5741  *
5742  * Converts a node to its string value.
5743  *
5744  * Returns a newly allocated string.
5745  */
5746 xmlChar *
5747 xmlXPathCastNodeToString (xmlNodePtr node) {
5748 xmlChar *ret;
5749     if ((ret = xmlNodeGetContent(node)) == NULL)
5750         ret = xmlStrdup((const xmlChar *) "");
5751     return(ret);
5752 }
5753
5754 /**
5755  * xmlXPathCastNodeSetToString:
5756  * @ns:  a node-set
5757  *
5758  * Converts a node-set to its string value.
5759  *
5760  * Returns a newly allocated string.
5761  */
5762 xmlChar *
5763 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5764     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5765         return(xmlStrdup((const xmlChar *) ""));
5766
5767     if (ns->nodeNr > 1)
5768         xmlXPathNodeSetSort(ns);
5769     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5770 }
5771
5772 /**
5773  * xmlXPathCastToString:
5774  * @val:  an XPath object
5775  *
5776  * Converts an existing object to its string() equivalent
5777  *
5778  * Returns the allocated string value of the object, NULL in case of error.
5779  *         It's up to the caller to free the string memory with xmlFree().
5780  */
5781 xmlChar *
5782 xmlXPathCastToString(xmlXPathObjectPtr val) {
5783     xmlChar *ret = NULL;
5784
5785     if (val == NULL)
5786         return(xmlStrdup((const xmlChar *) ""));
5787     switch (val->type) {
5788         case XPATH_UNDEFINED:
5789 #ifdef DEBUG_EXPR
5790             xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5791 #endif
5792             ret = xmlStrdup((const xmlChar *) "");
5793             break;
5794         case XPATH_NODESET:
5795         case XPATH_XSLT_TREE:
5796             ret = xmlXPathCastNodeSetToString(val->nodesetval);
5797             break;
5798         case XPATH_STRING:
5799             return(xmlStrdup(val->stringval));
5800         case XPATH_BOOLEAN:
5801             ret = xmlXPathCastBooleanToString(val->boolval);
5802             break;
5803         case XPATH_NUMBER: {
5804             ret = xmlXPathCastNumberToString(val->floatval);
5805             break;
5806         }
5807         case XPATH_USERS:
5808         case XPATH_POINT:
5809         case XPATH_RANGE:
5810         case XPATH_LOCATIONSET:
5811             TODO
5812             ret = xmlStrdup((const xmlChar *) "");
5813             break;
5814     }
5815     return(ret);
5816 }
5817
5818 /**
5819  * xmlXPathConvertString:
5820  * @val:  an XPath object
5821  *
5822  * Converts an existing object to its string() equivalent
5823  *
5824  * Returns the new object, the old one is freed (or the operation
5825  *         is done directly on @val)
5826  */
5827 xmlXPathObjectPtr
5828 xmlXPathConvertString(xmlXPathObjectPtr val) {
5829     xmlChar *res = NULL;
5830
5831     if (val == NULL)
5832         return(xmlXPathNewCString(""));
5833
5834     switch (val->type) {
5835     case XPATH_UNDEFINED:
5836 #ifdef DEBUG_EXPR
5837         xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5838 #endif
5839         break;
5840     case XPATH_NODESET:
5841     case XPATH_XSLT_TREE:
5842         res = xmlXPathCastNodeSetToString(val->nodesetval);
5843         break;
5844     case XPATH_STRING:
5845         return(val);
5846     case XPATH_BOOLEAN:
5847         res = xmlXPathCastBooleanToString(val->boolval);
5848         break;
5849     case XPATH_NUMBER:
5850         res = xmlXPathCastNumberToString(val->floatval);
5851         break;
5852     case XPATH_USERS:
5853     case XPATH_POINT:
5854     case XPATH_RANGE:
5855     case XPATH_LOCATIONSET:
5856         TODO;
5857         break;
5858     }
5859     xmlXPathFreeObject(val);
5860     if (res == NULL)
5861         return(xmlXPathNewCString(""));
5862     return(xmlXPathWrapString(res));
5863 }
5864
5865 /**
5866  * xmlXPathCastBooleanToNumber:
5867  * @val:  a boolean
5868  *
5869  * Converts a boolean to its number value
5870  *
5871  * Returns the number value
5872  */
5873 double
5874 xmlXPathCastBooleanToNumber(int val) {
5875     if (val)
5876         return(1.0);
5877     return(0.0);
5878 }
5879
5880 /**
5881  * xmlXPathCastStringToNumber:
5882  * @val:  a string
5883  *
5884  * Converts a string to its number value
5885  *
5886  * Returns the number value
5887  */
5888 double
5889 xmlXPathCastStringToNumber(const xmlChar * val) {
5890     return(xmlXPathStringEvalNumber(val));
5891 }
5892
5893 /**
5894  * xmlXPathCastNodeToNumber:
5895  * @node:  a node
5896  *
5897  * Converts a node to its number value
5898  *
5899  * Returns the number value
5900  */
5901 double
5902 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5903     xmlChar *strval;
5904     double ret;
5905
5906     if (node == NULL)
5907         return(xmlXPathNAN);
5908     strval = xmlXPathCastNodeToString(node);
5909     if (strval == NULL)
5910         return(xmlXPathNAN);
5911     ret = xmlXPathCastStringToNumber(strval);
5912     xmlFree(strval);
5913
5914     return(ret);
5915 }
5916
5917 /**
5918  * xmlXPathCastNodeSetToNumber:
5919  * @ns:  a node-set
5920  *
5921  * Converts a node-set to its number value
5922  *
5923  * Returns the number value
5924  */
5925 double
5926 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5927     xmlChar *str;
5928     double ret;
5929
5930     if (ns == NULL)
5931         return(xmlXPathNAN);
5932     str = xmlXPathCastNodeSetToString(ns);
5933     ret = xmlXPathCastStringToNumber(str);
5934     xmlFree(str);
5935     return(ret);
5936 }
5937
5938 /**
5939  * xmlXPathCastToNumber:
5940  * @val:  an XPath object
5941  *
5942  * Converts an XPath object to its number value
5943  *
5944  * Returns the number value
5945  */
5946 double
5947 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5948     double ret = 0.0;
5949
5950     if (val == NULL)
5951         return(xmlXPathNAN);
5952     switch (val->type) {
5953     case XPATH_UNDEFINED:
5954 #ifdef DEGUB_EXPR
5955         xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5956 #endif
5957         ret = xmlXPathNAN;
5958         break;
5959     case XPATH_NODESET:
5960     case XPATH_XSLT_TREE:
5961         ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5962         break;
5963     case XPATH_STRING:
5964         ret = xmlXPathCastStringToNumber(val->stringval);
5965         break;
5966     case XPATH_NUMBER:
5967         ret = val->floatval;
5968         break;
5969     case XPATH_BOOLEAN:
5970         ret = xmlXPathCastBooleanToNumber(val->boolval);
5971         break;
5972     case XPATH_USERS:
5973     case XPATH_POINT:
5974     case XPATH_RANGE:
5975     case XPATH_LOCATIONSET:
5976         TODO;
5977         ret = xmlXPathNAN;
5978         break;
5979     }
5980     return(ret);
5981 }
5982
5983 /**
5984  * xmlXPathConvertNumber:
5985  * @val:  an XPath object
5986  *
5987  * Converts an existing object to its number() equivalent
5988  *
5989  * Returns the new object, the old one is freed (or the operation
5990  *         is done directly on @val)
5991  */
5992 xmlXPathObjectPtr
5993 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5994     xmlXPathObjectPtr ret;
5995
5996     if (val == NULL)
5997         return(xmlXPathNewFloat(0.0));
5998     if (val->type == XPATH_NUMBER)
5999         return(val);
6000     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
6001     xmlXPathFreeObject(val);
6002     return(ret);
6003 }
6004
6005 /**
6006  * xmlXPathCastNumberToBoolean:
6007  * @val:  a number
6008  *
6009  * Converts a number to its boolean value
6010  *
6011  * Returns the boolean value
6012  */
6013 int
6014 xmlXPathCastNumberToBoolean (double val) {
6015      if (xmlXPathIsNaN(val) || (val == 0.0))
6016          return(0);
6017      return(1);
6018 }
6019
6020 /**
6021  * xmlXPathCastStringToBoolean:
6022  * @val:  a string
6023  *
6024  * Converts a string to its boolean value
6025  *
6026  * Returns the boolean value
6027  */
6028 int
6029 xmlXPathCastStringToBoolean (const xmlChar *val) {
6030     if ((val == NULL) || (xmlStrlen(val) == 0))
6031         return(0);
6032     return(1);
6033 }
6034
6035 /**
6036  * xmlXPathCastNodeSetToBoolean:
6037  * @ns:  a node-set
6038  *
6039  * Converts a node-set to its boolean value
6040  *
6041  * Returns the boolean value
6042  */
6043 int
6044 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6045     if ((ns == NULL) || (ns->nodeNr == 0))
6046         return(0);
6047     return(1);
6048 }
6049
6050 /**
6051  * xmlXPathCastToBoolean:
6052  * @val:  an XPath object
6053  *
6054  * Converts an XPath object to its boolean value
6055  *
6056  * Returns the boolean value
6057  */
6058 int
6059 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6060     int ret = 0;
6061
6062     if (val == NULL)
6063         return(0);
6064     switch (val->type) {
6065     case XPATH_UNDEFINED:
6066 #ifdef DEBUG_EXPR
6067         xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6068 #endif
6069         ret = 0;
6070         break;
6071     case XPATH_NODESET:
6072     case XPATH_XSLT_TREE:
6073         ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6074         break;
6075     case XPATH_STRING:
6076         ret = xmlXPathCastStringToBoolean(val->stringval);
6077         break;
6078     case XPATH_NUMBER:
6079         ret = xmlXPathCastNumberToBoolean(val->floatval);
6080         break;
6081     case XPATH_BOOLEAN:
6082         ret = val->boolval;
6083         break;
6084     case XPATH_USERS:
6085     case XPATH_POINT:
6086     case XPATH_RANGE:
6087     case XPATH_LOCATIONSET:
6088         TODO;
6089         ret = 0;
6090         break;
6091     }
6092     return(ret);
6093 }
6094
6095
6096 /**
6097  * xmlXPathConvertBoolean:
6098  * @val:  an XPath object
6099  *
6100  * Converts an existing object to its boolean() equivalent
6101  *
6102  * Returns the new object, the old one is freed (or the operation
6103  *         is done directly on @val)
6104  */
6105 xmlXPathObjectPtr
6106 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6107     xmlXPathObjectPtr ret;
6108
6109     if (val == NULL)
6110         return(xmlXPathNewBoolean(0));
6111     if (val->type == XPATH_BOOLEAN)
6112         return(val);
6113     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6114     xmlXPathFreeObject(val);
6115     return(ret);
6116 }
6117
6118 /************************************************************************
6119  *                                                                      *
6120  *              Routines to handle XPath contexts                       *
6121  *                                                                      *
6122  ************************************************************************/
6123
6124 /**
6125  * xmlXPathNewContext:
6126  * @doc:  the XML document
6127  *
6128  * Create a new xmlXPathContext
6129  *
6130  * Returns the xmlXPathContext just allocated. The caller will need to free it.
6131  */
6132 xmlXPathContextPtr
6133 xmlXPathNewContext(xmlDocPtr doc) {
6134     xmlXPathContextPtr ret;
6135
6136     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6137     if (ret == NULL) {
6138         xmlXPathErrMemory(NULL, "creating context\n");
6139         return(NULL);
6140     }
6141     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6142     ret->doc = doc;
6143     ret->node = NULL;
6144
6145     ret->varHash = NULL;
6146
6147     ret->nb_types = 0;
6148     ret->max_types = 0;
6149     ret->types = NULL;
6150
6151     ret->funcHash = xmlHashCreate(0);
6152
6153     ret->nb_axis = 0;
6154     ret->max_axis = 0;
6155     ret->axis = NULL;
6156
6157     ret->nsHash = NULL;
6158     ret->user = NULL;
6159
6160     ret->contextSize = -1;
6161     ret->proximityPosition = -1;
6162
6163 #ifdef XP_DEFAULT_CACHE_ON
6164     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6165         xmlXPathFreeContext(ret);
6166         return(NULL);
6167     }
6168 #endif
6169
6170     xmlXPathRegisterAllFunctions(ret);
6171
6172     return(ret);
6173 }
6174
6175 /**
6176  * xmlXPathFreeContext:
6177  * @ctxt:  the context to free
6178  *
6179  * Free up an xmlXPathContext
6180  */
6181 void
6182 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6183     if (ctxt == NULL) return;
6184
6185     if (ctxt->cache != NULL)
6186         xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6187     xmlXPathRegisteredNsCleanup(ctxt);
6188     xmlXPathRegisteredFuncsCleanup(ctxt);
6189     xmlXPathRegisteredVariablesCleanup(ctxt);
6190     xmlResetError(&ctxt->lastError);
6191     xmlFree(ctxt);
6192 }
6193
6194 /************************************************************************
6195  *                                                                      *
6196  *              Routines to handle XPath parser contexts                *
6197  *                                                                      *
6198  ************************************************************************/
6199
6200 #define CHECK_CTXT(ctxt)                                                \
6201     if (ctxt == NULL) {                                         \
6202         __xmlRaiseError(NULL, NULL, NULL,                               \
6203                 NULL, NULL, XML_FROM_XPATH,                             \
6204                 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6205                 __FILE__, __LINE__,                                     \
6206                 NULL, NULL, NULL, 0, 0,                                 \
6207                 "NULL context pointer\n");                              \
6208         return(NULL);                                                   \
6209     }                                                                   \
6210
6211 #define CHECK_CTXT_NEG(ctxt)                                            \
6212     if (ctxt == NULL) {                                         \
6213         __xmlRaiseError(NULL, NULL, NULL,                               \
6214                 NULL, NULL, XML_FROM_XPATH,                             \
6215                 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6216                 __FILE__, __LINE__,                                     \
6217                 NULL, NULL, NULL, 0, 0,                                 \
6218                 "NULL context pointer\n");                              \
6219         return(-1);                                                     \
6220     }                                                                   \
6221
6222
6223 #define CHECK_CONTEXT(ctxt)                                             \
6224     if ((ctxt == NULL) || (ctxt->doc == NULL) ||                        \
6225         (ctxt->doc->children == NULL)) {                                \
6226         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);    \
6227         return(NULL);                                                   \
6228     }
6229
6230
6231 /**
6232  * xmlXPathNewParserContext:
6233  * @str:  the XPath expression
6234  * @ctxt:  the XPath context
6235  *
6236  * Create a new xmlXPathParserContext
6237  *
6238  * Returns the xmlXPathParserContext just allocated.
6239  */
6240 xmlXPathParserContextPtr
6241 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6242     xmlXPathParserContextPtr ret;
6243
6244     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6245     if (ret == NULL) {
6246         xmlXPathErrMemory(ctxt, "creating parser context\n");
6247         return(NULL);
6248     }
6249     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6250     ret->cur = ret->base = str;
6251     ret->context = ctxt;
6252
6253     ret->comp = xmlXPathNewCompExpr();
6254     if (ret->comp == NULL) {
6255         xmlFree(ret->valueTab);
6256         xmlFree(ret);
6257         return(NULL);
6258     }
6259     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6260         ret->comp->dict = ctxt->dict;
6261         xmlDictReference(ret->comp->dict);
6262     }
6263
6264     return(ret);
6265 }
6266
6267 /**
6268  * xmlXPathCompParserContext:
6269  * @comp:  the XPath compiled expression
6270  * @ctxt:  the XPath context
6271  *
6272  * Create a new xmlXPathParserContext when processing a compiled expression
6273  *
6274  * Returns the xmlXPathParserContext just allocated.
6275  */
6276 static xmlXPathParserContextPtr
6277 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6278     xmlXPathParserContextPtr ret;
6279
6280     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6281     if (ret == NULL) {
6282         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6283         return(NULL);
6284     }
6285     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6286
6287     /* Allocate the value stack */
6288     ret->valueTab = (xmlXPathObjectPtr *)
6289                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6290     if (ret->valueTab == NULL) {
6291         xmlFree(ret);
6292         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6293         return(NULL);
6294     }
6295     ret->valueNr = 0;
6296     ret->valueMax = 10;
6297     ret->value = NULL;
6298     ret->valueFrame = 0;
6299
6300     ret->context = ctxt;
6301     ret->comp = comp;
6302
6303     return(ret);
6304 }
6305
6306 /**
6307  * xmlXPathFreeParserContext:
6308  * @ctxt:  the context to free
6309  *
6310  * Free up an xmlXPathParserContext
6311  */
6312 void
6313 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6314     int i;
6315
6316     if (ctxt->valueTab != NULL) {
6317         for (i = 0; i < ctxt->valueNr; i++) {
6318             if (ctxt->context)
6319                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6320             else
6321                 xmlXPathFreeObject(ctxt->valueTab[i]);
6322         }
6323         xmlFree(ctxt->valueTab);
6324     }
6325     if (ctxt->comp != NULL) {
6326 #ifdef XPATH_STREAMING
6327         if (ctxt->comp->stream != NULL) {
6328             xmlFreePatternList(ctxt->comp->stream);
6329             ctxt->comp->stream = NULL;
6330         }
6331 #endif
6332         xmlXPathFreeCompExpr(ctxt->comp);
6333     }
6334     xmlFree(ctxt);
6335 }
6336
6337 /************************************************************************
6338  *                                                                      *
6339  *              The implicit core function library                      *
6340  *                                                                      *
6341  ************************************************************************/
6342
6343 /**
6344  * xmlXPathNodeValHash:
6345  * @node:  a node pointer
6346  *
6347  * Function computing the beginning of the string value of the node,
6348  * used to speed up comparisons
6349  *
6350  * Returns an int usable as a hash
6351  */
6352 static unsigned int
6353 xmlXPathNodeValHash(xmlNodePtr node) {
6354     int len = 2;
6355     const xmlChar * string = NULL;
6356     xmlNodePtr tmp = NULL;
6357     unsigned int ret = 0;
6358
6359     if (node == NULL)
6360         return(0);
6361
6362     if (node->type == XML_DOCUMENT_NODE) {
6363         tmp = xmlDocGetRootElement((xmlDocPtr) node);
6364         if (tmp == NULL)
6365             node = node->children;
6366         else
6367             node = tmp;
6368
6369         if (node == NULL)
6370             return(0);
6371     }
6372
6373     switch (node->type) {
6374         case XML_COMMENT_NODE:
6375         case XML_PI_NODE:
6376         case XML_CDATA_SECTION_NODE:
6377         case XML_TEXT_NODE:
6378             string = node->content;
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_NAMESPACE_DECL:
6386             string = ((xmlNsPtr)node)->href;
6387             if (string == NULL)
6388                 return(0);
6389             if (string[0] == 0)
6390                 return(0);
6391             return(((unsigned int) string[0]) +
6392                    (((unsigned int) string[1]) << 8));
6393         case XML_ATTRIBUTE_NODE:
6394             tmp = ((xmlAttrPtr) node)->children;
6395             break;
6396         case XML_ELEMENT_NODE:
6397             tmp = node->children;
6398             break;
6399         default:
6400             return(0);
6401     }
6402     while (tmp != NULL) {
6403         switch (tmp->type) {
6404             case XML_CDATA_SECTION_NODE:
6405             case XML_TEXT_NODE:
6406                 string = tmp->content;
6407                 break;
6408             default:
6409                 string = NULL;
6410                 break;
6411         }
6412         if ((string != NULL) && (string[0] != 0)) {
6413             if (len == 1) {
6414                 return(ret + (((unsigned int) string[0]) << 8));
6415             }
6416             if (string[1] == 0) {
6417                 len = 1;
6418                 ret = (unsigned int) string[0];
6419             } else {
6420                 return(((unsigned int) string[0]) +
6421                        (((unsigned int) string[1]) << 8));
6422             }
6423         }
6424         /*
6425          * Skip to next node
6426          */
6427         if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6428             if (tmp->children->type != XML_ENTITY_DECL) {
6429                 tmp = tmp->children;
6430                 continue;
6431             }
6432         }
6433         if (tmp == node)
6434             break;
6435
6436         if (tmp->next != NULL) {
6437             tmp = tmp->next;
6438             continue;
6439         }
6440
6441         do {
6442             tmp = tmp->parent;
6443             if (tmp == NULL)
6444                 break;
6445             if (tmp == node) {
6446                 tmp = NULL;
6447                 break;
6448             }
6449             if (tmp->next != NULL) {
6450                 tmp = tmp->next;
6451                 break;
6452             }
6453         } while (tmp != NULL);
6454     }
6455     return(ret);
6456 }
6457
6458 /**
6459  * xmlXPathStringHash:
6460  * @string:  a string
6461  *
6462  * Function computing the beginning of the string value of the node,
6463  * used to speed up comparisons
6464  *
6465  * Returns an int usable as a hash
6466  */
6467 static unsigned int
6468 xmlXPathStringHash(const xmlChar * string) {
6469     if (string == NULL)
6470         return((unsigned int) 0);
6471     if (string[0] == 0)
6472         return(0);
6473     return(((unsigned int) string[0]) +
6474            (((unsigned int) string[1]) << 8));
6475 }
6476
6477 /**
6478  * xmlXPathCompareNodeSetFloat:
6479  * @ctxt:  the XPath Parser context
6480  * @inf:  less than (1) or greater than (0)
6481  * @strict:  is the comparison strict
6482  * @arg:  the node set
6483  * @f:  the value
6484  *
6485  * Implement the compare operation between a nodeset and a number
6486  *     @ns < @val    (1, 1, ...
6487  *     @ns <= @val   (1, 0, ...
6488  *     @ns > @val    (0, 1, ...
6489  *     @ns >= @val   (0, 0, ...
6490  *
6491  * If one object to be compared is a node-set and the other is a number,
6492  * then the comparison will be true if and only if there is a node in the
6493  * node-set such that the result of performing the comparison on the number
6494  * to be compared and on the result of converting the string-value of that
6495  * node to a number using the number function is true.
6496  *
6497  * Returns 0 or 1 depending on the results of the test.
6498  */
6499 static int
6500 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6501                             xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6502     int i, ret = 0;
6503     xmlNodeSetPtr ns;
6504     xmlChar *str2;
6505
6506     if ((f == NULL) || (arg == NULL) ||
6507         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6508         xmlXPathReleaseObject(ctxt->context, arg);
6509         xmlXPathReleaseObject(ctxt->context, f);
6510         return(0);
6511     }
6512     ns = arg->nodesetval;
6513     if (ns != NULL) {
6514         for (i = 0;i < ns->nodeNr;i++) {
6515              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6516              if (str2 != NULL) {
6517                  valuePush(ctxt,
6518                            xmlXPathCacheNewString(ctxt->context, str2));
6519                  xmlFree(str2);
6520                  xmlXPathNumberFunction(ctxt, 1);
6521                  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6522                  ret = xmlXPathCompareValues(ctxt, inf, strict);
6523                  if (ret)
6524                      break;
6525              }
6526         }
6527     }
6528     xmlXPathReleaseObject(ctxt->context, arg);
6529     xmlXPathReleaseObject(ctxt->context, f);
6530     return(ret);
6531 }
6532
6533 /**
6534  * xmlXPathCompareNodeSetString:
6535  * @ctxt:  the XPath Parser context
6536  * @inf:  less than (1) or greater than (0)
6537  * @strict:  is the comparison strict
6538  * @arg:  the node set
6539  * @s:  the value
6540  *
6541  * Implement the compare operation between a nodeset and a string
6542  *     @ns < @val    (1, 1, ...
6543  *     @ns <= @val   (1, 0, ...
6544  *     @ns > @val    (0, 1, ...
6545  *     @ns >= @val   (0, 0, ...
6546  *
6547  * If one object to be compared is a node-set and the other is a string,
6548  * then the comparison will be true if and only if there is a node in
6549  * the node-set such that the result of performing the comparison on the
6550  * string-value of the node and the other string is true.
6551  *
6552  * Returns 0 or 1 depending on the results of the test.
6553  */
6554 static int
6555 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6556                             xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6557     int i, ret = 0;
6558     xmlNodeSetPtr ns;
6559     xmlChar *str2;
6560
6561     if ((s == NULL) || (arg == NULL) ||
6562         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6563         xmlXPathReleaseObject(ctxt->context, arg);
6564         xmlXPathReleaseObject(ctxt->context, s);
6565         return(0);
6566     }
6567     ns = arg->nodesetval;
6568     if (ns != NULL) {
6569         for (i = 0;i < ns->nodeNr;i++) {
6570              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6571              if (str2 != NULL) {
6572                  valuePush(ctxt,
6573                            xmlXPathCacheNewString(ctxt->context, str2));
6574                  xmlFree(str2);
6575                  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6576                  ret = xmlXPathCompareValues(ctxt, inf, strict);
6577                  if (ret)
6578                      break;
6579              }
6580         }
6581     }
6582     xmlXPathReleaseObject(ctxt->context, arg);
6583     xmlXPathReleaseObject(ctxt->context, s);
6584     return(ret);
6585 }
6586
6587 /**
6588  * xmlXPathCompareNodeSets:
6589  * @inf:  less than (1) or greater than (0)
6590  * @strict:  is the comparison strict
6591  * @arg1:  the first node set object
6592  * @arg2:  the second node set object
6593  *
6594  * Implement the compare operation on nodesets:
6595  *
6596  * If both objects to be compared are node-sets, then the comparison
6597  * will be true if and only if there is a node in the first node-set
6598  * and a node in the second node-set such that the result of performing
6599  * the comparison on the string-values of the two nodes is true.
6600  * ....
6601  * When neither object to be compared is a node-set and the operator
6602  * is <=, <, >= or >, then the objects are compared by converting both
6603  * objects to numbers and comparing the numbers according to IEEE 754.
6604  * ....
6605  * The number function converts its argument to a number as follows:
6606  *  - a string that consists of optional whitespace followed by an
6607  *    optional minus sign followed by a Number followed by whitespace
6608  *    is converted to the IEEE 754 number that is nearest (according
6609  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6610  *    represented by the string; any other string is converted to NaN
6611  *
6612  * Conclusion all nodes need to be converted first to their string value
6613  * and then the comparison must be done when possible
6614  */
6615 static int
6616 xmlXPathCompareNodeSets(int inf, int strict,
6617                         xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6618     int i, j, init = 0;
6619     double val1;
6620     double *values2;
6621     int ret = 0;
6622     xmlNodeSetPtr ns1;
6623     xmlNodeSetPtr ns2;
6624
6625     if ((arg1 == NULL) ||
6626         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6627         xmlXPathFreeObject(arg2);
6628         return(0);
6629     }
6630     if ((arg2 == NULL) ||
6631         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6632         xmlXPathFreeObject(arg1);
6633         xmlXPathFreeObject(arg2);
6634         return(0);
6635     }
6636
6637     ns1 = arg1->nodesetval;
6638     ns2 = arg2->nodesetval;
6639
6640     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6641         xmlXPathFreeObject(arg1);
6642         xmlXPathFreeObject(arg2);
6643         return(0);
6644     }
6645     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6646         xmlXPathFreeObject(arg1);
6647         xmlXPathFreeObject(arg2);
6648         return(0);
6649     }
6650
6651     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6652     if (values2 == NULL) {
6653         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6654         xmlXPathFreeObject(arg1);
6655         xmlXPathFreeObject(arg2);
6656         return(0);
6657     }
6658     for (i = 0;i < ns1->nodeNr;i++) {
6659         val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6660         if (xmlXPathIsNaN(val1))
6661             continue;
6662         for (j = 0;j < ns2->nodeNr;j++) {
6663             if (init == 0) {
6664                 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6665             }
6666             if (xmlXPathIsNaN(values2[j]))
6667                 continue;
6668             if (inf && strict)
6669                 ret = (val1 < values2[j]);
6670             else if (inf && !strict)
6671                 ret = (val1 <= values2[j]);
6672             else if (!inf && strict)
6673                 ret = (val1 > values2[j]);
6674             else if (!inf && !strict)
6675                 ret = (val1 >= values2[j]);
6676             if (ret)
6677                 break;
6678         }
6679         if (ret)
6680             break;
6681         init = 1;
6682     }
6683     xmlFree(values2);
6684     xmlXPathFreeObject(arg1);
6685     xmlXPathFreeObject(arg2);
6686     return(ret);
6687 }
6688
6689 /**
6690  * xmlXPathCompareNodeSetValue:
6691  * @ctxt:  the XPath Parser context
6692  * @inf:  less than (1) or greater than (0)
6693  * @strict:  is the comparison strict
6694  * @arg:  the node set
6695  * @val:  the value
6696  *
6697  * Implement the compare operation between a nodeset and a value
6698  *     @ns < @val    (1, 1, ...
6699  *     @ns <= @val   (1, 0, ...
6700  *     @ns > @val    (0, 1, ...
6701  *     @ns >= @val   (0, 0, ...
6702  *
6703  * If one object to be compared is a node-set and the other is a boolean,
6704  * then the comparison will be true if and only if the result of performing
6705  * the comparison on the boolean and on the result of converting
6706  * the node-set to a boolean using the boolean function is true.
6707  *
6708  * Returns 0 or 1 depending on the results of the test.
6709  */
6710 static int
6711 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6712                             xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6713     if ((val == NULL) || (arg == NULL) ||
6714         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6715         return(0);
6716
6717     switch(val->type) {
6718         case XPATH_NUMBER:
6719             return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6720         case XPATH_NODESET:
6721         case XPATH_XSLT_TREE:
6722             return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6723         case XPATH_STRING:
6724             return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6725         case XPATH_BOOLEAN:
6726             valuePush(ctxt, arg);
6727             xmlXPathBooleanFunction(ctxt, 1);
6728             valuePush(ctxt, val);
6729             return(xmlXPathCompareValues(ctxt, inf, strict));
6730         default:
6731             xmlGenericError(xmlGenericErrorContext,
6732                     "xmlXPathCompareNodeSetValue: Can't compare node set "
6733                     "and object of type %d\n",
6734                     val->type);
6735             xmlXPathReleaseObject(ctxt->context, arg);
6736             xmlXPathReleaseObject(ctxt->context, val);
6737             XP_ERROR0(XPATH_INVALID_TYPE);
6738     }
6739     return(0);
6740 }
6741
6742 /**
6743  * xmlXPathEqualNodeSetString:
6744  * @arg:  the nodeset object argument
6745  * @str:  the string to compare to.
6746  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6747  *
6748  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6749  * If one object to be compared is a node-set and the other is a string,
6750  * then the comparison will be true if and only if there is a node in
6751  * the node-set such that the result of performing the comparison on the
6752  * string-value of the node and the other string is true.
6753  *
6754  * Returns 0 or 1 depending on the results of the test.
6755  */
6756 static int
6757 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6758 {
6759     int i;
6760     xmlNodeSetPtr ns;
6761     xmlChar *str2;
6762     unsigned int hash;
6763
6764     if ((str == NULL) || (arg == NULL) ||
6765         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6766         return (0);
6767     ns = arg->nodesetval;
6768     /*
6769      * A NULL nodeset compared with a string is always false
6770      * (since there is no node equal, and no node not equal)
6771      */
6772     if ((ns == NULL) || (ns->nodeNr <= 0) )
6773         return (0);
6774     hash = xmlXPathStringHash(str);
6775     for (i = 0; i < ns->nodeNr; i++) {
6776         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6777             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6778             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6779                 xmlFree(str2);
6780                 if (neq)
6781                     continue;
6782                 return (1);
6783             } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6784                 if (neq)
6785                     continue;
6786                 return (1);
6787             } else if (neq) {
6788                 if (str2 != NULL)
6789                     xmlFree(str2);
6790                 return (1);
6791             }
6792             if (str2 != NULL)
6793                 xmlFree(str2);
6794         } else if (neq)
6795             return (1);
6796     }
6797     return (0);
6798 }
6799
6800 /**
6801  * xmlXPathEqualNodeSetFloat:
6802  * @arg:  the nodeset object argument
6803  * @f:  the float to compare to
6804  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6805  *
6806  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6807  * If one object to be compared is a node-set and the other is a number,
6808  * then the comparison will be true if and only if there is a node in
6809  * the node-set such that the result of performing the comparison on the
6810  * number to be compared and on the result of converting the string-value
6811  * of that node to a number using the number function is true.
6812  *
6813  * Returns 0 or 1 depending on the results of the test.
6814  */
6815 static int
6816 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6817     xmlXPathObjectPtr arg, double f, int neq) {
6818   int i, ret=0;
6819   xmlNodeSetPtr ns;
6820   xmlChar *str2;
6821   xmlXPathObjectPtr val;
6822   double v;
6823
6824     if ((arg == NULL) ||
6825         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6826         return(0);
6827
6828     ns = arg->nodesetval;
6829     if (ns != NULL) {
6830         for (i=0;i<ns->nodeNr;i++) {
6831             str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6832             if (str2 != NULL) {
6833                 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6834                 xmlFree(str2);
6835                 xmlXPathNumberFunction(ctxt, 1);
6836                 val = valuePop(ctxt);
6837                 v = val->floatval;
6838                 xmlXPathReleaseObject(ctxt->context, val);
6839                 if (!xmlXPathIsNaN(v)) {
6840                     if ((!neq) && (v==f)) {
6841                         ret = 1;
6842                         break;
6843                     } else if ((neq) && (v!=f)) {
6844                         ret = 1;
6845                         break;
6846                     }
6847                 } else {        /* NaN is unequal to any value */
6848                     if (neq)
6849                         ret = 1;
6850                 }
6851             }
6852         }
6853     }
6854
6855     return(ret);
6856 }
6857
6858
6859 /**
6860  * xmlXPathEqualNodeSets:
6861  * @arg1:  first nodeset object argument
6862  * @arg2:  second nodeset object argument
6863  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6864  *
6865  * Implement the equal / not equal operation on XPath nodesets:
6866  * @arg1 == @arg2  or  @arg1 != @arg2
6867  * If both objects to be compared are node-sets, then the comparison
6868  * will be true if and only if there is a node in the first node-set and
6869  * a node in the second node-set such that the result of performing the
6870  * comparison on the string-values of the two nodes is true.
6871  *
6872  * (needless to say, this is a costly operation)
6873  *
6874  * Returns 0 or 1 depending on the results of the test.
6875  */
6876 static int
6877 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6878     int i, j;
6879     unsigned int *hashs1;
6880     unsigned int *hashs2;
6881     xmlChar **values1;
6882     xmlChar **values2;
6883     int ret = 0;
6884     xmlNodeSetPtr ns1;
6885     xmlNodeSetPtr ns2;
6886
6887     if ((arg1 == NULL) ||
6888         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6889         return(0);
6890     if ((arg2 == NULL) ||
6891         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6892         return(0);
6893
6894     ns1 = arg1->nodesetval;
6895     ns2 = arg2->nodesetval;
6896
6897     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6898         return(0);
6899     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6900         return(0);
6901
6902     /*
6903      * for equal, check if there is a node pertaining to both sets
6904      */
6905     if (neq == 0)
6906         for (i = 0;i < ns1->nodeNr;i++)
6907             for (j = 0;j < ns2->nodeNr;j++)
6908                 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6909                     return(1);
6910
6911     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6912     if (values1 == NULL) {
6913         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6914         return(0);
6915     }
6916     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6917     if (hashs1 == NULL) {
6918         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6919         xmlFree(values1);
6920         return(0);
6921     }
6922     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6923     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6924     if (values2 == NULL) {
6925         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6926         xmlFree(hashs1);
6927         xmlFree(values1);
6928         return(0);
6929     }
6930     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6931     if (hashs2 == NULL) {
6932         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6933         xmlFree(hashs1);
6934         xmlFree(values1);
6935         xmlFree(values2);
6936         return(0);
6937     }
6938     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6939     for (i = 0;i < ns1->nodeNr;i++) {
6940         hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6941         for (j = 0;j < ns2->nodeNr;j++) {
6942             if (i == 0)
6943                 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6944             if (hashs1[i] != hashs2[j]) {
6945                 if (neq) {
6946                     ret = 1;
6947                     break;
6948                 }
6949             }
6950             else {
6951                 if (values1[i] == NULL)
6952                     values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6953                 if (values2[j] == NULL)
6954                     values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6955                 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6956                 if (ret)
6957                     break;
6958             }
6959         }
6960         if (ret)
6961             break;
6962     }
6963     for (i = 0;i < ns1->nodeNr;i++)
6964         if (values1[i] != NULL)
6965             xmlFree(values1[i]);
6966     for (j = 0;j < ns2->nodeNr;j++)
6967         if (values2[j] != NULL)
6968             xmlFree(values2[j]);
6969     xmlFree(values1);
6970     xmlFree(values2);
6971     xmlFree(hashs1);
6972     xmlFree(hashs2);
6973     return(ret);
6974 }
6975
6976 static int
6977 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6978   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6979     int ret = 0;
6980     /*
6981      *At this point we are assured neither arg1 nor arg2
6982      *is a nodeset, so we can just pick the appropriate routine.
6983      */
6984     switch (arg1->type) {
6985         case XPATH_UNDEFINED:
6986 #ifdef DEBUG_EXPR
6987             xmlGenericError(xmlGenericErrorContext,
6988                     "Equal: undefined\n");
6989 #endif
6990             break;
6991         case XPATH_BOOLEAN:
6992             switch (arg2->type) {
6993                 case XPATH_UNDEFINED:
6994 #ifdef DEBUG_EXPR
6995                     xmlGenericError(xmlGenericErrorContext,
6996                             "Equal: undefined\n");
6997 #endif
6998                     break;
6999                 case XPATH_BOOLEAN:
7000 #ifdef DEBUG_EXPR
7001                     xmlGenericError(xmlGenericErrorContext,
7002                             "Equal: %d boolean %d \n",
7003                             arg1->boolval, arg2->boolval);
7004 #endif
7005                     ret = (arg1->boolval == arg2->boolval);
7006                     break;
7007                 case XPATH_NUMBER:
7008                     ret = (arg1->boolval ==
7009                            xmlXPathCastNumberToBoolean(arg2->floatval));
7010                     break;
7011                 case XPATH_STRING:
7012                     if ((arg2->stringval == NULL) ||
7013                         (arg2->stringval[0] == 0)) ret = 0;
7014                     else
7015                         ret = 1;
7016                     ret = (arg1->boolval == ret);
7017                     break;
7018                 case XPATH_USERS:
7019                 case XPATH_POINT:
7020                 case XPATH_RANGE:
7021                 case XPATH_LOCATIONSET:
7022                     TODO
7023                     break;
7024                 case XPATH_NODESET:
7025                 case XPATH_XSLT_TREE:
7026                     break;
7027             }
7028             break;
7029         case XPATH_NUMBER:
7030             switch (arg2->type) {
7031                 case XPATH_UNDEFINED:
7032 #ifdef DEBUG_EXPR
7033                     xmlGenericError(xmlGenericErrorContext,
7034                             "Equal: undefined\n");
7035 #endif
7036                     break;
7037                 case XPATH_BOOLEAN:
7038                     ret = (arg2->boolval==
7039                            xmlXPathCastNumberToBoolean(arg1->floatval));
7040                     break;
7041                 case XPATH_STRING:
7042                     valuePush(ctxt, arg2);
7043                     xmlXPathNumberFunction(ctxt, 1);
7044                     arg2 = valuePop(ctxt);
7045                     /* Falls through. */
7046                 case XPATH_NUMBER:
7047                     /* Hand check NaN and Infinity equalities */
7048                     if (xmlXPathIsNaN(arg1->floatval) ||
7049                             xmlXPathIsNaN(arg2->floatval)) {
7050                         ret = 0;
7051                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7052                         if (xmlXPathIsInf(arg2->floatval) == 1)
7053                             ret = 1;
7054                         else
7055                             ret = 0;
7056                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7057                         if (xmlXPathIsInf(arg2->floatval) == -1)
7058                             ret = 1;
7059                         else
7060                             ret = 0;
7061                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7062                         if (xmlXPathIsInf(arg1->floatval) == 1)
7063                             ret = 1;
7064                         else
7065                             ret = 0;
7066                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7067                         if (xmlXPathIsInf(arg1->floatval) == -1)
7068                             ret = 1;
7069                         else
7070                             ret = 0;
7071                     } else {
7072                         ret = (arg1->floatval == arg2->floatval);
7073                     }
7074                     break;
7075                 case XPATH_USERS:
7076                 case XPATH_POINT:
7077                 case XPATH_RANGE:
7078                 case XPATH_LOCATIONSET:
7079                     TODO
7080                     break;
7081                 case XPATH_NODESET:
7082                 case XPATH_XSLT_TREE:
7083                     break;
7084             }
7085             break;
7086         case XPATH_STRING:
7087             switch (arg2->type) {
7088                 case XPATH_UNDEFINED:
7089 #ifdef DEBUG_EXPR
7090                     xmlGenericError(xmlGenericErrorContext,
7091                             "Equal: undefined\n");
7092 #endif
7093                     break;
7094                 case XPATH_BOOLEAN:
7095                     if ((arg1->stringval == NULL) ||
7096                         (arg1->stringval[0] == 0)) ret = 0;
7097                     else
7098                         ret = 1;
7099                     ret = (arg2->boolval == ret);
7100                     break;
7101                 case XPATH_STRING:
7102                     ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7103                     break;
7104                 case XPATH_NUMBER:
7105                     valuePush(ctxt, arg1);
7106                     xmlXPathNumberFunction(ctxt, 1);
7107                     arg1 = valuePop(ctxt);
7108                     /* Hand check NaN and Infinity equalities */
7109                     if (xmlXPathIsNaN(arg1->floatval) ||
7110                             xmlXPathIsNaN(arg2->floatval)) {
7111                         ret = 0;
7112                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7113                         if (xmlXPathIsInf(arg2->floatval) == 1)
7114                             ret = 1;
7115                         else
7116                             ret = 0;
7117                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7118                         if (xmlXPathIsInf(arg2->floatval) == -1)
7119                             ret = 1;
7120                         else
7121                             ret = 0;
7122                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7123                         if (xmlXPathIsInf(arg1->floatval) == 1)
7124                             ret = 1;
7125                         else
7126                             ret = 0;
7127                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7128                         if (xmlXPathIsInf(arg1->floatval) == -1)
7129                             ret = 1;
7130                         else
7131                             ret = 0;
7132                     } else {
7133                         ret = (arg1->floatval == arg2->floatval);
7134                     }
7135                     break;
7136                 case XPATH_USERS:
7137                 case XPATH_POINT:
7138                 case XPATH_RANGE:
7139                 case XPATH_LOCATIONSET:
7140                     TODO
7141                     break;
7142                 case XPATH_NODESET:
7143                 case XPATH_XSLT_TREE:
7144                     break;
7145             }
7146             break;
7147         case XPATH_USERS:
7148         case XPATH_POINT:
7149         case XPATH_RANGE:
7150         case XPATH_LOCATIONSET:
7151             TODO
7152             break;
7153         case XPATH_NODESET:
7154         case XPATH_XSLT_TREE:
7155             break;
7156     }
7157     xmlXPathReleaseObject(ctxt->context, arg1);
7158     xmlXPathReleaseObject(ctxt->context, arg2);
7159     return(ret);
7160 }
7161
7162 /**
7163  * xmlXPathEqualValues:
7164  * @ctxt:  the XPath Parser context
7165  *
7166  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7167  *
7168  * Returns 0 or 1 depending on the results of the test.
7169  */
7170 int
7171 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7172     xmlXPathObjectPtr arg1, arg2, argtmp;
7173     int ret = 0;
7174
7175     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7176     arg2 = valuePop(ctxt);
7177     arg1 = valuePop(ctxt);
7178     if ((arg1 == NULL) || (arg2 == NULL)) {
7179         if (arg1 != NULL)
7180             xmlXPathReleaseObject(ctxt->context, arg1);
7181         else
7182             xmlXPathReleaseObject(ctxt->context, arg2);
7183         XP_ERROR0(XPATH_INVALID_OPERAND);
7184     }
7185
7186     if (arg1 == arg2) {
7187 #ifdef DEBUG_EXPR
7188         xmlGenericError(xmlGenericErrorContext,
7189                 "Equal: by pointer\n");
7190 #endif
7191         xmlXPathFreeObject(arg1);
7192         return(1);
7193     }
7194
7195     /*
7196      *If either argument is a nodeset, it's a 'special case'
7197      */
7198     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7199       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7200         /*
7201          *Hack it to assure arg1 is the nodeset
7202          */
7203         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7204                 argtmp = arg2;
7205                 arg2 = arg1;
7206                 arg1 = argtmp;
7207         }
7208         switch (arg2->type) {
7209             case XPATH_UNDEFINED:
7210 #ifdef DEBUG_EXPR
7211                 xmlGenericError(xmlGenericErrorContext,
7212                         "Equal: undefined\n");
7213 #endif
7214                 break;
7215             case XPATH_NODESET:
7216             case XPATH_XSLT_TREE:
7217                 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7218                 break;
7219             case XPATH_BOOLEAN:
7220                 if ((arg1->nodesetval == NULL) ||
7221                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
7222                 else
7223                     ret = 1;
7224                 ret = (ret == arg2->boolval);
7225                 break;
7226             case XPATH_NUMBER:
7227                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7228                 break;
7229             case XPATH_STRING:
7230                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7231                 break;
7232             case XPATH_USERS:
7233             case XPATH_POINT:
7234             case XPATH_RANGE:
7235             case XPATH_LOCATIONSET:
7236                 TODO
7237                 break;
7238         }
7239         xmlXPathReleaseObject(ctxt->context, arg1);
7240         xmlXPathReleaseObject(ctxt->context, arg2);
7241         return(ret);
7242     }
7243
7244     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7245 }
7246
7247 /**
7248  * xmlXPathNotEqualValues:
7249  * @ctxt:  the XPath Parser context
7250  *
7251  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7252  *
7253  * Returns 0 or 1 depending on the results of the test.
7254  */
7255 int
7256 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7257     xmlXPathObjectPtr arg1, arg2, argtmp;
7258     int ret = 0;
7259
7260     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7261     arg2 = valuePop(ctxt);
7262     arg1 = valuePop(ctxt);
7263     if ((arg1 == NULL) || (arg2 == NULL)) {
7264         if (arg1 != NULL)
7265             xmlXPathReleaseObject(ctxt->context, arg1);
7266         else
7267             xmlXPathReleaseObject(ctxt->context, arg2);
7268         XP_ERROR0(XPATH_INVALID_OPERAND);
7269     }
7270
7271     if (arg1 == arg2) {
7272 #ifdef DEBUG_EXPR
7273         xmlGenericError(xmlGenericErrorContext,
7274                 "NotEqual: by pointer\n");
7275 #endif
7276         xmlXPathReleaseObject(ctxt->context, arg1);
7277         return(0);
7278     }
7279
7280     /*
7281      *If either argument is a nodeset, it's a 'special case'
7282      */
7283     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7284       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7285         /*
7286          *Hack it to assure arg1 is the nodeset
7287          */
7288         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7289                 argtmp = arg2;
7290                 arg2 = arg1;
7291                 arg1 = argtmp;
7292         }
7293         switch (arg2->type) {
7294             case XPATH_UNDEFINED:
7295 #ifdef DEBUG_EXPR
7296                 xmlGenericError(xmlGenericErrorContext,
7297                         "NotEqual: undefined\n");
7298 #endif
7299                 break;
7300             case XPATH_NODESET:
7301             case XPATH_XSLT_TREE:
7302                 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7303                 break;
7304             case XPATH_BOOLEAN:
7305                 if ((arg1->nodesetval == NULL) ||
7306                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
7307                 else
7308                     ret = 1;
7309                 ret = (ret != arg2->boolval);
7310                 break;
7311             case XPATH_NUMBER:
7312                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7313                 break;
7314             case XPATH_STRING:
7315                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7316                 break;
7317             case XPATH_USERS:
7318             case XPATH_POINT:
7319             case XPATH_RANGE:
7320             case XPATH_LOCATIONSET:
7321                 TODO
7322                 break;
7323         }
7324         xmlXPathReleaseObject(ctxt->context, arg1);
7325         xmlXPathReleaseObject(ctxt->context, arg2);
7326         return(ret);
7327     }
7328
7329     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7330 }
7331
7332 /**
7333  * xmlXPathCompareValues:
7334  * @ctxt:  the XPath Parser context
7335  * @inf:  less than (1) or greater than (0)
7336  * @strict:  is the comparison strict
7337  *
7338  * Implement the compare operation on XPath objects:
7339  *     @arg1 < @arg2    (1, 1, ...
7340  *     @arg1 <= @arg2   (1, 0, ...
7341  *     @arg1 > @arg2    (0, 1, ...
7342  *     @arg1 >= @arg2   (0, 0, ...
7343  *
7344  * When neither object to be compared is a node-set and the operator is
7345  * <=, <, >=, >, then the objects are compared by converted both objects
7346  * to numbers and comparing the numbers according to IEEE 754. The <
7347  * comparison will be true if and only if the first number is less than the
7348  * second number. The <= comparison will be true if and only if the first
7349  * number is less than or equal to the second number. The > comparison
7350  * will be true if and only if the first number is greater than the second
7351  * number. The >= comparison will be true if and only if the first number
7352  * is greater than or equal to the second number.
7353  *
7354  * Returns 1 if the comparison succeeded, 0 if it failed
7355  */
7356 int
7357 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7358     int ret = 0, arg1i = 0, arg2i = 0;
7359     xmlXPathObjectPtr arg1, arg2;
7360
7361     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7362     arg2 = valuePop(ctxt);
7363     arg1 = valuePop(ctxt);
7364     if ((arg1 == NULL) || (arg2 == NULL)) {
7365         if (arg1 != NULL)
7366             xmlXPathReleaseObject(ctxt->context, arg1);
7367         else
7368             xmlXPathReleaseObject(ctxt->context, arg2);
7369         XP_ERROR0(XPATH_INVALID_OPERAND);
7370     }
7371
7372     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7373       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7374         /*
7375          * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7376          * are not freed from within this routine; they will be freed from the
7377          * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7378          */
7379         if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7380           ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7381             ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7382         } else {
7383             if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7384                 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7385                                                   arg1, arg2);
7386             } else {
7387                 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7388                                                   arg2, arg1);
7389             }
7390         }
7391         return(ret);
7392     }
7393
7394     if (arg1->type != XPATH_NUMBER) {
7395         valuePush(ctxt, arg1);
7396         xmlXPathNumberFunction(ctxt, 1);
7397         arg1 = valuePop(ctxt);
7398     }
7399     if (arg1->type != XPATH_NUMBER) {
7400         xmlXPathFreeObject(arg1);
7401         xmlXPathFreeObject(arg2);
7402         XP_ERROR0(XPATH_INVALID_OPERAND);
7403     }
7404     if (arg2->type != XPATH_NUMBER) {
7405         valuePush(ctxt, arg2);
7406         xmlXPathNumberFunction(ctxt, 1);
7407         arg2 = valuePop(ctxt);
7408     }
7409     if (arg2->type != XPATH_NUMBER) {
7410         xmlXPathReleaseObject(ctxt->context, arg1);
7411         xmlXPathReleaseObject(ctxt->context, arg2);
7412         XP_ERROR0(XPATH_INVALID_OPERAND);
7413     }
7414     /*
7415      * Add tests for infinity and nan
7416      * => feedback on 3.4 for Inf and NaN
7417      */
7418     /* Hand check NaN and Infinity comparisons */
7419     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7420         ret=0;
7421     } else {
7422         arg1i=xmlXPathIsInf(arg1->floatval);
7423         arg2i=xmlXPathIsInf(arg2->floatval);
7424         if (inf && strict) {
7425             if ((arg1i == -1 && arg2i != -1) ||
7426                 (arg2i == 1 && arg1i != 1)) {
7427                 ret = 1;
7428             } else if (arg1i == 0 && arg2i == 0) {
7429                 ret = (arg1->floatval < arg2->floatval);
7430             } else {
7431                 ret = 0;
7432             }
7433         }
7434         else if (inf && !strict) {
7435             if (arg1i == -1 || arg2i == 1) {
7436                 ret = 1;
7437             } else if (arg1i == 0 && arg2i == 0) {
7438                 ret = (arg1->floatval <= arg2->floatval);
7439             } else {
7440                 ret = 0;
7441             }
7442         }
7443         else if (!inf && strict) {
7444             if ((arg1i == 1 && arg2i != 1) ||
7445                 (arg2i == -1 && arg1i != -1)) {
7446                 ret = 1;
7447             } else if (arg1i == 0 && arg2i == 0) {
7448                 ret = (arg1->floatval > arg2->floatval);
7449             } else {
7450                 ret = 0;
7451             }
7452         }
7453         else if (!inf && !strict) {
7454             if (arg1i == 1 || arg2i == -1) {
7455                 ret = 1;
7456             } else if (arg1i == 0 && arg2i == 0) {
7457                 ret = (arg1->floatval >= arg2->floatval);
7458             } else {
7459                 ret = 0;
7460             }
7461         }
7462     }
7463     xmlXPathReleaseObject(ctxt->context, arg1);
7464     xmlXPathReleaseObject(ctxt->context, arg2);
7465     return(ret);
7466 }
7467
7468 /**
7469  * xmlXPathValueFlipSign:
7470  * @ctxt:  the XPath Parser context
7471  *
7472  * Implement the unary - operation on an XPath object
7473  * The numeric operators convert their operands to numbers as if
7474  * by calling the number function.
7475  */
7476 void
7477 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7478     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7479     CAST_TO_NUMBER;
7480     CHECK_TYPE(XPATH_NUMBER);
7481     if (xmlXPathIsNaN(ctxt->value->floatval))
7482         ctxt->value->floatval=xmlXPathNAN;
7483     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7484         ctxt->value->floatval=xmlXPathNINF;
7485     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7486         ctxt->value->floatval=xmlXPathPINF;
7487     else if (ctxt->value->floatval == 0) {
7488         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7489             ctxt->value->floatval = xmlXPathNZERO;
7490         else
7491             ctxt->value->floatval = 0;
7492     }
7493     else
7494         ctxt->value->floatval = - ctxt->value->floatval;
7495 }
7496
7497 /**
7498  * xmlXPathAddValues:
7499  * @ctxt:  the XPath Parser context
7500  *
7501  * Implement the add operation on XPath objects:
7502  * The numeric operators convert their operands to numbers as if
7503  * by calling the number function.
7504  */
7505 void
7506 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7507     xmlXPathObjectPtr arg;
7508     double val;
7509
7510     arg = valuePop(ctxt);
7511     if (arg == NULL)
7512         XP_ERROR(XPATH_INVALID_OPERAND);
7513     val = xmlXPathCastToNumber(arg);
7514     xmlXPathReleaseObject(ctxt->context, arg);
7515     CAST_TO_NUMBER;
7516     CHECK_TYPE(XPATH_NUMBER);
7517     ctxt->value->floatval += val;
7518 }
7519
7520 /**
7521  * xmlXPathSubValues:
7522  * @ctxt:  the XPath Parser context
7523  *
7524  * Implement the subtraction operation on XPath objects:
7525  * The numeric operators convert their operands to numbers as if
7526  * by calling the number function.
7527  */
7528 void
7529 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7530     xmlXPathObjectPtr arg;
7531     double val;
7532
7533     arg = valuePop(ctxt);
7534     if (arg == NULL)
7535         XP_ERROR(XPATH_INVALID_OPERAND);
7536     val = xmlXPathCastToNumber(arg);
7537     xmlXPathReleaseObject(ctxt->context, arg);
7538     CAST_TO_NUMBER;
7539     CHECK_TYPE(XPATH_NUMBER);
7540     ctxt->value->floatval -= val;
7541 }
7542
7543 /**
7544  * xmlXPathMultValues:
7545  * @ctxt:  the XPath Parser context
7546  *
7547  * Implement the multiply operation on XPath objects:
7548  * The numeric operators convert their operands to numbers as if
7549  * by calling the number function.
7550  */
7551 void
7552 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7553     xmlXPathObjectPtr arg;
7554     double val;
7555
7556     arg = valuePop(ctxt);
7557     if (arg == NULL)
7558         XP_ERROR(XPATH_INVALID_OPERAND);
7559     val = xmlXPathCastToNumber(arg);
7560     xmlXPathReleaseObject(ctxt->context, arg);
7561     CAST_TO_NUMBER;
7562     CHECK_TYPE(XPATH_NUMBER);
7563     ctxt->value->floatval *= val;
7564 }
7565
7566 /**
7567  * xmlXPathDivValues:
7568  * @ctxt:  the XPath Parser context
7569  *
7570  * Implement the div operation on XPath objects @arg1 / @arg2:
7571  * The numeric operators convert their operands to numbers as if
7572  * by calling the number function.
7573  */
7574 void
7575 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7576     xmlXPathObjectPtr arg;
7577     double val;
7578
7579     arg = valuePop(ctxt);
7580     if (arg == NULL)
7581         XP_ERROR(XPATH_INVALID_OPERAND);
7582     val = xmlXPathCastToNumber(arg);
7583     xmlXPathReleaseObject(ctxt->context, arg);
7584     CAST_TO_NUMBER;
7585     CHECK_TYPE(XPATH_NUMBER);
7586     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7587         ctxt->value->floatval = xmlXPathNAN;
7588     else if (val == 0 && xmlXPathGetSign(val) != 0) {
7589         if (ctxt->value->floatval == 0)
7590             ctxt->value->floatval = xmlXPathNAN;
7591         else if (ctxt->value->floatval > 0)
7592             ctxt->value->floatval = xmlXPathNINF;
7593         else if (ctxt->value->floatval < 0)
7594             ctxt->value->floatval = xmlXPathPINF;
7595     }
7596     else if (val == 0) {
7597         if (ctxt->value->floatval == 0)
7598             ctxt->value->floatval = xmlXPathNAN;
7599         else if (ctxt->value->floatval > 0)
7600             ctxt->value->floatval = xmlXPathPINF;
7601         else if (ctxt->value->floatval < 0)
7602             ctxt->value->floatval = xmlXPathNINF;
7603     } else
7604         ctxt->value->floatval /= val;
7605 }
7606
7607 /**
7608  * xmlXPathModValues:
7609  * @ctxt:  the XPath Parser context
7610  *
7611  * Implement the mod operation on XPath objects: @arg1 / @arg2
7612  * The numeric operators convert their operands to numbers as if
7613  * by calling the number function.
7614  */
7615 void
7616 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7617     xmlXPathObjectPtr arg;
7618     double arg1, arg2;
7619
7620     arg = valuePop(ctxt);
7621     if (arg == NULL)
7622         XP_ERROR(XPATH_INVALID_OPERAND);
7623     arg2 = xmlXPathCastToNumber(arg);
7624     xmlXPathReleaseObject(ctxt->context, arg);
7625     CAST_TO_NUMBER;
7626     CHECK_TYPE(XPATH_NUMBER);
7627     arg1 = ctxt->value->floatval;
7628     if (arg2 == 0)
7629         ctxt->value->floatval = xmlXPathNAN;
7630     else {
7631         ctxt->value->floatval = fmod(arg1, arg2);
7632     }
7633 }
7634
7635 /************************************************************************
7636  *                                                                      *
7637  *              The traversal functions                                 *
7638  *                                                                      *
7639  ************************************************************************/
7640
7641 /*
7642  * A traversal function enumerates nodes along an axis.
7643  * Initially it must be called with NULL, and it indicates
7644  * termination on the axis by returning NULL.
7645  */
7646 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7647                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7648
7649 /*
7650  * xmlXPathTraversalFunctionExt:
7651  * A traversal function enumerates nodes along an axis.
7652  * Initially it must be called with NULL, and it indicates
7653  * termination on the axis by returning NULL.
7654  * The context node of the traversal is specified via @contextNode.
7655  */
7656 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7657                     (xmlNodePtr cur, xmlNodePtr contextNode);
7658
7659 /*
7660  * xmlXPathNodeSetMergeFunction:
7661  * Used for merging node sets in xmlXPathCollectAndTest().
7662  */
7663 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7664                     (xmlNodeSetPtr, xmlNodeSetPtr, int);
7665
7666
7667 /**
7668  * xmlXPathNextSelf:
7669  * @ctxt:  the XPath Parser context
7670  * @cur:  the current node in the traversal
7671  *
7672  * Traversal function for the "self" direction
7673  * The self axis contains just the context node itself
7674  *
7675  * Returns the next element following that axis
7676  */
7677 xmlNodePtr
7678 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7679     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7680     if (cur == NULL)
7681         return(ctxt->context->node);
7682     return(NULL);
7683 }
7684
7685 /**
7686  * xmlXPathNextChild:
7687  * @ctxt:  the XPath Parser context
7688  * @cur:  the current node in the traversal
7689  *
7690  * Traversal function for the "child" direction
7691  * The child axis contains the children of the context node in document order.
7692  *
7693  * Returns the next element following that axis
7694  */
7695 xmlNodePtr
7696 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7697     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7698     if (cur == NULL) {
7699         if (ctxt->context->node == NULL) return(NULL);
7700         switch (ctxt->context->node->type) {
7701             case XML_ELEMENT_NODE:
7702             case XML_TEXT_NODE:
7703             case XML_CDATA_SECTION_NODE:
7704             case XML_ENTITY_REF_NODE:
7705             case XML_ENTITY_NODE:
7706             case XML_PI_NODE:
7707             case XML_COMMENT_NODE:
7708             case XML_NOTATION_NODE:
7709             case XML_DTD_NODE:
7710                 return(ctxt->context->node->children);
7711             case XML_DOCUMENT_NODE:
7712             case XML_DOCUMENT_TYPE_NODE:
7713             case XML_DOCUMENT_FRAG_NODE:
7714             case XML_HTML_DOCUMENT_NODE:
7715 #ifdef LIBXML_DOCB_ENABLED
7716             case XML_DOCB_DOCUMENT_NODE:
7717 #endif
7718                 return(((xmlDocPtr) ctxt->context->node)->children);
7719             case XML_ELEMENT_DECL:
7720             case XML_ATTRIBUTE_DECL:
7721             case XML_ENTITY_DECL:
7722             case XML_ATTRIBUTE_NODE:
7723             case XML_NAMESPACE_DECL:
7724             case XML_XINCLUDE_START:
7725             case XML_XINCLUDE_END:
7726                 return(NULL);
7727         }
7728         return(NULL);
7729     }
7730     if ((cur->type == XML_DOCUMENT_NODE) ||
7731         (cur->type == XML_HTML_DOCUMENT_NODE))
7732         return(NULL);
7733     return(cur->next);
7734 }
7735
7736 /**
7737  * xmlXPathNextChildElement:
7738  * @ctxt:  the XPath Parser context
7739  * @cur:  the current node in the traversal
7740  *
7741  * Traversal function for the "child" direction and nodes of type element.
7742  * The child axis contains the children of the context node in document order.
7743  *
7744  * Returns the next element following that axis
7745  */
7746 static xmlNodePtr
7747 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7748     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7749     if (cur == NULL) {
7750         cur = ctxt->context->node;
7751         if (cur == NULL) return(NULL);
7752         /*
7753         * Get the first element child.
7754         */
7755         switch (cur->type) {
7756             case XML_ELEMENT_NODE:
7757             case XML_DOCUMENT_FRAG_NODE:
7758             case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7759             case XML_ENTITY_NODE:
7760                 cur = cur->children;
7761                 if (cur != NULL) {
7762                     if (cur->type == XML_ELEMENT_NODE)
7763                         return(cur);
7764                     do {
7765                         cur = cur->next;
7766                     } while ((cur != NULL) &&
7767                         (cur->type != XML_ELEMENT_NODE));
7768                     return(cur);
7769                 }
7770                 return(NULL);
7771             case XML_DOCUMENT_NODE:
7772             case XML_HTML_DOCUMENT_NODE:
7773 #ifdef LIBXML_DOCB_ENABLED
7774             case XML_DOCB_DOCUMENT_NODE:
7775 #endif
7776                 return(xmlDocGetRootElement((xmlDocPtr) cur));
7777             default:
7778                 return(NULL);
7779         }
7780         return(NULL);
7781     }
7782     /*
7783     * Get the next sibling element node.
7784     */
7785     switch (cur->type) {
7786         case XML_ELEMENT_NODE:
7787         case XML_TEXT_NODE:
7788         case XML_ENTITY_REF_NODE:
7789         case XML_ENTITY_NODE:
7790         case XML_CDATA_SECTION_NODE:
7791         case XML_PI_NODE:
7792         case XML_COMMENT_NODE:
7793         case XML_XINCLUDE_END:
7794             break;
7795         /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7796         default:
7797             return(NULL);
7798     }
7799     if (cur->next != NULL) {
7800         if (cur->next->type == XML_ELEMENT_NODE)
7801             return(cur->next);
7802         cur = cur->next;
7803         do {
7804             cur = cur->next;
7805         } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7806         return(cur);
7807     }
7808     return(NULL);
7809 }
7810
7811 #if 0
7812 /**
7813  * xmlXPathNextDescendantOrSelfElemParent:
7814  * @ctxt:  the XPath Parser context
7815  * @cur:  the current node in the traversal
7816  *
7817  * Traversal function for the "descendant-or-self" axis.
7818  * Additionally it returns only nodes which can be parents of
7819  * element nodes.
7820  *
7821  *
7822  * Returns the next element following that axis
7823  */
7824 static xmlNodePtr
7825 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7826                                        xmlNodePtr contextNode)
7827 {
7828     if (cur == NULL) {
7829         if (contextNode == NULL)
7830             return(NULL);
7831         switch (contextNode->type) {
7832             case XML_ELEMENT_NODE:
7833             case XML_XINCLUDE_START:
7834             case XML_DOCUMENT_FRAG_NODE:
7835             case XML_DOCUMENT_NODE:
7836 #ifdef LIBXML_DOCB_ENABLED
7837             case XML_DOCB_DOCUMENT_NODE:
7838 #endif
7839             case XML_HTML_DOCUMENT_NODE:
7840                 return(contextNode);
7841             default:
7842                 return(NULL);
7843         }
7844         return(NULL);
7845     } else {
7846         xmlNodePtr start = cur;
7847
7848         while (cur != NULL) {
7849             switch (cur->type) {
7850                 case XML_ELEMENT_NODE:
7851                 /* TODO: OK to have XInclude here? */
7852                 case XML_XINCLUDE_START:
7853                 case XML_DOCUMENT_FRAG_NODE:
7854                     if (cur != start)
7855                         return(cur);
7856                     if (cur->children != NULL) {
7857                         cur = cur->children;
7858                         continue;
7859                     }
7860                     break;
7861                 /* Not sure if we need those here. */
7862                 case XML_DOCUMENT_NODE:
7863 #ifdef LIBXML_DOCB_ENABLED
7864                 case XML_DOCB_DOCUMENT_NODE:
7865 #endif
7866                 case XML_HTML_DOCUMENT_NODE:
7867                     if (cur != start)
7868                         return(cur);
7869                     return(xmlDocGetRootElement((xmlDocPtr) cur));
7870                 default:
7871                     break;
7872             }
7873
7874 next_sibling:
7875             if ((cur == NULL) || (cur == contextNode))
7876                 return(NULL);
7877             if (cur->next != NULL) {
7878                 cur = cur->next;
7879             } else {
7880                 cur = cur->parent;
7881                 goto next_sibling;
7882             }
7883         }
7884     }
7885     return(NULL);
7886 }
7887 #endif
7888
7889 /**
7890  * xmlXPathNextDescendant:
7891  * @ctxt:  the XPath Parser context
7892  * @cur:  the current node in the traversal
7893  *
7894  * Traversal function for the "descendant" direction
7895  * the descendant axis contains the descendants of the context node in document
7896  * order; a descendant is a child or a child of a child and so on.
7897  *
7898  * Returns the next element following that axis
7899  */
7900 xmlNodePtr
7901 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7902     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7903     if (cur == NULL) {
7904         if (ctxt->context->node == NULL)
7905             return(NULL);
7906         if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7907             (ctxt->context->node->type == XML_NAMESPACE_DECL))
7908             return(NULL);
7909
7910         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7911             return(ctxt->context->doc->children);
7912         return(ctxt->context->node->children);
7913     }
7914
7915     if (cur->type == XML_NAMESPACE_DECL)
7916         return(NULL);
7917     if (cur->children != NULL) {
7918         /*
7919          * Do not descend on entities declarations
7920          */
7921         if (cur->children->type != XML_ENTITY_DECL) {
7922             cur = cur->children;
7923             /*
7924              * Skip DTDs
7925              */
7926             if (cur->type != XML_DTD_NODE)
7927                 return(cur);
7928         }
7929     }
7930
7931     if (cur == ctxt->context->node) return(NULL);
7932
7933     while (cur->next != NULL) {
7934         cur = cur->next;
7935         if ((cur->type != XML_ENTITY_DECL) &&
7936             (cur->type != XML_DTD_NODE))
7937             return(cur);
7938     }
7939
7940     do {
7941         cur = cur->parent;
7942         if (cur == NULL) break;
7943         if (cur == ctxt->context->node) return(NULL);
7944         if (cur->next != NULL) {
7945             cur = cur->next;
7946             return(cur);
7947         }
7948     } while (cur != NULL);
7949     return(cur);
7950 }
7951
7952 /**
7953  * xmlXPathNextDescendantOrSelf:
7954  * @ctxt:  the XPath Parser context
7955  * @cur:  the current node in the traversal
7956  *
7957  * Traversal function for the "descendant-or-self" direction
7958  * the descendant-or-self axis contains the context node and the descendants
7959  * of the context node in document order; thus the context node is the first
7960  * node on the axis, and the first child of the context node is the second node
7961  * on the axis
7962  *
7963  * Returns the next element following that axis
7964  */
7965 xmlNodePtr
7966 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7967     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7968     if (cur == NULL)
7969         return(ctxt->context->node);
7970
7971     if (ctxt->context->node == NULL)
7972         return(NULL);
7973     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7974         (ctxt->context->node->type == XML_NAMESPACE_DECL))
7975         return(NULL);
7976
7977     return(xmlXPathNextDescendant(ctxt, cur));
7978 }
7979
7980 /**
7981  * xmlXPathNextParent:
7982  * @ctxt:  the XPath Parser context
7983  * @cur:  the current node in the traversal
7984  *
7985  * Traversal function for the "parent" direction
7986  * The parent axis contains the parent of the context node, if there is one.
7987  *
7988  * Returns the next element following that axis
7989  */
7990 xmlNodePtr
7991 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7992     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7993     /*
7994      * the parent of an attribute or namespace node is the element
7995      * to which the attribute or namespace node is attached
7996      * Namespace handling !!!
7997      */
7998     if (cur == NULL) {
7999         if (ctxt->context->node == NULL) return(NULL);
8000         switch (ctxt->context->node->type) {
8001             case XML_ELEMENT_NODE:
8002             case XML_TEXT_NODE:
8003             case XML_CDATA_SECTION_NODE:
8004             case XML_ENTITY_REF_NODE:
8005             case XML_ENTITY_NODE:
8006             case XML_PI_NODE:
8007             case XML_COMMENT_NODE:
8008             case XML_NOTATION_NODE:
8009             case XML_DTD_NODE:
8010             case XML_ELEMENT_DECL:
8011             case XML_ATTRIBUTE_DECL:
8012             case XML_XINCLUDE_START:
8013             case XML_XINCLUDE_END:
8014             case XML_ENTITY_DECL:
8015                 if (ctxt->context->node->parent == NULL)
8016                     return((xmlNodePtr) ctxt->context->doc);
8017                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8018                     ((ctxt->context->node->parent->name[0] == ' ') ||
8019                      (xmlStrEqual(ctxt->context->node->parent->name,
8020                                  BAD_CAST "fake node libxslt"))))
8021                     return(NULL);
8022                 return(ctxt->context->node->parent);
8023             case XML_ATTRIBUTE_NODE: {
8024                 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8025
8026                 return(att->parent);
8027             }
8028             case XML_DOCUMENT_NODE:
8029             case XML_DOCUMENT_TYPE_NODE:
8030             case XML_DOCUMENT_FRAG_NODE:
8031             case XML_HTML_DOCUMENT_NODE:
8032 #ifdef LIBXML_DOCB_ENABLED
8033             case XML_DOCB_DOCUMENT_NODE:
8034 #endif
8035                 return(NULL);
8036             case XML_NAMESPACE_DECL: {
8037                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8038
8039                 if ((ns->next != NULL) &&
8040                     (ns->next->type != XML_NAMESPACE_DECL))
8041                     return((xmlNodePtr) ns->next);
8042                 return(NULL);
8043             }
8044         }
8045     }
8046     return(NULL);
8047 }
8048
8049 /**
8050  * xmlXPathNextAncestor:
8051  * @ctxt:  the XPath Parser context
8052  * @cur:  the current node in the traversal
8053  *
8054  * Traversal function for the "ancestor" direction
8055  * the ancestor axis contains the ancestors of the context node; the ancestors
8056  * of the context node consist of the parent of context node and the parent's
8057  * parent and so on; the nodes are ordered in reverse document order; thus the
8058  * parent is the first node on the axis, and the parent's parent is the second
8059  * node on the axis
8060  *
8061  * Returns the next element following that axis
8062  */
8063 xmlNodePtr
8064 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8065     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8066     /*
8067      * the parent of an attribute or namespace node is the element
8068      * to which the attribute or namespace node is attached
8069      * !!!!!!!!!!!!!
8070      */
8071     if (cur == NULL) {
8072         if (ctxt->context->node == NULL) return(NULL);
8073         switch (ctxt->context->node->type) {
8074             case XML_ELEMENT_NODE:
8075             case XML_TEXT_NODE:
8076             case XML_CDATA_SECTION_NODE:
8077             case XML_ENTITY_REF_NODE:
8078             case XML_ENTITY_NODE:
8079             case XML_PI_NODE:
8080             case XML_COMMENT_NODE:
8081             case XML_DTD_NODE:
8082             case XML_ELEMENT_DECL:
8083             case XML_ATTRIBUTE_DECL:
8084             case XML_ENTITY_DECL:
8085             case XML_NOTATION_NODE:
8086             case XML_XINCLUDE_START:
8087             case XML_XINCLUDE_END:
8088                 if (ctxt->context->node->parent == NULL)
8089                     return((xmlNodePtr) ctxt->context->doc);
8090                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8091                     ((ctxt->context->node->parent->name[0] == ' ') ||
8092                      (xmlStrEqual(ctxt->context->node->parent->name,
8093                                  BAD_CAST "fake node libxslt"))))
8094                     return(NULL);
8095                 return(ctxt->context->node->parent);
8096             case XML_ATTRIBUTE_NODE: {
8097                 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8098
8099                 return(tmp->parent);
8100             }
8101             case XML_DOCUMENT_NODE:
8102             case XML_DOCUMENT_TYPE_NODE:
8103             case XML_DOCUMENT_FRAG_NODE:
8104             case XML_HTML_DOCUMENT_NODE:
8105 #ifdef LIBXML_DOCB_ENABLED
8106             case XML_DOCB_DOCUMENT_NODE:
8107 #endif
8108                 return(NULL);
8109             case XML_NAMESPACE_DECL: {
8110                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8111
8112                 if ((ns->next != NULL) &&
8113                     (ns->next->type != XML_NAMESPACE_DECL))
8114                     return((xmlNodePtr) ns->next);
8115                 /* Bad, how did that namespace end up here ? */
8116                 return(NULL);
8117             }
8118         }
8119         return(NULL);
8120     }
8121     if (cur == ctxt->context->doc->children)
8122         return((xmlNodePtr) ctxt->context->doc);
8123     if (cur == (xmlNodePtr) ctxt->context->doc)
8124         return(NULL);
8125     switch (cur->type) {
8126         case XML_ELEMENT_NODE:
8127         case XML_TEXT_NODE:
8128         case XML_CDATA_SECTION_NODE:
8129         case XML_ENTITY_REF_NODE:
8130         case XML_ENTITY_NODE:
8131         case XML_PI_NODE:
8132         case XML_COMMENT_NODE:
8133         case XML_NOTATION_NODE:
8134         case XML_DTD_NODE:
8135         case XML_ELEMENT_DECL:
8136         case XML_ATTRIBUTE_DECL:
8137         case XML_ENTITY_DECL:
8138         case XML_XINCLUDE_START:
8139         case XML_XINCLUDE_END:
8140             if (cur->parent == NULL)
8141                 return(NULL);
8142             if ((cur->parent->type == XML_ELEMENT_NODE) &&
8143                 ((cur->parent->name[0] == ' ') ||
8144                  (xmlStrEqual(cur->parent->name,
8145                               BAD_CAST "fake node libxslt"))))
8146                 return(NULL);
8147             return(cur->parent);
8148         case XML_ATTRIBUTE_NODE: {
8149             xmlAttrPtr att = (xmlAttrPtr) cur;
8150
8151             return(att->parent);
8152         }
8153         case XML_NAMESPACE_DECL: {
8154             xmlNsPtr ns = (xmlNsPtr) cur;
8155
8156             if ((ns->next != NULL) &&
8157                 (ns->next->type != XML_NAMESPACE_DECL))
8158                 return((xmlNodePtr) ns->next);
8159             /* Bad, how did that namespace end up here ? */
8160             return(NULL);
8161         }
8162         case XML_DOCUMENT_NODE:
8163         case XML_DOCUMENT_TYPE_NODE:
8164         case XML_DOCUMENT_FRAG_NODE:
8165         case XML_HTML_DOCUMENT_NODE:
8166 #ifdef LIBXML_DOCB_ENABLED
8167         case XML_DOCB_DOCUMENT_NODE:
8168 #endif
8169             return(NULL);
8170     }
8171     return(NULL);
8172 }
8173
8174 /**
8175  * xmlXPathNextAncestorOrSelf:
8176  * @ctxt:  the XPath Parser context
8177  * @cur:  the current node in the traversal
8178  *
8179  * Traversal function for the "ancestor-or-self" direction
8180  * he ancestor-or-self axis contains the context node and ancestors of
8181  * the context node in reverse document order; thus the context node is
8182  * the first node on the axis, and the context node's parent the second;
8183  * parent here is defined the same as with the parent axis.
8184  *
8185  * Returns the next element following that axis
8186  */
8187 xmlNodePtr
8188 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8189     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8190     if (cur == NULL)
8191         return(ctxt->context->node);
8192     return(xmlXPathNextAncestor(ctxt, cur));
8193 }
8194
8195 /**
8196  * xmlXPathNextFollowingSibling:
8197  * @ctxt:  the XPath Parser context
8198  * @cur:  the current node in the traversal
8199  *
8200  * Traversal function for the "following-sibling" direction
8201  * The following-sibling axis contains the following siblings of the context
8202  * node in document order.
8203  *
8204  * Returns the next element following that axis
8205  */
8206 xmlNodePtr
8207 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8208     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8209     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8210         (ctxt->context->node->type == XML_NAMESPACE_DECL))
8211         return(NULL);
8212     if (cur == (xmlNodePtr) ctxt->context->doc)
8213         return(NULL);
8214     if (cur == NULL)
8215         return(ctxt->context->node->next);
8216     return(cur->next);
8217 }
8218
8219 /**
8220  * xmlXPathNextPrecedingSibling:
8221  * @ctxt:  the XPath Parser context
8222  * @cur:  the current node in the traversal
8223  *
8224  * Traversal function for the "preceding-sibling" direction
8225  * The preceding-sibling axis contains the preceding siblings of the context
8226  * node in reverse document order; the first preceding sibling is first on the
8227  * axis; the sibling preceding that node is the second on the axis and so on.
8228  *
8229  * Returns the next element following that axis
8230  */
8231 xmlNodePtr
8232 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8233     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8234     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8235         (ctxt->context->node->type == XML_NAMESPACE_DECL))
8236         return(NULL);
8237     if (cur == (xmlNodePtr) ctxt->context->doc)
8238         return(NULL);
8239     if (cur == NULL)
8240         return(ctxt->context->node->prev);
8241     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8242         cur = cur->prev;
8243         if (cur == NULL)
8244             return(ctxt->context->node->prev);
8245     }
8246     return(cur->prev);
8247 }
8248
8249 /**
8250  * xmlXPathNextFollowing:
8251  * @ctxt:  the XPath Parser context
8252  * @cur:  the current node in the traversal
8253  *
8254  * Traversal function for the "following" direction
8255  * The following axis contains all nodes in the same document as the context
8256  * node that are after the context node in document order, excluding any
8257  * descendants and excluding attribute nodes and namespace nodes; the nodes
8258  * are ordered in document order
8259  *
8260  * Returns the next element following that axis
8261  */
8262 xmlNodePtr
8263 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8264     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8265     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8266         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8267         return(cur->children);
8268
8269     if (cur == NULL) {
8270         cur = ctxt->context->node;
8271         if (cur->type == XML_ATTRIBUTE_NODE) {
8272             cur = cur->parent;
8273         } else if (cur->type == XML_NAMESPACE_DECL) {
8274             xmlNsPtr ns = (xmlNsPtr) cur;
8275
8276             if ((ns->next == NULL) ||
8277                 (ns->next->type == XML_NAMESPACE_DECL))
8278                 return (NULL);
8279             cur = (xmlNodePtr) ns->next;
8280         }
8281     }
8282     if (cur == NULL) return(NULL) ; /* ERROR */
8283     if (cur->next != NULL) return(cur->next) ;
8284     do {
8285         cur = cur->parent;
8286         if (cur == NULL) break;
8287         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8288         if (cur->next != NULL) return(cur->next);
8289     } while (cur != NULL);
8290     return(cur);
8291 }
8292
8293 /*
8294  * xmlXPathIsAncestor:
8295  * @ancestor:  the ancestor node
8296  * @node:  the current node
8297  *
8298  * Check that @ancestor is a @node's ancestor
8299  *
8300  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8301  */
8302 static int
8303 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8304     if ((ancestor == NULL) || (node == NULL)) return(0);
8305     if (node->type == XML_NAMESPACE_DECL)
8306         return(0);
8307     if (ancestor->type == XML_NAMESPACE_DECL)
8308         return(0);
8309     /* nodes need to be in the same document */
8310     if (ancestor->doc != node->doc) return(0);
8311     /* avoid searching if ancestor or node is the root node */
8312     if (ancestor == (xmlNodePtr) node->doc) return(1);
8313     if (node == (xmlNodePtr) ancestor->doc) return(0);
8314     while (node->parent != NULL) {
8315         if (node->parent == ancestor)
8316             return(1);
8317         node = node->parent;
8318     }
8319     return(0);
8320 }
8321
8322 /**
8323  * xmlXPathNextPreceding:
8324  * @ctxt:  the XPath Parser context
8325  * @cur:  the current node in the traversal
8326  *
8327  * Traversal function for the "preceding" direction
8328  * the preceding axis contains all nodes in the same document as the context
8329  * node that are before the context node in document order, excluding any
8330  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8331  * ordered in reverse document order
8332  *
8333  * Returns the next element following that axis
8334  */
8335 xmlNodePtr
8336 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8337 {
8338     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8339     if (cur == NULL) {
8340         cur = ctxt->context->node;
8341         if (cur->type == XML_ATTRIBUTE_NODE) {
8342             cur = cur->parent;
8343         } else if (cur->type == XML_NAMESPACE_DECL) {
8344             xmlNsPtr ns = (xmlNsPtr) cur;
8345
8346             if ((ns->next == NULL) ||
8347                 (ns->next->type == XML_NAMESPACE_DECL))
8348                 return (NULL);
8349             cur = (xmlNodePtr) ns->next;
8350         }
8351     }
8352     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8353         return (NULL);
8354     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8355         cur = cur->prev;
8356     do {
8357         if (cur->prev != NULL) {
8358             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8359             return (cur);
8360         }
8361
8362         cur = cur->parent;
8363         if (cur == NULL)
8364             return (NULL);
8365         if (cur == ctxt->context->doc->children)
8366             return (NULL);
8367     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8368     return (cur);
8369 }
8370
8371 /**
8372  * xmlXPathNextPrecedingInternal:
8373  * @ctxt:  the XPath Parser context
8374  * @cur:  the current node in the traversal
8375  *
8376  * Traversal function for the "preceding" direction
8377  * the preceding axis contains all nodes in the same document as the context
8378  * node that are before the context node in document order, excluding any
8379  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8380  * ordered in reverse document order
8381  * This is a faster implementation but internal only since it requires a
8382  * state kept in the parser context: ctxt->ancestor.
8383  *
8384  * Returns the next element following that axis
8385  */
8386 static xmlNodePtr
8387 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8388                               xmlNodePtr cur)
8389 {
8390     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8391     if (cur == NULL) {
8392         cur = ctxt->context->node;
8393         if (cur == NULL)
8394             return (NULL);
8395         if (cur->type == XML_ATTRIBUTE_NODE) {
8396             cur = cur->parent;
8397         } else if (cur->type == XML_NAMESPACE_DECL) {
8398             xmlNsPtr ns = (xmlNsPtr) cur;
8399
8400             if ((ns->next == NULL) ||
8401                 (ns->next->type == XML_NAMESPACE_DECL))
8402                 return (NULL);
8403             cur = (xmlNodePtr) ns->next;
8404         }
8405         ctxt->ancestor = cur->parent;
8406     }
8407     if (cur->type == XML_NAMESPACE_DECL)
8408         return(NULL);
8409     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8410         cur = cur->prev;
8411     while (cur->prev == NULL) {
8412         cur = cur->parent;
8413         if (cur == NULL)
8414             return (NULL);
8415         if (cur == ctxt->context->doc->children)
8416             return (NULL);
8417         if (cur != ctxt->ancestor)
8418             return (cur);
8419         ctxt->ancestor = cur->parent;
8420     }
8421     cur = cur->prev;
8422     while (cur->last != NULL)
8423         cur = cur->last;
8424     return (cur);
8425 }
8426
8427 /**
8428  * xmlXPathNextNamespace:
8429  * @ctxt:  the XPath Parser context
8430  * @cur:  the current attribute in the traversal
8431  *
8432  * Traversal function for the "namespace" direction
8433  * the namespace axis contains the namespace nodes of the context node;
8434  * the order of nodes on this axis is implementation-defined; the axis will
8435  * be empty unless the context node is an element
8436  *
8437  * We keep the XML namespace node at the end of the list.
8438  *
8439  * Returns the next element following that axis
8440  */
8441 xmlNodePtr
8442 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8443     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8444     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8445     if (cur == NULL) {
8446         if (ctxt->context->tmpNsList != NULL)
8447             xmlFree(ctxt->context->tmpNsList);
8448         ctxt->context->tmpNsList =
8449             xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8450         ctxt->context->tmpNsNr = 0;
8451         if (ctxt->context->tmpNsList != NULL) {
8452             while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8453                 ctxt->context->tmpNsNr++;
8454             }
8455         }
8456         return((xmlNodePtr) xmlXPathXMLNamespace);
8457     }
8458     if (ctxt->context->tmpNsNr > 0) {
8459         return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8460     } else {
8461         if (ctxt->context->tmpNsList != NULL)
8462             xmlFree(ctxt->context->tmpNsList);
8463         ctxt->context->tmpNsList = NULL;
8464         return(NULL);
8465     }
8466 }
8467
8468 /**
8469  * xmlXPathNextAttribute:
8470  * @ctxt:  the XPath Parser context
8471  * @cur:  the current attribute in the traversal
8472  *
8473  * Traversal function for the "attribute" direction
8474  * TODO: support DTD inherited default attributes
8475  *
8476  * Returns the next element following that axis
8477  */
8478 xmlNodePtr
8479 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8480     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8481     if (ctxt->context->node == NULL)
8482         return(NULL);
8483     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8484         return(NULL);
8485     if (cur == NULL) {
8486         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8487             return(NULL);
8488         return((xmlNodePtr)ctxt->context->node->properties);
8489     }
8490     return((xmlNodePtr)cur->next);
8491 }
8492
8493 /************************************************************************
8494  *                                                                      *
8495  *              NodeTest Functions                                      *
8496  *                                                                      *
8497  ************************************************************************/
8498
8499 #define IS_FUNCTION                     200
8500
8501
8502 /************************************************************************
8503  *                                                                      *
8504  *              Implicit tree core function library                     *
8505  *                                                                      *
8506  ************************************************************************/
8507
8508 /**
8509  * xmlXPathRoot:
8510  * @ctxt:  the XPath Parser context
8511  *
8512  * Initialize the context to the root of the document
8513  */
8514 void
8515 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8516     if ((ctxt == NULL) || (ctxt->context == NULL))
8517         return;
8518     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8519     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8520         ctxt->context->node));
8521 }
8522
8523 /************************************************************************
8524  *                                                                      *
8525  *              The explicit core function library                      *
8526  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8527  *                                                                      *
8528  ************************************************************************/
8529
8530
8531 /**
8532  * xmlXPathLastFunction:
8533  * @ctxt:  the XPath Parser context
8534  * @nargs:  the number of arguments
8535  *
8536  * Implement the last() XPath function
8537  *    number last()
8538  * The last function returns the number of nodes in the context node list.
8539  */
8540 void
8541 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8542     CHECK_ARITY(0);
8543     if (ctxt->context->contextSize >= 0) {
8544         valuePush(ctxt,
8545             xmlXPathCacheNewFloat(ctxt->context,
8546                 (double) ctxt->context->contextSize));
8547 #ifdef DEBUG_EXPR
8548         xmlGenericError(xmlGenericErrorContext,
8549                 "last() : %d\n", ctxt->context->contextSize);
8550 #endif
8551     } else {
8552         XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8553     }
8554 }
8555
8556 /**
8557  * xmlXPathPositionFunction:
8558  * @ctxt:  the XPath Parser context
8559  * @nargs:  the number of arguments
8560  *
8561  * Implement the position() XPath function
8562  *    number position()
8563  * The position function returns the position of the context node in the
8564  * context node list. The first position is 1, and so the last position
8565  * will be equal to last().
8566  */
8567 void
8568 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8569     CHECK_ARITY(0);
8570     if (ctxt->context->proximityPosition >= 0) {
8571         valuePush(ctxt,
8572               xmlXPathCacheNewFloat(ctxt->context,
8573                 (double) ctxt->context->proximityPosition));
8574 #ifdef DEBUG_EXPR
8575         xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8576                 ctxt->context->proximityPosition);
8577 #endif
8578     } else {
8579         XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8580     }
8581 }
8582
8583 /**
8584  * xmlXPathCountFunction:
8585  * @ctxt:  the XPath Parser context
8586  * @nargs:  the number of arguments
8587  *
8588  * Implement the count() XPath function
8589  *    number count(node-set)
8590  */
8591 void
8592 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8593     xmlXPathObjectPtr cur;
8594
8595     CHECK_ARITY(1);
8596     if ((ctxt->value == NULL) ||
8597         ((ctxt->value->type != XPATH_NODESET) &&
8598          (ctxt->value->type != XPATH_XSLT_TREE)))
8599         XP_ERROR(XPATH_INVALID_TYPE);
8600     cur = valuePop(ctxt);
8601
8602     if ((cur == NULL) || (cur->nodesetval == NULL))
8603         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8604     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8605         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8606             (double) cur->nodesetval->nodeNr));
8607     } else {
8608         if ((cur->nodesetval->nodeNr != 1) ||
8609             (cur->nodesetval->nodeTab == NULL)) {
8610             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8611         } else {
8612             xmlNodePtr tmp;
8613             int i = 0;
8614
8615             tmp = cur->nodesetval->nodeTab[0];
8616             if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8617                 tmp = tmp->children;
8618                 while (tmp != NULL) {
8619                     tmp = tmp->next;
8620                     i++;
8621                 }
8622             }
8623             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8624         }
8625     }
8626     xmlXPathReleaseObject(ctxt->context, cur);
8627 }
8628
8629 /**
8630  * xmlXPathGetElementsByIds:
8631  * @doc:  the document
8632  * @ids:  a whitespace separated list of IDs
8633  *
8634  * Selects elements by their unique ID.
8635  *
8636  * Returns a node-set of selected elements.
8637  */
8638 static xmlNodeSetPtr
8639 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8640     xmlNodeSetPtr ret;
8641     const xmlChar *cur = ids;
8642     xmlChar *ID;
8643     xmlAttrPtr attr;
8644     xmlNodePtr elem = NULL;
8645
8646     if (ids == NULL) return(NULL);
8647
8648     ret = xmlXPathNodeSetCreate(NULL);
8649     if (ret == NULL)
8650         return(ret);
8651
8652     while (IS_BLANK_CH(*cur)) cur++;
8653     while (*cur != 0) {
8654         while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8655             cur++;
8656
8657         ID = xmlStrndup(ids, cur - ids);
8658         if (ID != NULL) {
8659             /*
8660              * We used to check the fact that the value passed
8661              * was an NCName, but this generated much troubles for
8662              * me and Aleksey Sanin, people blatantly violated that
8663              * constaint, like Visa3D spec.
8664              * if (xmlValidateNCName(ID, 1) == 0)
8665              */
8666             attr = xmlGetID(doc, ID);
8667             if (attr != NULL) {
8668                 if (attr->type == XML_ATTRIBUTE_NODE)
8669                     elem = attr->parent;
8670                 else if (attr->type == XML_ELEMENT_NODE)
8671                     elem = (xmlNodePtr) attr;
8672                 else
8673                     elem = NULL;
8674                 if (elem != NULL)
8675                     xmlXPathNodeSetAdd(ret, elem);
8676             }
8677             xmlFree(ID);
8678         }
8679
8680         while (IS_BLANK_CH(*cur)) cur++;
8681         ids = cur;
8682     }
8683     return(ret);
8684 }
8685
8686 /**
8687  * xmlXPathIdFunction:
8688  * @ctxt:  the XPath Parser context
8689  * @nargs:  the number of arguments
8690  *
8691  * Implement the id() XPath function
8692  *    node-set id(object)
8693  * The id function selects elements by their unique ID
8694  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8695  * then the result is the union of the result of applying id to the
8696  * string value of each of the nodes in the argument node-set. When the
8697  * argument to id is of any other type, the argument is converted to a
8698  * string as if by a call to the string function; the string is split
8699  * into a whitespace-separated list of tokens (whitespace is any sequence
8700  * of characters matching the production S); the result is a node-set
8701  * containing the elements in the same document as the context node that
8702  * have a unique ID equal to any of the tokens in the list.
8703  */
8704 void
8705 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8706     xmlChar *tokens;
8707     xmlNodeSetPtr ret;
8708     xmlXPathObjectPtr obj;
8709
8710     CHECK_ARITY(1);
8711     obj = valuePop(ctxt);
8712     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8713     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8714         xmlNodeSetPtr ns;
8715         int i;
8716
8717         ret = xmlXPathNodeSetCreate(NULL);
8718         /*
8719          * FIXME -- in an out-of-memory condition this will behave badly.
8720          * The solution is not clear -- we already popped an item from
8721          * ctxt, so the object is in a corrupt state.
8722          */
8723
8724         if (obj->nodesetval != NULL) {
8725             for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8726                 tokens =
8727                     xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8728                 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8729                 ret = xmlXPathNodeSetMerge(ret, ns);
8730                 xmlXPathFreeNodeSet(ns);
8731                 if (tokens != NULL)
8732                     xmlFree(tokens);
8733             }
8734         }
8735         xmlXPathReleaseObject(ctxt->context, obj);
8736         valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8737         return;
8738     }
8739     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8740     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8741     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8742     xmlXPathReleaseObject(ctxt->context, obj);
8743     return;
8744 }
8745
8746 /**
8747  * xmlXPathLocalNameFunction:
8748  * @ctxt:  the XPath Parser context
8749  * @nargs:  the number of arguments
8750  *
8751  * Implement the local-name() XPath function
8752  *    string local-name(node-set?)
8753  * The local-name function returns a string containing the local part
8754  * of the name of the node in the argument node-set that is first in
8755  * document order. If the node-set is empty or the first node has no
8756  * name, an empty string is returned. If the argument is omitted it
8757  * defaults to the context node.
8758  */
8759 void
8760 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8761     xmlXPathObjectPtr cur;
8762
8763     if (ctxt == NULL) return;
8764
8765     if (nargs == 0) {
8766         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8767             ctxt->context->node));
8768         nargs = 1;
8769     }
8770
8771     CHECK_ARITY(1);
8772     if ((ctxt->value == NULL) ||
8773         ((ctxt->value->type != XPATH_NODESET) &&
8774          (ctxt->value->type != XPATH_XSLT_TREE)))
8775         XP_ERROR(XPATH_INVALID_TYPE);
8776     cur = valuePop(ctxt);
8777
8778     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8779         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8780     } else {
8781         int i = 0; /* Should be first in document order !!!!! */
8782         switch (cur->nodesetval->nodeTab[i]->type) {
8783         case XML_ELEMENT_NODE:
8784         case XML_ATTRIBUTE_NODE:
8785         case XML_PI_NODE:
8786             if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8787                 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8788             else
8789                 valuePush(ctxt,
8790                       xmlXPathCacheNewString(ctxt->context,
8791                         cur->nodesetval->nodeTab[i]->name));
8792             break;
8793         case XML_NAMESPACE_DECL:
8794             valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8795                         ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8796             break;
8797         default:
8798             valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8799         }
8800     }
8801     xmlXPathReleaseObject(ctxt->context, cur);
8802 }
8803
8804 /**
8805  * xmlXPathNamespaceURIFunction:
8806  * @ctxt:  the XPath Parser context
8807  * @nargs:  the number of arguments
8808  *
8809  * Implement the namespace-uri() XPath function
8810  *    string namespace-uri(node-set?)
8811  * The namespace-uri function returns a string containing the
8812  * namespace URI of the expanded name of the node in the argument
8813  * node-set that is first in document order. If the node-set is empty,
8814  * the first node has no name, or the expanded name has no namespace
8815  * URI, an empty string is returned. If the argument is omitted it
8816  * defaults to the context node.
8817  */
8818 void
8819 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8820     xmlXPathObjectPtr cur;
8821
8822     if (ctxt == NULL) return;
8823
8824     if (nargs == 0) {
8825         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8826             ctxt->context->node));
8827         nargs = 1;
8828     }
8829     CHECK_ARITY(1);
8830     if ((ctxt->value == NULL) ||
8831         ((ctxt->value->type != XPATH_NODESET) &&
8832          (ctxt->value->type != XPATH_XSLT_TREE)))
8833         XP_ERROR(XPATH_INVALID_TYPE);
8834     cur = valuePop(ctxt);
8835
8836     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8837         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8838     } else {
8839         int i = 0; /* Should be first in document order !!!!! */
8840         switch (cur->nodesetval->nodeTab[i]->type) {
8841         case XML_ELEMENT_NODE:
8842         case XML_ATTRIBUTE_NODE:
8843             if (cur->nodesetval->nodeTab[i]->ns == NULL)
8844                 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8845             else
8846                 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8847                           cur->nodesetval->nodeTab[i]->ns->href));
8848             break;
8849         default:
8850             valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8851         }
8852     }
8853     xmlXPathReleaseObject(ctxt->context, cur);
8854 }
8855
8856 /**
8857  * xmlXPathNameFunction:
8858  * @ctxt:  the XPath Parser context
8859  * @nargs:  the number of arguments
8860  *
8861  * Implement the name() XPath function
8862  *    string name(node-set?)
8863  * The name function returns a string containing a QName representing
8864  * the name of the node in the argument node-set that is first in document
8865  * order. The QName must represent the name with respect to the namespace
8866  * declarations in effect on the node whose name is being represented.
8867  * Typically, this will be the form in which the name occurred in the XML
8868  * source. This need not be the case if there are namespace declarations
8869  * in effect on the node that associate multiple prefixes with the same
8870  * namespace. However, an implementation may include information about
8871  * the original prefix in its representation of nodes; in this case, an
8872  * implementation can ensure that the returned string is always the same
8873  * as the QName used in the XML source. If the argument it omitted it
8874  * defaults to the context node.
8875  * Libxml keep the original prefix so the "real qualified name" used is
8876  * returned.
8877  */
8878 static void
8879 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8880 {
8881     xmlXPathObjectPtr cur;
8882
8883     if (nargs == 0) {
8884         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8885             ctxt->context->node));
8886         nargs = 1;
8887     }
8888
8889     CHECK_ARITY(1);
8890     if ((ctxt->value == NULL) ||
8891         ((ctxt->value->type != XPATH_NODESET) &&
8892          (ctxt->value->type != XPATH_XSLT_TREE)))
8893         XP_ERROR(XPATH_INVALID_TYPE);
8894     cur = valuePop(ctxt);
8895
8896     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8897         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8898     } else {
8899         int i = 0;              /* Should be first in document order !!!!! */
8900
8901         switch (cur->nodesetval->nodeTab[i]->type) {
8902             case XML_ELEMENT_NODE:
8903             case XML_ATTRIBUTE_NODE:
8904                 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8905                     valuePush(ctxt,
8906                         xmlXPathCacheNewCString(ctxt->context, ""));
8907                 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8908                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8909                     valuePush(ctxt,
8910                         xmlXPathCacheNewString(ctxt->context,
8911                             cur->nodesetval->nodeTab[i]->name));
8912                 } else {
8913                     xmlChar *fullname;
8914
8915                     fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8916                                      cur->nodesetval->nodeTab[i]->ns->prefix,
8917                                      NULL, 0);
8918                     if (fullname == cur->nodesetval->nodeTab[i]->name)
8919                         fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8920                     if (fullname == NULL) {
8921                         XP_ERROR(XPATH_MEMORY_ERROR);
8922                     }
8923                     valuePush(ctxt, xmlXPathCacheWrapString(
8924                         ctxt->context, fullname));
8925                 }
8926                 break;
8927             default:
8928                 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8929                     cur->nodesetval->nodeTab[i]));
8930                 xmlXPathLocalNameFunction(ctxt, 1);
8931         }
8932     }
8933     xmlXPathReleaseObject(ctxt->context, cur);
8934 }
8935
8936
8937 /**
8938  * xmlXPathStringFunction:
8939  * @ctxt:  the XPath Parser context
8940  * @nargs:  the number of arguments
8941  *
8942  * Implement the string() XPath function
8943  *    string string(object?)
8944  * The string function converts an object to a string as follows:
8945  *    - A node-set is converted to a string by returning the value of
8946  *      the node in the node-set that is first in document order.
8947  *      If the node-set is empty, an empty string is returned.
8948  *    - A number is converted to a string as follows
8949  *      + NaN is converted to the string NaN
8950  *      + positive zero is converted to the string 0
8951  *      + negative zero is converted to the string 0
8952  *      + positive infinity is converted to the string Infinity
8953  *      + negative infinity is converted to the string -Infinity
8954  *      + if the number is an integer, the number is represented in
8955  *        decimal form as a Number with no decimal point and no leading
8956  *        zeros, preceded by a minus sign (-) if the number is negative
8957  *      + otherwise, the number is represented in decimal form as a
8958  *        Number including a decimal point with at least one digit
8959  *        before the decimal point and at least one digit after the
8960  *        decimal point, preceded by a minus sign (-) if the number
8961  *        is negative; there must be no leading zeros before the decimal
8962  *        point apart possibly from the one required digit immediately
8963  *        before the decimal point; beyond the one required digit
8964  *        after the decimal point there must be as many, but only as
8965  *        many, more digits as are needed to uniquely distinguish the
8966  *        number from all other IEEE 754 numeric values.
8967  *    - The boolean false value is converted to the string false.
8968  *      The boolean true value is converted to the string true.
8969  *
8970  * If the argument is omitted, it defaults to a node-set with the
8971  * context node as its only member.
8972  */
8973 void
8974 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8975     xmlXPathObjectPtr cur;
8976
8977     if (ctxt == NULL) return;
8978     if (nargs == 0) {
8979     valuePush(ctxt,
8980         xmlXPathCacheWrapString(ctxt->context,
8981             xmlXPathCastNodeToString(ctxt->context->node)));
8982         return;
8983     }
8984
8985     CHECK_ARITY(1);
8986     cur = valuePop(ctxt);
8987     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8988     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8989 }
8990
8991 /**
8992  * xmlXPathStringLengthFunction:
8993  * @ctxt:  the XPath Parser context
8994  * @nargs:  the number of arguments
8995  *
8996  * Implement the string-length() XPath function
8997  *    number string-length(string?)
8998  * The string-length returns the number of characters in the string
8999  * (see [3.6 Strings]). If the argument is omitted, it defaults to
9000  * the context node converted to a string, in other words the value
9001  * of the context node.
9002  */
9003 void
9004 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9005     xmlXPathObjectPtr cur;
9006
9007     if (nargs == 0) {
9008         if ((ctxt == NULL) || (ctxt->context == NULL))
9009             return;
9010         if (ctxt->context->node == NULL) {
9011             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
9012         } else {
9013             xmlChar *content;
9014
9015             content = xmlXPathCastNodeToString(ctxt->context->node);
9016             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9017                 xmlUTF8Strlen(content)));
9018             xmlFree(content);
9019         }
9020         return;
9021     }
9022     CHECK_ARITY(1);
9023     CAST_TO_STRING;
9024     CHECK_TYPE(XPATH_STRING);
9025     cur = valuePop(ctxt);
9026     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9027         xmlUTF8Strlen(cur->stringval)));
9028     xmlXPathReleaseObject(ctxt->context, cur);
9029 }
9030
9031 /**
9032  * xmlXPathConcatFunction:
9033  * @ctxt:  the XPath Parser context
9034  * @nargs:  the number of arguments
9035  *
9036  * Implement the concat() XPath function
9037  *    string concat(string, string, string*)
9038  * The concat function returns the concatenation of its arguments.
9039  */
9040 void
9041 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9042     xmlXPathObjectPtr cur, newobj;
9043     xmlChar *tmp;
9044
9045     if (ctxt == NULL) return;
9046     if (nargs < 2) {
9047         CHECK_ARITY(2);
9048     }
9049
9050     CAST_TO_STRING;
9051     cur = valuePop(ctxt);
9052     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9053         xmlXPathReleaseObject(ctxt->context, cur);
9054         return;
9055     }
9056     nargs--;
9057
9058     while (nargs > 0) {
9059         CAST_TO_STRING;
9060         newobj = valuePop(ctxt);
9061         if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9062             xmlXPathReleaseObject(ctxt->context, newobj);
9063             xmlXPathReleaseObject(ctxt->context, cur);
9064             XP_ERROR(XPATH_INVALID_TYPE);
9065         }
9066         tmp = xmlStrcat(newobj->stringval, cur->stringval);
9067         newobj->stringval = cur->stringval;
9068         cur->stringval = tmp;
9069         xmlXPathReleaseObject(ctxt->context, newobj);
9070         nargs--;
9071     }
9072     valuePush(ctxt, cur);
9073 }
9074
9075 /**
9076  * xmlXPathContainsFunction:
9077  * @ctxt:  the XPath Parser context
9078  * @nargs:  the number of arguments
9079  *
9080  * Implement the contains() XPath function
9081  *    boolean contains(string, string)
9082  * The contains function returns true if the first argument string
9083  * contains the second argument string, and otherwise returns false.
9084  */
9085 void
9086 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9087     xmlXPathObjectPtr hay, needle;
9088
9089     CHECK_ARITY(2);
9090     CAST_TO_STRING;
9091     CHECK_TYPE(XPATH_STRING);
9092     needle = valuePop(ctxt);
9093     CAST_TO_STRING;
9094     hay = valuePop(ctxt);
9095
9096     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9097         xmlXPathReleaseObject(ctxt->context, hay);
9098         xmlXPathReleaseObject(ctxt->context, needle);
9099         XP_ERROR(XPATH_INVALID_TYPE);
9100     }
9101     if (xmlStrstr(hay->stringval, needle->stringval))
9102         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9103     else
9104         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9105     xmlXPathReleaseObject(ctxt->context, hay);
9106     xmlXPathReleaseObject(ctxt->context, needle);
9107 }
9108
9109 /**
9110  * xmlXPathStartsWithFunction:
9111  * @ctxt:  the XPath Parser context
9112  * @nargs:  the number of arguments
9113  *
9114  * Implement the starts-with() XPath function
9115  *    boolean starts-with(string, string)
9116  * The starts-with function returns true if the first argument string
9117  * starts with the second argument string, and otherwise returns false.
9118  */
9119 void
9120 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9121     xmlXPathObjectPtr hay, needle;
9122     int n;
9123
9124     CHECK_ARITY(2);
9125     CAST_TO_STRING;
9126     CHECK_TYPE(XPATH_STRING);
9127     needle = valuePop(ctxt);
9128     CAST_TO_STRING;
9129     hay = valuePop(ctxt);
9130
9131     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9132         xmlXPathReleaseObject(ctxt->context, hay);
9133         xmlXPathReleaseObject(ctxt->context, needle);
9134         XP_ERROR(XPATH_INVALID_TYPE);
9135     }
9136     n = xmlStrlen(needle->stringval);
9137     if (xmlStrncmp(hay->stringval, needle->stringval, n))
9138         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9139     else
9140         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9141     xmlXPathReleaseObject(ctxt->context, hay);
9142     xmlXPathReleaseObject(ctxt->context, needle);
9143 }
9144
9145 /**
9146  * xmlXPathSubstringFunction:
9147  * @ctxt:  the XPath Parser context
9148  * @nargs:  the number of arguments
9149  *
9150  * Implement the substring() XPath function
9151  *    string substring(string, number, number?)
9152  * The substring function returns the substring of the first argument
9153  * starting at the position specified in the second argument with
9154  * length specified in the third argument. For example,
9155  * substring("12345",2,3) returns "234". If the third argument is not
9156  * specified, it returns the substring starting at the position specified
9157  * in the second argument and continuing to the end of the string. For
9158  * example, substring("12345",2) returns "2345".  More precisely, each
9159  * character in the string (see [3.6 Strings]) is considered to have a
9160  * numeric position: the position of the first character is 1, the position
9161  * of the second character is 2 and so on. The returned substring contains
9162  * those characters for which the position of the character is greater than
9163  * or equal to the second argument and, if the third argument is specified,
9164  * less than the sum of the second and third arguments; the comparisons
9165  * and addition used for the above follow the standard IEEE 754 rules. Thus:
9166  *  - substring("12345", 1.5, 2.6) returns "234"
9167  *  - substring("12345", 0, 3) returns "12"
9168  *  - substring("12345", 0 div 0, 3) returns ""
9169  *  - substring("12345", 1, 0 div 0) returns ""
9170  *  - substring("12345", -42, 1 div 0) returns "12345"
9171  *  - substring("12345", -1 div 0, 1 div 0) returns ""
9172  */
9173 void
9174 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9175     xmlXPathObjectPtr str, start, len;
9176     double le=0, in;
9177     int i, l, m;
9178     xmlChar *ret;
9179
9180     if (nargs < 2) {
9181         CHECK_ARITY(2);
9182     }
9183     if (nargs > 3) {
9184         CHECK_ARITY(3);
9185     }
9186     /*
9187      * take care of possible last (position) argument
9188     */
9189     if (nargs == 3) {
9190         CAST_TO_NUMBER;
9191         CHECK_TYPE(XPATH_NUMBER);
9192         len = valuePop(ctxt);
9193         le = len->floatval;
9194         xmlXPathReleaseObject(ctxt->context, len);
9195     }
9196
9197     CAST_TO_NUMBER;
9198     CHECK_TYPE(XPATH_NUMBER);
9199     start = valuePop(ctxt);
9200     in = start->floatval;
9201     xmlXPathReleaseObject(ctxt->context, start);
9202     CAST_TO_STRING;
9203     CHECK_TYPE(XPATH_STRING);
9204     str = valuePop(ctxt);
9205     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9206
9207     /*
9208      * If last pos not present, calculate last position
9209     */
9210     if (nargs != 3) {
9211         le = (double)m;
9212         if (in < 1.0)
9213             in = 1.0;
9214     }
9215
9216     /* Need to check for the special cases where either
9217      * the index is NaN, the length is NaN, or both
9218      * arguments are infinity (relying on Inf + -Inf = NaN)
9219      */
9220     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9221         /*
9222          * To meet the requirements of the spec, the arguments
9223          * must be converted to integer format before
9224          * initial index calculations are done
9225          *
9226          * First we go to integer form, rounding up
9227          * and checking for special cases
9228          */
9229         i = (int) in;
9230         if (((double)i)+0.5 <= in) i++;
9231
9232         if (xmlXPathIsInf(le) == 1) {
9233             l = m;
9234             if (i < 1)
9235                 i = 1;
9236         }
9237         else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9238             l = 0;
9239         else {
9240             l = (int) le;
9241             if (((double)l)+0.5 <= le) l++;
9242         }
9243
9244         /* Now we normalize inidices */
9245         i -= 1;
9246         l += i;
9247         if (i < 0)
9248             i = 0;
9249         if (l > m)
9250             l = m;
9251
9252         /* number of chars to copy */
9253         l -= i;
9254
9255         ret = xmlUTF8Strsub(str->stringval, i, l);
9256     }
9257     else {
9258         ret = NULL;
9259     }
9260     if (ret == NULL)
9261         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9262     else {
9263         valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9264         xmlFree(ret);
9265     }
9266     xmlXPathReleaseObject(ctxt->context, str);
9267 }
9268
9269 /**
9270  * xmlXPathSubstringBeforeFunction:
9271  * @ctxt:  the XPath Parser context
9272  * @nargs:  the number of arguments
9273  *
9274  * Implement the substring-before() XPath function
9275  *    string substring-before(string, string)
9276  * The substring-before function returns the substring of the first
9277  * argument string that precedes the first occurrence of the second
9278  * argument string in the first argument string, or the empty string
9279  * if the first argument string does not contain the second argument
9280  * string. For example, substring-before("1999/04/01","/") returns 1999.
9281  */
9282 void
9283 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9284   xmlXPathObjectPtr str;
9285   xmlXPathObjectPtr find;
9286   xmlBufPtr target;
9287   const xmlChar *point;
9288   int offset;
9289
9290   CHECK_ARITY(2);
9291   CAST_TO_STRING;
9292   find = valuePop(ctxt);
9293   CAST_TO_STRING;
9294   str = valuePop(ctxt);
9295
9296   target = xmlBufCreate();
9297   if (target) {
9298     point = xmlStrstr(str->stringval, find->stringval);
9299     if (point) {
9300       offset = (int)(point - str->stringval);
9301       xmlBufAdd(target, str->stringval, offset);
9302     }
9303     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9304         xmlBufContent(target)));
9305     xmlBufFree(target);
9306   }
9307   xmlXPathReleaseObject(ctxt->context, str);
9308   xmlXPathReleaseObject(ctxt->context, find);
9309 }
9310
9311 /**
9312  * xmlXPathSubstringAfterFunction:
9313  * @ctxt:  the XPath Parser context
9314  * @nargs:  the number of arguments
9315  *
9316  * Implement the substring-after() XPath function
9317  *    string substring-after(string, string)
9318  * The substring-after function returns the substring of the first
9319  * argument string that follows the first occurrence of the second
9320  * argument string in the first argument string, or the empty stringi
9321  * if the first argument string does not contain the second argument
9322  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9323  * and substring-after("1999/04/01","19") returns 99/04/01.
9324  */
9325 void
9326 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9327   xmlXPathObjectPtr str;
9328   xmlXPathObjectPtr find;
9329   xmlBufPtr target;
9330   const xmlChar *point;
9331   int offset;
9332
9333   CHECK_ARITY(2);
9334   CAST_TO_STRING;
9335   find = valuePop(ctxt);
9336   CAST_TO_STRING;
9337   str = valuePop(ctxt);
9338
9339   target = xmlBufCreate();
9340   if (target) {
9341     point = xmlStrstr(str->stringval, find->stringval);
9342     if (point) {
9343       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9344       xmlBufAdd(target, &str->stringval[offset],
9345                    xmlStrlen(str->stringval) - offset);
9346     }
9347     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9348         xmlBufContent(target)));
9349     xmlBufFree(target);
9350   }
9351   xmlXPathReleaseObject(ctxt->context, str);
9352   xmlXPathReleaseObject(ctxt->context, find);
9353 }
9354
9355 /**
9356  * xmlXPathNormalizeFunction:
9357  * @ctxt:  the XPath Parser context
9358  * @nargs:  the number of arguments
9359  *
9360  * Implement the normalize-space() XPath function
9361  *    string normalize-space(string?)
9362  * The normalize-space function returns the argument string with white
9363  * space normalized by stripping leading and trailing whitespace
9364  * and replacing sequences of whitespace characters by a single
9365  * space. Whitespace characters are the same allowed by the S production
9366  * in XML. If the argument is omitted, it defaults to the context
9367  * node converted to a string, in other words the value of the context node.
9368  */
9369 void
9370 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9371   xmlXPathObjectPtr obj = NULL;
9372   xmlChar *source = NULL;
9373   xmlBufPtr target;
9374   xmlChar blank;
9375
9376   if (ctxt == NULL) return;
9377   if (nargs == 0) {
9378     /* Use current context node */
9379       valuePush(ctxt,
9380           xmlXPathCacheWrapString(ctxt->context,
9381             xmlXPathCastNodeToString(ctxt->context->node)));
9382     nargs = 1;
9383   }
9384
9385   CHECK_ARITY(1);
9386   CAST_TO_STRING;
9387   CHECK_TYPE(XPATH_STRING);
9388   obj = valuePop(ctxt);
9389   source = obj->stringval;
9390
9391   target = xmlBufCreate();
9392   if (target && source) {
9393
9394     /* Skip leading whitespaces */
9395     while (IS_BLANK_CH(*source))
9396       source++;
9397
9398     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9399     blank = 0;
9400     while (*source) {
9401       if (IS_BLANK_CH(*source)) {
9402         blank = 0x20;
9403       } else {
9404         if (blank) {
9405           xmlBufAdd(target, &blank, 1);
9406           blank = 0;
9407         }
9408         xmlBufAdd(target, source, 1);
9409       }
9410       source++;
9411     }
9412     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9413         xmlBufContent(target)));
9414     xmlBufFree(target);
9415   }
9416   xmlXPathReleaseObject(ctxt->context, obj);
9417 }
9418
9419 /**
9420  * xmlXPathTranslateFunction:
9421  * @ctxt:  the XPath Parser context
9422  * @nargs:  the number of arguments
9423  *
9424  * Implement the translate() XPath function
9425  *    string translate(string, string, string)
9426  * The translate function returns the first argument string with
9427  * occurrences of characters in the second argument string replaced
9428  * by the character at the corresponding position in the third argument
9429  * string. For example, translate("bar","abc","ABC") returns the string
9430  * BAr. If there is a character in the second argument string with no
9431  * character at a corresponding position in the third argument string
9432  * (because the second argument string is longer than the third argument
9433  * string), then occurrences of that character in the first argument
9434  * string are removed. For example, translate("--aaa--","abc-","ABC")
9435  * returns "AAA". If a character occurs more than once in second
9436  * argument string, then the first occurrence determines the replacement
9437  * character. If the third argument string is longer than the second
9438  * argument string, then excess characters are ignored.
9439  */
9440 void
9441 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9442     xmlXPathObjectPtr str;
9443     xmlXPathObjectPtr from;
9444     xmlXPathObjectPtr to;
9445     xmlBufPtr target;
9446     int offset, max;
9447     xmlChar ch;
9448     const xmlChar *point;
9449     xmlChar *cptr;
9450
9451     CHECK_ARITY(3);
9452
9453     CAST_TO_STRING;
9454     to = valuePop(ctxt);
9455     CAST_TO_STRING;
9456     from = valuePop(ctxt);
9457     CAST_TO_STRING;
9458     str = valuePop(ctxt);
9459
9460     target = xmlBufCreate();
9461     if (target) {
9462         max = xmlUTF8Strlen(to->stringval);
9463         for (cptr = str->stringval; (ch=*cptr); ) {
9464             offset = xmlUTF8Strloc(from->stringval, cptr);
9465             if (offset >= 0) {
9466                 if (offset < max) {
9467                     point = xmlUTF8Strpos(to->stringval, offset);
9468                     if (point)
9469                         xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9470                 }
9471             } else
9472                 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9473
9474             /* Step to next character in input */
9475             cptr++;
9476             if ( ch & 0x80 ) {
9477                 /* if not simple ascii, verify proper format */
9478                 if ( (ch & 0xc0) != 0xc0 ) {
9479                     xmlGenericError(xmlGenericErrorContext,
9480                         "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9481                     /* not asserting an XPath error is probably better */
9482                     break;
9483                 }
9484                 /* then skip over remaining bytes for this char */
9485                 while ( (ch <<= 1) & 0x80 )
9486                     if ( (*cptr++ & 0xc0) != 0x80 ) {
9487                         xmlGenericError(xmlGenericErrorContext,
9488                             "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9489                         /* not asserting an XPath error is probably better */
9490                         break;
9491                     }
9492                 if (ch & 0x80) /* must have had error encountered */
9493                     break;
9494             }
9495         }
9496     }
9497     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9498         xmlBufContent(target)));
9499     xmlBufFree(target);
9500     xmlXPathReleaseObject(ctxt->context, str);
9501     xmlXPathReleaseObject(ctxt->context, from);
9502     xmlXPathReleaseObject(ctxt->context, to);
9503 }
9504
9505 /**
9506  * xmlXPathBooleanFunction:
9507  * @ctxt:  the XPath Parser context
9508  * @nargs:  the number of arguments
9509  *
9510  * Implement the boolean() XPath function
9511  *    boolean boolean(object)
9512  * The boolean function converts its argument to a boolean as follows:
9513  *    - a number is true if and only if it is neither positive or
9514  *      negative zero nor NaN
9515  *    - a node-set is true if and only if it is non-empty
9516  *    - a string is true if and only if its length is non-zero
9517  */
9518 void
9519 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9520     xmlXPathObjectPtr cur;
9521
9522     CHECK_ARITY(1);
9523     cur = valuePop(ctxt);
9524     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9525     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9526     valuePush(ctxt, cur);
9527 }
9528
9529 /**
9530  * xmlXPathNotFunction:
9531  * @ctxt:  the XPath Parser context
9532  * @nargs:  the number of arguments
9533  *
9534  * Implement the not() XPath function
9535  *    boolean not(boolean)
9536  * The not function returns true if its argument is false,
9537  * and false otherwise.
9538  */
9539 void
9540 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9541     CHECK_ARITY(1);
9542     CAST_TO_BOOLEAN;
9543     CHECK_TYPE(XPATH_BOOLEAN);
9544     ctxt->value->boolval = ! ctxt->value->boolval;
9545 }
9546
9547 /**
9548  * xmlXPathTrueFunction:
9549  * @ctxt:  the XPath Parser context
9550  * @nargs:  the number of arguments
9551  *
9552  * Implement the true() XPath function
9553  *    boolean true()
9554  */
9555 void
9556 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9557     CHECK_ARITY(0);
9558     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9559 }
9560
9561 /**
9562  * xmlXPathFalseFunction:
9563  * @ctxt:  the XPath Parser context
9564  * @nargs:  the number of arguments
9565  *
9566  * Implement the false() XPath function
9567  *    boolean false()
9568  */
9569 void
9570 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9571     CHECK_ARITY(0);
9572     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9573 }
9574
9575 /**
9576  * xmlXPathLangFunction:
9577  * @ctxt:  the XPath Parser context
9578  * @nargs:  the number of arguments
9579  *
9580  * Implement the lang() XPath function
9581  *    boolean lang(string)
9582  * The lang function returns true or false depending on whether the
9583  * language of the context node as specified by xml:lang attributes
9584  * is the same as or is a sublanguage of the language specified by
9585  * the argument string. The language of the context node is determined
9586  * by the value of the xml:lang attribute on the context node, or, if
9587  * the context node has no xml:lang attribute, by the value of the
9588  * xml:lang attribute on the nearest ancestor of the context node that
9589  * has an xml:lang attribute. If there is no such attribute, then lang
9590  * returns false. If there is such an attribute, then lang returns
9591  * true if the attribute value is equal to the argument ignoring case,
9592  * or if there is some suffix starting with - such that the attribute
9593  * value is equal to the argument ignoring that suffix of the attribute
9594  * value and ignoring case.
9595  */
9596 void
9597 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9598     xmlXPathObjectPtr val = NULL;
9599     const xmlChar *theLang = NULL;
9600     const xmlChar *lang;
9601     int ret = 0;
9602     int i;
9603
9604     CHECK_ARITY(1);
9605     CAST_TO_STRING;
9606     CHECK_TYPE(XPATH_STRING);
9607     val = valuePop(ctxt);
9608     lang = val->stringval;
9609     theLang = xmlNodeGetLang(ctxt->context->node);
9610     if ((theLang != NULL) && (lang != NULL)) {
9611         for (i = 0;lang[i] != 0;i++)
9612             if (toupper(lang[i]) != toupper(theLang[i]))
9613                 goto not_equal;
9614         if ((theLang[i] == 0) || (theLang[i] == '-'))
9615             ret = 1;
9616     }
9617 not_equal:
9618     if (theLang != NULL)
9619         xmlFree((void *)theLang);
9620
9621     xmlXPathReleaseObject(ctxt->context, val);
9622     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9623 }
9624
9625 /**
9626  * xmlXPathNumberFunction:
9627  * @ctxt:  the XPath Parser context
9628  * @nargs:  the number of arguments
9629  *
9630  * Implement the number() XPath function
9631  *    number number(object?)
9632  */
9633 void
9634 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9635     xmlXPathObjectPtr cur;
9636     double res;
9637
9638     if (ctxt == NULL) return;
9639     if (nargs == 0) {
9640         if (ctxt->context->node == NULL) {
9641             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9642         } else {
9643             xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9644
9645             res = xmlXPathStringEvalNumber(content);
9646             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9647             xmlFree(content);
9648         }
9649         return;
9650     }
9651
9652     CHECK_ARITY(1);
9653     cur = valuePop(ctxt);
9654     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9655 }
9656
9657 /**
9658  * xmlXPathSumFunction:
9659  * @ctxt:  the XPath Parser context
9660  * @nargs:  the number of arguments
9661  *
9662  * Implement the sum() XPath function
9663  *    number sum(node-set)
9664  * The sum function returns the sum of the values of the nodes in
9665  * the argument node-set.
9666  */
9667 void
9668 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9669     xmlXPathObjectPtr cur;
9670     int i;
9671     double res = 0.0;
9672
9673     CHECK_ARITY(1);
9674     if ((ctxt->value == NULL) ||
9675         ((ctxt->value->type != XPATH_NODESET) &&
9676          (ctxt->value->type != XPATH_XSLT_TREE)))
9677         XP_ERROR(XPATH_INVALID_TYPE);
9678     cur = valuePop(ctxt);
9679
9680     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9681         for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9682             res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9683         }
9684     }
9685     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9686     xmlXPathReleaseObject(ctxt->context, cur);
9687 }
9688
9689 /**
9690  * xmlXPathFloorFunction:
9691  * @ctxt:  the XPath Parser context
9692  * @nargs:  the number of arguments
9693  *
9694  * Implement the floor() XPath function
9695  *    number floor(number)
9696  * The floor function returns the largest (closest to positive infinity)
9697  * number that is not greater than the argument and that is an integer.
9698  */
9699 void
9700 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9701     CHECK_ARITY(1);
9702     CAST_TO_NUMBER;
9703     CHECK_TYPE(XPATH_NUMBER);
9704
9705     ctxt->value->floatval = floor(ctxt->value->floatval);
9706 }
9707
9708 /**
9709  * xmlXPathCeilingFunction:
9710  * @ctxt:  the XPath Parser context
9711  * @nargs:  the number of arguments
9712  *
9713  * Implement the ceiling() XPath function
9714  *    number ceiling(number)
9715  * The ceiling function returns the smallest (closest to negative infinity)
9716  * number that is not less than the argument and that is an integer.
9717  */
9718 void
9719 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9720     CHECK_ARITY(1);
9721     CAST_TO_NUMBER;
9722     CHECK_TYPE(XPATH_NUMBER);
9723
9724     ctxt->value->floatval = ceil(ctxt->value->floatval);
9725 }
9726
9727 /**
9728  * xmlXPathRoundFunction:
9729  * @ctxt:  the XPath Parser context
9730  * @nargs:  the number of arguments
9731  *
9732  * Implement the round() XPath function
9733  *    number round(number)
9734  * The round function returns the number that is closest to the
9735  * argument and that is an integer. If there are two such numbers,
9736  * then the one that is closest to positive infinity is returned.
9737  */
9738 void
9739 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9740     double f;
9741
9742     CHECK_ARITY(1);
9743     CAST_TO_NUMBER;
9744     CHECK_TYPE(XPATH_NUMBER);
9745
9746     f = ctxt->value->floatval;
9747
9748     /* Test for zero to keep negative zero unchanged. */
9749     if ((xmlXPathIsNaN(f)) || (f == 0.0))
9750         return;
9751
9752     if ((f >= -0.5) && (f < 0.0)) {
9753         /* Negative zero. */
9754         ctxt->value->floatval = xmlXPathNZERO;
9755     }
9756     else {
9757         double rounded = floor(f);
9758         if (f - rounded >= 0.5)
9759             rounded += 1.0;
9760         ctxt->value->floatval = rounded;
9761     }
9762 }
9763
9764 /************************************************************************
9765  *                                                                      *
9766  *                      The Parser                                      *
9767  *                                                                      *
9768  ************************************************************************/
9769
9770 /*
9771  * a few forward declarations since we use a recursive call based
9772  * implementation.
9773  */
9774 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9775 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9776 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9777 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9778 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9779                                           int qualified);
9780
9781 /**
9782  * xmlXPathCurrentChar:
9783  * @ctxt:  the XPath parser context
9784  * @cur:  pointer to the beginning of the char
9785  * @len:  pointer to the length of the char read
9786  *
9787  * The current char value, if using UTF-8 this may actually span multiple
9788  * bytes in the input buffer.
9789  *
9790  * Returns the current char value and its length
9791  */
9792
9793 static int
9794 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9795     unsigned char c;
9796     unsigned int val;
9797     const xmlChar *cur;
9798
9799     if (ctxt == NULL)
9800         return(0);
9801     cur = ctxt->cur;
9802
9803     /*
9804      * We are supposed to handle UTF8, check it's valid
9805      * From rfc2044: encoding of the Unicode values on UTF-8:
9806      *
9807      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9808      * 0000 0000-0000 007F   0xxxxxxx
9809      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9810      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9811      *
9812      * Check for the 0x110000 limit too
9813      */
9814     c = *cur;
9815     if (c & 0x80) {
9816         if ((cur[1] & 0xc0) != 0x80)
9817             goto encoding_error;
9818         if ((c & 0xe0) == 0xe0) {
9819
9820             if ((cur[2] & 0xc0) != 0x80)
9821                 goto encoding_error;
9822             if ((c & 0xf0) == 0xf0) {
9823                 if (((c & 0xf8) != 0xf0) ||
9824                     ((cur[3] & 0xc0) != 0x80))
9825                     goto encoding_error;
9826                 /* 4-byte code */
9827                 *len = 4;
9828                 val = (cur[0] & 0x7) << 18;
9829                 val |= (cur[1] & 0x3f) << 12;
9830                 val |= (cur[2] & 0x3f) << 6;
9831                 val |= cur[3] & 0x3f;
9832             } else {
9833               /* 3-byte code */
9834                 *len = 3;
9835                 val = (cur[0] & 0xf) << 12;
9836                 val |= (cur[1] & 0x3f) << 6;
9837                 val |= cur[2] & 0x3f;
9838             }
9839         } else {
9840           /* 2-byte code */
9841             *len = 2;
9842             val = (cur[0] & 0x1f) << 6;
9843             val |= cur[1] & 0x3f;
9844         }
9845         if (!IS_CHAR(val)) {
9846             XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9847         }
9848         return(val);
9849     } else {
9850         /* 1-byte code */
9851         *len = 1;
9852         return((int) *cur);
9853     }
9854 encoding_error:
9855     /*
9856      * If we detect an UTF8 error that probably means that the
9857      * input encoding didn't get properly advertised in the
9858      * declaration header. Report the error and switch the encoding
9859      * to ISO-Latin-1 (if you don't like this policy, just declare the
9860      * encoding !)
9861      */
9862     *len = 0;
9863     XP_ERROR0(XPATH_ENCODING_ERROR);
9864 }
9865
9866 /**
9867  * xmlXPathParseNCName:
9868  * @ctxt:  the XPath Parser context
9869  *
9870  * parse an XML namespace non qualified name.
9871  *
9872  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9873  *
9874  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9875  *                       CombiningChar | Extender
9876  *
9877  * Returns the namespace name or NULL
9878  */
9879
9880 xmlChar *
9881 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9882     const xmlChar *in;
9883     xmlChar *ret;
9884     int count = 0;
9885
9886     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9887     /*
9888      * Accelerator for simple ASCII names
9889      */
9890     in = ctxt->cur;
9891     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9892         ((*in >= 0x41) && (*in <= 0x5A)) ||
9893         (*in == '_')) {
9894         in++;
9895         while (((*in >= 0x61) && (*in <= 0x7A)) ||
9896                ((*in >= 0x41) && (*in <= 0x5A)) ||
9897                ((*in >= 0x30) && (*in <= 0x39)) ||
9898                (*in == '_') || (*in == '.') ||
9899                (*in == '-'))
9900             in++;
9901         if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9902             (*in == '[') || (*in == ']') || (*in == ':') ||
9903             (*in == '@') || (*in == '*')) {
9904             count = in - ctxt->cur;
9905             if (count == 0)
9906                 return(NULL);
9907             ret = xmlStrndup(ctxt->cur, count);
9908             ctxt->cur = in;
9909             return(ret);
9910         }
9911     }
9912     return(xmlXPathParseNameComplex(ctxt, 0));
9913 }
9914
9915
9916 /**
9917  * xmlXPathParseQName:
9918  * @ctxt:  the XPath Parser context
9919  * @prefix:  a xmlChar **
9920  *
9921  * parse an XML qualified name
9922  *
9923  * [NS 5] QName ::= (Prefix ':')? LocalPart
9924  *
9925  * [NS 6] Prefix ::= NCName
9926  *
9927  * [NS 7] LocalPart ::= NCName
9928  *
9929  * Returns the function returns the local part, and prefix is updated
9930  *   to get the Prefix if any.
9931  */
9932
9933 static xmlChar *
9934 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9935     xmlChar *ret = NULL;
9936
9937     *prefix = NULL;
9938     ret = xmlXPathParseNCName(ctxt);
9939     if (ret && CUR == ':') {
9940         *prefix = ret;
9941         NEXT;
9942         ret = xmlXPathParseNCName(ctxt);
9943     }
9944     return(ret);
9945 }
9946
9947 /**
9948  * xmlXPathParseName:
9949  * @ctxt:  the XPath Parser context
9950  *
9951  * parse an XML name
9952  *
9953  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9954  *                  CombiningChar | Extender
9955  *
9956  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9957  *
9958  * Returns the namespace name or NULL
9959  */
9960
9961 xmlChar *
9962 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9963     const xmlChar *in;
9964     xmlChar *ret;
9965     size_t count = 0;
9966
9967     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9968     /*
9969      * Accelerator for simple ASCII names
9970      */
9971     in = ctxt->cur;
9972     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9973         ((*in >= 0x41) && (*in <= 0x5A)) ||
9974         (*in == '_') || (*in == ':')) {
9975         in++;
9976         while (((*in >= 0x61) && (*in <= 0x7A)) ||
9977                ((*in >= 0x41) && (*in <= 0x5A)) ||
9978                ((*in >= 0x30) && (*in <= 0x39)) ||
9979                (*in == '_') || (*in == '-') ||
9980                (*in == ':') || (*in == '.'))
9981             in++;
9982         if ((*in > 0) && (*in < 0x80)) {
9983             count = in - ctxt->cur;
9984             if (count > XML_MAX_NAME_LENGTH) {
9985                 ctxt->cur = in;
9986                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9987             }
9988             ret = xmlStrndup(ctxt->cur, count);
9989             ctxt->cur = in;
9990             return(ret);
9991         }
9992     }
9993     return(xmlXPathParseNameComplex(ctxt, 1));
9994 }
9995
9996 static xmlChar *
9997 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9998     xmlChar buf[XML_MAX_NAMELEN + 5];
9999     int len = 0, l;
10000     int c;
10001
10002     /*
10003      * Handler for more complex cases
10004      */
10005     c = CUR_CHAR(l);
10006     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10007         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
10008         (c == '*') || /* accelerators */
10009         (!IS_LETTER(c) && (c != '_') &&
10010          ((!qualified) || (c != ':')))) {
10011         return(NULL);
10012     }
10013
10014     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10015            ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10016             (c == '.') || (c == '-') ||
10017             (c == '_') || ((qualified) && (c == ':')) ||
10018             (IS_COMBINING(c)) ||
10019             (IS_EXTENDER(c)))) {
10020         COPY_BUF(l,buf,len,c);
10021         NEXTL(l);
10022         c = CUR_CHAR(l);
10023         if (len >= XML_MAX_NAMELEN) {
10024             /*
10025              * Okay someone managed to make a huge name, so he's ready to pay
10026              * for the processing speed.
10027              */
10028             xmlChar *buffer;
10029             int max = len * 2;
10030
10031             if (len > XML_MAX_NAME_LENGTH) {
10032                 XP_ERRORNULL(XPATH_EXPR_ERROR);
10033             }
10034             buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10035             if (buffer == NULL) {
10036                 XP_ERRORNULL(XPATH_MEMORY_ERROR);
10037             }
10038             memcpy(buffer, buf, len);
10039             while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10040                    (c == '.') || (c == '-') ||
10041                    (c == '_') || ((qualified) && (c == ':')) ||
10042                    (IS_COMBINING(c)) ||
10043                    (IS_EXTENDER(c))) {
10044                 if (len + 10 > max) {
10045                     if (max > XML_MAX_NAME_LENGTH) {
10046                         XP_ERRORNULL(XPATH_EXPR_ERROR);
10047                     }
10048                     max *= 2;
10049                     buffer = (xmlChar *) xmlRealloc(buffer,
10050                                                     max * sizeof(xmlChar));
10051                     if (buffer == NULL) {
10052                         XP_ERRORNULL(XPATH_MEMORY_ERROR);
10053                     }
10054                 }
10055                 COPY_BUF(l,buffer,len,c);
10056                 NEXTL(l);
10057                 c = CUR_CHAR(l);
10058             }
10059             buffer[len] = 0;
10060             return(buffer);
10061         }
10062     }
10063     if (len == 0)
10064         return(NULL);
10065     return(xmlStrndup(buf, len));
10066 }
10067
10068 #define MAX_FRAC 20
10069
10070 /**
10071  * xmlXPathStringEvalNumber:
10072  * @str:  A string to scan
10073  *
10074  *  [30a]  Float  ::= Number ('e' Digits?)?
10075  *
10076  *  [30]   Number ::=   Digits ('.' Digits?)?
10077  *                    | '.' Digits
10078  *  [31]   Digits ::=   [0-9]+
10079  *
10080  * Compile a Number in the string
10081  * In complement of the Number expression, this function also handles
10082  * negative values : '-' Number.
10083  *
10084  * Returns the double value.
10085  */
10086 double
10087 xmlXPathStringEvalNumber(const xmlChar *str) {
10088     const xmlChar *cur = str;
10089     double ret;
10090     int ok = 0;
10091     int isneg = 0;
10092     int exponent = 0;
10093     int is_exponent_negative = 0;
10094 #ifdef __GNUC__
10095     unsigned long tmp = 0;
10096     double temp;
10097 #endif
10098     if (cur == NULL) return(0);
10099     while (IS_BLANK_CH(*cur)) cur++;
10100     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10101         return(xmlXPathNAN);
10102     }
10103     if (*cur == '-') {
10104         isneg = 1;
10105         cur++;
10106     }
10107
10108 #ifdef __GNUC__
10109     /*
10110      * tmp/temp is a workaround against a gcc compiler bug
10111      * http://veillard.com/gcc.bug
10112      */
10113     ret = 0;
10114     while ((*cur >= '0') && (*cur <= '9')) {
10115         ret = ret * 10;
10116         tmp = (*cur - '0');
10117         ok = 1;
10118         cur++;
10119         temp = (double) tmp;
10120         ret = ret + temp;
10121     }
10122 #else
10123     ret = 0;
10124     while ((*cur >= '0') && (*cur <= '9')) {
10125         ret = ret * 10 + (*cur - '0');
10126         ok = 1;
10127         cur++;
10128     }
10129 #endif
10130
10131     if (*cur == '.') {
10132         int v, frac = 0, max;
10133         double fraction = 0;
10134
10135         cur++;
10136         if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10137             return(xmlXPathNAN);
10138         }
10139         while (*cur == '0') {
10140             frac = frac + 1;
10141             cur++;
10142         }
10143         max = frac + MAX_FRAC;
10144         while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10145             v = (*cur - '0');
10146             fraction = fraction * 10 + v;
10147             frac = frac + 1;
10148             cur++;
10149         }
10150         fraction /= pow(10.0, frac);
10151         ret = ret + fraction;
10152         while ((*cur >= '0') && (*cur <= '9'))
10153             cur++;
10154     }
10155     if ((*cur == 'e') || (*cur == 'E')) {
10156       cur++;
10157       if (*cur == '-') {
10158         is_exponent_negative = 1;
10159         cur++;
10160       } else if (*cur == '+') {
10161         cur++;
10162       }
10163       while ((*cur >= '0') && (*cur <= '9')) {
10164         if (exponent < 1000000)
10165           exponent = exponent * 10 + (*cur - '0');
10166         cur++;
10167       }
10168     }
10169     while (IS_BLANK_CH(*cur)) cur++;
10170     if (*cur != 0) return(xmlXPathNAN);
10171     if (isneg) ret = -ret;
10172     if (is_exponent_negative) exponent = -exponent;
10173     ret *= pow(10.0, (double)exponent);
10174     return(ret);
10175 }
10176
10177 /**
10178  * xmlXPathCompNumber:
10179  * @ctxt:  the XPath Parser context
10180  *
10181  *  [30]   Number ::=   Digits ('.' Digits?)?
10182  *                    | '.' Digits
10183  *  [31]   Digits ::=   [0-9]+
10184  *
10185  * Compile a Number, then push it on the stack
10186  *
10187  */
10188 static void
10189 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10190 {
10191     double ret = 0.0;
10192     int ok = 0;
10193     int exponent = 0;
10194     int is_exponent_negative = 0;
10195 #ifdef __GNUC__
10196     unsigned long tmp = 0;
10197     double temp;
10198 #endif
10199
10200     CHECK_ERROR;
10201     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10202         XP_ERROR(XPATH_NUMBER_ERROR);
10203     }
10204 #ifdef __GNUC__
10205     /*
10206      * tmp/temp is a workaround against a gcc compiler bug
10207      * http://veillard.com/gcc.bug
10208      */
10209     ret = 0;
10210     while ((CUR >= '0') && (CUR <= '9')) {
10211         ret = ret * 10;
10212         tmp = (CUR - '0');
10213         ok = 1;
10214         NEXT;
10215         temp = (double) tmp;
10216         ret = ret + temp;
10217     }
10218 #else
10219     ret = 0;
10220     while ((CUR >= '0') && (CUR <= '9')) {
10221         ret = ret * 10 + (CUR - '0');
10222         ok = 1;
10223         NEXT;
10224     }
10225 #endif
10226     if (CUR == '.') {
10227         int v, frac = 0, max;
10228         double fraction = 0;
10229
10230         NEXT;
10231         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10232             XP_ERROR(XPATH_NUMBER_ERROR);
10233         }
10234         while (CUR == '0') {
10235             frac = frac + 1;
10236             NEXT;
10237         }
10238         max = frac + MAX_FRAC;
10239         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10240             v = (CUR - '0');
10241             fraction = fraction * 10 + v;
10242             frac = frac + 1;
10243             NEXT;
10244         }
10245         fraction /= pow(10.0, frac);
10246         ret = ret + fraction;
10247         while ((CUR >= '0') && (CUR <= '9'))
10248             NEXT;
10249     }
10250     if ((CUR == 'e') || (CUR == 'E')) {
10251         NEXT;
10252         if (CUR == '-') {
10253             is_exponent_negative = 1;
10254             NEXT;
10255         } else if (CUR == '+') {
10256             NEXT;
10257         }
10258         while ((CUR >= '0') && (CUR <= '9')) {
10259             if (exponent < 1000000)
10260                 exponent = exponent * 10 + (CUR - '0');
10261             NEXT;
10262         }
10263         if (is_exponent_negative)
10264             exponent = -exponent;
10265         ret *= pow(10.0, (double) exponent);
10266     }
10267     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10268                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10269 }
10270
10271 /**
10272  * xmlXPathParseLiteral:
10273  * @ctxt:  the XPath Parser context
10274  *
10275  * Parse a Literal
10276  *
10277  *  [29]   Literal ::=   '"' [^"]* '"'
10278  *                    | "'" [^']* "'"
10279  *
10280  * Returns the value found or NULL in case of error
10281  */
10282 static xmlChar *
10283 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10284     const xmlChar *q;
10285     xmlChar *ret = NULL;
10286
10287     if (CUR == '"') {
10288         NEXT;
10289         q = CUR_PTR;
10290         while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10291             NEXT;
10292         if (!IS_CHAR_CH(CUR)) {
10293             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10294         } else {
10295             ret = xmlStrndup(q, CUR_PTR - q);
10296             NEXT;
10297         }
10298     } else if (CUR == '\'') {
10299         NEXT;
10300         q = CUR_PTR;
10301         while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10302             NEXT;
10303         if (!IS_CHAR_CH(CUR)) {
10304             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10305         } else {
10306             ret = xmlStrndup(q, CUR_PTR - q);
10307             NEXT;
10308         }
10309     } else {
10310         XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10311     }
10312     return(ret);
10313 }
10314
10315 /**
10316  * xmlXPathCompLiteral:
10317  * @ctxt:  the XPath Parser context
10318  *
10319  * Parse a Literal and push it on the stack.
10320  *
10321  *  [29]   Literal ::=   '"' [^"]* '"'
10322  *                    | "'" [^']* "'"
10323  *
10324  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10325  */
10326 static void
10327 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10328     const xmlChar *q;
10329     xmlChar *ret = NULL;
10330
10331     if (CUR == '"') {
10332         NEXT;
10333         q = CUR_PTR;
10334         while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10335             NEXT;
10336         if (!IS_CHAR_CH(CUR)) {
10337             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10338         } else {
10339             ret = xmlStrndup(q, CUR_PTR - q);
10340             NEXT;
10341         }
10342     } else if (CUR == '\'') {
10343         NEXT;
10344         q = CUR_PTR;
10345         while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10346             NEXT;
10347         if (!IS_CHAR_CH(CUR)) {
10348             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10349         } else {
10350             ret = xmlStrndup(q, CUR_PTR - q);
10351             NEXT;
10352         }
10353     } else {
10354         XP_ERROR(XPATH_START_LITERAL_ERROR);
10355     }
10356     if (ret == NULL) return;
10357     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10358                    xmlXPathCacheNewString(ctxt->context, ret), NULL);
10359     xmlFree(ret);
10360 }
10361
10362 /**
10363  * xmlXPathCompVariableReference:
10364  * @ctxt:  the XPath Parser context
10365  *
10366  * Parse a VariableReference, evaluate it and push it on the stack.
10367  *
10368  * The variable bindings consist of a mapping from variable names
10369  * to variable values. The value of a variable is an object, which can be
10370  * of any of the types that are possible for the value of an expression,
10371  * and may also be of additional types not specified here.
10372  *
10373  * Early evaluation is possible since:
10374  * The variable bindings [...] used to evaluate a subexpression are
10375  * always the same as those used to evaluate the containing expression.
10376  *
10377  *  [36]   VariableReference ::=   '$' QName
10378  */
10379 static void
10380 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10381     xmlChar *name;
10382     xmlChar *prefix;
10383
10384     SKIP_BLANKS;
10385     if (CUR != '$') {
10386         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10387     }
10388     NEXT;
10389     name = xmlXPathParseQName(ctxt, &prefix);
10390     if (name == NULL) {
10391         xmlFree(prefix);
10392         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10393     }
10394     ctxt->comp->last = -1;
10395     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10396                    name, prefix);
10397     SKIP_BLANKS;
10398     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10399         XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10400     }
10401 }
10402
10403 /**
10404  * xmlXPathIsNodeType:
10405  * @name:  a name string
10406  *
10407  * Is the name given a NodeType one.
10408  *
10409  *  [38]   NodeType ::=   'comment'
10410  *                    | 'text'
10411  *                    | 'processing-instruction'
10412  *                    | 'node'
10413  *
10414  * Returns 1 if true 0 otherwise
10415  */
10416 int
10417 xmlXPathIsNodeType(const xmlChar *name) {
10418     if (name == NULL)
10419         return(0);
10420
10421     if (xmlStrEqual(name, BAD_CAST "node"))
10422         return(1);
10423     if (xmlStrEqual(name, BAD_CAST "text"))
10424         return(1);
10425     if (xmlStrEqual(name, BAD_CAST "comment"))
10426         return(1);
10427     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10428         return(1);
10429     return(0);
10430 }
10431
10432 /**
10433  * xmlXPathCompFunctionCall:
10434  * @ctxt:  the XPath Parser context
10435  *
10436  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10437  *  [17]   Argument ::=   Expr
10438  *
10439  * Compile a function call, the evaluation of all arguments are
10440  * pushed on the stack
10441  */
10442 static void
10443 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10444     xmlChar *name;
10445     xmlChar *prefix;
10446     int nbargs = 0;
10447     int sort = 1;
10448
10449     name = xmlXPathParseQName(ctxt, &prefix);
10450     if (name == NULL) {
10451         xmlFree(prefix);
10452         XP_ERROR(XPATH_EXPR_ERROR);
10453     }
10454     SKIP_BLANKS;
10455 #ifdef DEBUG_EXPR
10456     if (prefix == NULL)
10457         xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10458                         name);
10459     else
10460         xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10461                         prefix, name);
10462 #endif
10463
10464     if (CUR != '(') {
10465         xmlFree(name);
10466         xmlFree(prefix);
10467         XP_ERROR(XPATH_EXPR_ERROR);
10468     }
10469     NEXT;
10470     SKIP_BLANKS;
10471
10472     /*
10473     * Optimization for count(): we don't need the node-set to be sorted.
10474     */
10475     if ((prefix == NULL) && (name[0] == 'c') &&
10476         xmlStrEqual(name, BAD_CAST "count"))
10477     {
10478         sort = 0;
10479     }
10480     ctxt->comp->last = -1;
10481     if (CUR != ')') {
10482         while (CUR != 0) {
10483             int op1 = ctxt->comp->last;
10484             ctxt->comp->last = -1;
10485             xmlXPathCompileExpr(ctxt, sort);
10486             if (ctxt->error != XPATH_EXPRESSION_OK) {
10487                 xmlFree(name);
10488                 xmlFree(prefix);
10489                 return;
10490             }
10491             PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10492             nbargs++;
10493             if (CUR == ')') break;
10494             if (CUR != ',') {
10495                 xmlFree(name);
10496                 xmlFree(prefix);
10497                 XP_ERROR(XPATH_EXPR_ERROR);
10498             }
10499             NEXT;
10500             SKIP_BLANKS;
10501         }
10502     }
10503     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10504                    name, prefix);
10505     NEXT;
10506     SKIP_BLANKS;
10507 }
10508
10509 /**
10510  * xmlXPathCompPrimaryExpr:
10511  * @ctxt:  the XPath Parser context
10512  *
10513  *  [15]   PrimaryExpr ::=   VariableReference
10514  *                | '(' Expr ')'
10515  *                | Literal
10516  *                | Number
10517  *                | FunctionCall
10518  *
10519  * Compile a primary expression.
10520  */
10521 static void
10522 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10523     SKIP_BLANKS;
10524     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10525     else if (CUR == '(') {
10526         NEXT;
10527         SKIP_BLANKS;
10528         xmlXPathCompileExpr(ctxt, 1);
10529         CHECK_ERROR;
10530         if (CUR != ')') {
10531             XP_ERROR(XPATH_EXPR_ERROR);
10532         }
10533         NEXT;
10534         SKIP_BLANKS;
10535     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10536         xmlXPathCompNumber(ctxt);
10537     } else if ((CUR == '\'') || (CUR == '"')) {
10538         xmlXPathCompLiteral(ctxt);
10539     } else {
10540         xmlXPathCompFunctionCall(ctxt);
10541     }
10542     SKIP_BLANKS;
10543 }
10544
10545 /**
10546  * xmlXPathCompFilterExpr:
10547  * @ctxt:  the XPath Parser context
10548  *
10549  *  [20]   FilterExpr ::=   PrimaryExpr
10550  *               | FilterExpr Predicate
10551  *
10552  * Compile a filter expression.
10553  * Square brackets are used to filter expressions in the same way that
10554  * they are used in location paths. It is an error if the expression to
10555  * be filtered does not evaluate to a node-set. The context node list
10556  * used for evaluating the expression in square brackets is the node-set
10557  * to be filtered listed in document order.
10558  */
10559
10560 static void
10561 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10562     xmlXPathCompPrimaryExpr(ctxt);
10563     CHECK_ERROR;
10564     SKIP_BLANKS;
10565
10566     while (CUR == '[') {
10567         xmlXPathCompPredicate(ctxt, 1);
10568         SKIP_BLANKS;
10569     }
10570
10571
10572 }
10573
10574 /**
10575  * xmlXPathScanName:
10576  * @ctxt:  the XPath Parser context
10577  *
10578  * Trickery: parse an XML name but without consuming the input flow
10579  * Needed to avoid insanity in the parser state.
10580  *
10581  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10582  *                  CombiningChar | Extender
10583  *
10584  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10585  *
10586  * [6] Names ::= Name (S Name)*
10587  *
10588  * Returns the Name parsed or NULL
10589  */
10590
10591 static xmlChar *
10592 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10593     int len = 0, l;
10594     int c;
10595     const xmlChar *cur;
10596     xmlChar *ret;
10597
10598     cur = ctxt->cur;
10599
10600     c = CUR_CHAR(l);
10601     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10602         (!IS_LETTER(c) && (c != '_') &&
10603          (c != ':'))) {
10604         return(NULL);
10605     }
10606
10607     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10608            ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10609             (c == '.') || (c == '-') ||
10610             (c == '_') || (c == ':') ||
10611             (IS_COMBINING(c)) ||
10612             (IS_EXTENDER(c)))) {
10613         len += l;
10614         NEXTL(l);
10615         c = CUR_CHAR(l);
10616     }
10617     ret = xmlStrndup(cur, ctxt->cur - cur);
10618     ctxt->cur = cur;
10619     return(ret);
10620 }
10621
10622 /**
10623  * xmlXPathCompPathExpr:
10624  * @ctxt:  the XPath Parser context
10625  *
10626  *  [19]   PathExpr ::=   LocationPath
10627  *               | FilterExpr
10628  *               | FilterExpr '/' RelativeLocationPath
10629  *               | FilterExpr '//' RelativeLocationPath
10630  *
10631  * Compile a path expression.
10632  * The / operator and // operators combine an arbitrary expression
10633  * and a relative location path. It is an error if the expression
10634  * does not evaluate to a node-set.
10635  * The / operator does composition in the same way as when / is
10636  * used in a location path. As in location paths, // is short for
10637  * /descendant-or-self::node()/.
10638  */
10639
10640 static void
10641 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10642     int lc = 1;           /* Should we branch to LocationPath ?         */
10643     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10644
10645     SKIP_BLANKS;
10646     if ((CUR == '$') || (CUR == '(') ||
10647         (IS_ASCII_DIGIT(CUR)) ||
10648         (CUR == '\'') || (CUR == '"') ||
10649         (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10650         lc = 0;
10651     } else if (CUR == '*') {
10652         /* relative or absolute location path */
10653         lc = 1;
10654     } else if (CUR == '/') {
10655         /* relative or absolute location path */
10656         lc = 1;
10657     } else if (CUR == '@') {
10658         /* relative abbreviated attribute location path */
10659         lc = 1;
10660     } else if (CUR == '.') {
10661         /* relative abbreviated attribute location path */
10662         lc = 1;
10663     } else {
10664         /*
10665          * Problem is finding if we have a name here whether it's:
10666          *   - a nodetype
10667          *   - a function call in which case it's followed by '('
10668          *   - an axis in which case it's followed by ':'
10669          *   - a element name
10670          * We do an a priori analysis here rather than having to
10671          * maintain parsed token content through the recursive function
10672          * calls. This looks uglier but makes the code easier to
10673          * read/write/debug.
10674          */
10675         SKIP_BLANKS;
10676         name = xmlXPathScanName(ctxt);
10677         if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10678 #ifdef DEBUG_STEP
10679             xmlGenericError(xmlGenericErrorContext,
10680                     "PathExpr: Axis\n");
10681 #endif
10682             lc = 1;
10683             xmlFree(name);
10684         } else if (name != NULL) {
10685             int len =xmlStrlen(name);
10686
10687
10688             while (NXT(len) != 0) {
10689                 if (NXT(len) == '/') {
10690                     /* element name */
10691 #ifdef DEBUG_STEP
10692                     xmlGenericError(xmlGenericErrorContext,
10693                             "PathExpr: AbbrRelLocation\n");
10694 #endif
10695                     lc = 1;
10696                     break;
10697                 } else if (IS_BLANK_CH(NXT(len))) {
10698                     /* ignore blanks */
10699                     ;
10700                 } else if (NXT(len) == ':') {
10701 #ifdef DEBUG_STEP
10702                     xmlGenericError(xmlGenericErrorContext,
10703                             "PathExpr: AbbrRelLocation\n");
10704 #endif
10705                     lc = 1;
10706                     break;
10707                 } else if ((NXT(len) == '(')) {
10708                     /* Node Type or Function */
10709                     if (xmlXPathIsNodeType(name)) {
10710 #ifdef DEBUG_STEP
10711                         xmlGenericError(xmlGenericErrorContext,
10712                                 "PathExpr: Type search\n");
10713 #endif
10714                         lc = 1;
10715 #ifdef LIBXML_XPTR_ENABLED
10716                     } else if (ctxt->xptr &&
10717                                xmlStrEqual(name, BAD_CAST "range-to")) {
10718                         lc = 1;
10719 #endif
10720                     } else {
10721 #ifdef DEBUG_STEP
10722                         xmlGenericError(xmlGenericErrorContext,
10723                                 "PathExpr: function call\n");
10724 #endif
10725                         lc = 0;
10726                     }
10727                     break;
10728                 } else if ((NXT(len) == '[')) {
10729                     /* element name */
10730 #ifdef DEBUG_STEP
10731                     xmlGenericError(xmlGenericErrorContext,
10732                             "PathExpr: AbbrRelLocation\n");
10733 #endif
10734                     lc = 1;
10735                     break;
10736                 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10737                            (NXT(len) == '=')) {
10738                     lc = 1;
10739                     break;
10740                 } else {
10741                     lc = 1;
10742                     break;
10743                 }
10744                 len++;
10745             }
10746             if (NXT(len) == 0) {
10747 #ifdef DEBUG_STEP
10748                 xmlGenericError(xmlGenericErrorContext,
10749                         "PathExpr: AbbrRelLocation\n");
10750 #endif
10751                 /* element name */
10752                 lc = 1;
10753             }
10754             xmlFree(name);
10755         } else {
10756             /* make sure all cases are covered explicitly */
10757             XP_ERROR(XPATH_EXPR_ERROR);
10758         }
10759     }
10760
10761     if (lc) {
10762         if (CUR == '/') {
10763             PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10764         } else {
10765             PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10766         }
10767         xmlXPathCompLocationPath(ctxt);
10768     } else {
10769         xmlXPathCompFilterExpr(ctxt);
10770         CHECK_ERROR;
10771         if ((CUR == '/') && (NXT(1) == '/')) {
10772             SKIP(2);
10773             SKIP_BLANKS;
10774
10775             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10776                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10777             PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10778
10779             xmlXPathCompRelativeLocationPath(ctxt);
10780         } else if (CUR == '/') {
10781             xmlXPathCompRelativeLocationPath(ctxt);
10782         }
10783     }
10784     SKIP_BLANKS;
10785 }
10786
10787 /**
10788  * xmlXPathCompUnionExpr:
10789  * @ctxt:  the XPath Parser context
10790  *
10791  *  [18]   UnionExpr ::=   PathExpr
10792  *               | UnionExpr '|' PathExpr
10793  *
10794  * Compile an union expression.
10795  */
10796
10797 static void
10798 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10799     xmlXPathCompPathExpr(ctxt);
10800     CHECK_ERROR;
10801     SKIP_BLANKS;
10802     while (CUR == '|') {
10803         int op1 = ctxt->comp->last;
10804         PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10805
10806         NEXT;
10807         SKIP_BLANKS;
10808         xmlXPathCompPathExpr(ctxt);
10809
10810         PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10811
10812         SKIP_BLANKS;
10813     }
10814 }
10815
10816 /**
10817  * xmlXPathCompUnaryExpr:
10818  * @ctxt:  the XPath Parser context
10819  *
10820  *  [27]   UnaryExpr ::=   UnionExpr
10821  *                   | '-' UnaryExpr
10822  *
10823  * Compile an unary expression.
10824  */
10825
10826 static void
10827 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10828     int minus = 0;
10829     int found = 0;
10830
10831     SKIP_BLANKS;
10832     while (CUR == '-') {
10833         minus = 1 - minus;
10834         found = 1;
10835         NEXT;
10836         SKIP_BLANKS;
10837     }
10838
10839     xmlXPathCompUnionExpr(ctxt);
10840     CHECK_ERROR;
10841     if (found) {
10842         if (minus)
10843             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10844         else
10845             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10846     }
10847 }
10848
10849 /**
10850  * xmlXPathCompMultiplicativeExpr:
10851  * @ctxt:  the XPath Parser context
10852  *
10853  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10854  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10855  *                   | MultiplicativeExpr 'div' UnaryExpr
10856  *                   | MultiplicativeExpr 'mod' UnaryExpr
10857  *  [34]   MultiplyOperator ::=   '*'
10858  *
10859  * Compile an Additive expression.
10860  */
10861
10862 static void
10863 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10864     xmlXPathCompUnaryExpr(ctxt);
10865     CHECK_ERROR;
10866     SKIP_BLANKS;
10867     while ((CUR == '*') ||
10868            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10869            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10870         int op = -1;
10871         int op1 = ctxt->comp->last;
10872
10873         if (CUR == '*') {
10874             op = 0;
10875             NEXT;
10876         } else if (CUR == 'd') {
10877             op = 1;
10878             SKIP(3);
10879         } else if (CUR == 'm') {
10880             op = 2;
10881             SKIP(3);
10882         }
10883         SKIP_BLANKS;
10884         xmlXPathCompUnaryExpr(ctxt);
10885         CHECK_ERROR;
10886         PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10887         SKIP_BLANKS;
10888     }
10889 }
10890
10891 /**
10892  * xmlXPathCompAdditiveExpr:
10893  * @ctxt:  the XPath Parser context
10894  *
10895  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10896  *                   | AdditiveExpr '+' MultiplicativeExpr
10897  *                   | AdditiveExpr '-' MultiplicativeExpr
10898  *
10899  * Compile an Additive expression.
10900  */
10901
10902 static void
10903 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10904
10905     xmlXPathCompMultiplicativeExpr(ctxt);
10906     CHECK_ERROR;
10907     SKIP_BLANKS;
10908     while ((CUR == '+') || (CUR == '-')) {
10909         int plus;
10910         int op1 = ctxt->comp->last;
10911
10912         if (CUR == '+') plus = 1;
10913         else plus = 0;
10914         NEXT;
10915         SKIP_BLANKS;
10916         xmlXPathCompMultiplicativeExpr(ctxt);
10917         CHECK_ERROR;
10918         PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10919         SKIP_BLANKS;
10920     }
10921 }
10922
10923 /**
10924  * xmlXPathCompRelationalExpr:
10925  * @ctxt:  the XPath Parser context
10926  *
10927  *  [24]   RelationalExpr ::=   AdditiveExpr
10928  *                 | RelationalExpr '<' AdditiveExpr
10929  *                 | RelationalExpr '>' AdditiveExpr
10930  *                 | RelationalExpr '<=' AdditiveExpr
10931  *                 | RelationalExpr '>=' AdditiveExpr
10932  *
10933  *  A <= B > C is allowed ? Answer from James, yes with
10934  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10935  *  which is basically what got implemented.
10936  *
10937  * Compile a Relational expression, then push the result
10938  * on the stack
10939  */
10940
10941 static void
10942 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10943     xmlXPathCompAdditiveExpr(ctxt);
10944     CHECK_ERROR;
10945     SKIP_BLANKS;
10946     while ((CUR == '<') ||
10947            (CUR == '>') ||
10948            ((CUR == '<') && (NXT(1) == '=')) ||
10949            ((CUR == '>') && (NXT(1) == '='))) {
10950         int inf, strict;
10951         int op1 = ctxt->comp->last;
10952
10953         if (CUR == '<') inf = 1;
10954         else inf = 0;
10955         if (NXT(1) == '=') strict = 0;
10956         else strict = 1;
10957         NEXT;
10958         if (!strict) NEXT;
10959         SKIP_BLANKS;
10960         xmlXPathCompAdditiveExpr(ctxt);
10961         CHECK_ERROR;
10962         PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10963         SKIP_BLANKS;
10964     }
10965 }
10966
10967 /**
10968  * xmlXPathCompEqualityExpr:
10969  * @ctxt:  the XPath Parser context
10970  *
10971  *  [23]   EqualityExpr ::=   RelationalExpr
10972  *                 | EqualityExpr '=' RelationalExpr
10973  *                 | EqualityExpr '!=' RelationalExpr
10974  *
10975  *  A != B != C is allowed ? Answer from James, yes with
10976  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10977  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10978  *  which is basically what got implemented.
10979  *
10980  * Compile an Equality expression.
10981  *
10982  */
10983 static void
10984 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10985     xmlXPathCompRelationalExpr(ctxt);
10986     CHECK_ERROR;
10987     SKIP_BLANKS;
10988     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10989         int eq;
10990         int op1 = ctxt->comp->last;
10991
10992         if (CUR == '=') eq = 1;
10993         else eq = 0;
10994         NEXT;
10995         if (!eq) NEXT;
10996         SKIP_BLANKS;
10997         xmlXPathCompRelationalExpr(ctxt);
10998         CHECK_ERROR;
10999         PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
11000         SKIP_BLANKS;
11001     }
11002 }
11003
11004 /**
11005  * xmlXPathCompAndExpr:
11006  * @ctxt:  the XPath Parser context
11007  *
11008  *  [22]   AndExpr ::=   EqualityExpr
11009  *                 | AndExpr 'and' EqualityExpr
11010  *
11011  * Compile an AND expression.
11012  *
11013  */
11014 static void
11015 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
11016     xmlXPathCompEqualityExpr(ctxt);
11017     CHECK_ERROR;
11018     SKIP_BLANKS;
11019     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
11020         int op1 = ctxt->comp->last;
11021         SKIP(3);
11022         SKIP_BLANKS;
11023         xmlXPathCompEqualityExpr(ctxt);
11024         CHECK_ERROR;
11025         PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11026         SKIP_BLANKS;
11027     }
11028 }
11029
11030 /**
11031  * xmlXPathCompileExpr:
11032  * @ctxt:  the XPath Parser context
11033  *
11034  *  [14]   Expr ::=   OrExpr
11035  *  [21]   OrExpr ::=   AndExpr
11036  *                 | OrExpr 'or' AndExpr
11037  *
11038  * Parse and compile an expression
11039  */
11040 static void
11041 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11042     xmlXPathCompAndExpr(ctxt);
11043     CHECK_ERROR;
11044     SKIP_BLANKS;
11045     while ((CUR == 'o') && (NXT(1) == 'r')) {
11046         int op1 = ctxt->comp->last;
11047         SKIP(2);
11048         SKIP_BLANKS;
11049         xmlXPathCompAndExpr(ctxt);
11050         CHECK_ERROR;
11051         PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11052         SKIP_BLANKS;
11053     }
11054     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11055         /* more ops could be optimized too */
11056         /*
11057         * This is the main place to eliminate sorting for
11058         * operations which don't require a sorted node-set.
11059         * E.g. count().
11060         */
11061         PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11062     }
11063 }
11064
11065 /**
11066  * xmlXPathCompPredicate:
11067  * @ctxt:  the XPath Parser context
11068  * @filter:  act as a filter
11069  *
11070  *  [8]   Predicate ::=   '[' PredicateExpr ']'
11071  *  [9]   PredicateExpr ::=   Expr
11072  *
11073  * Compile a predicate expression
11074  */
11075 static void
11076 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11077     int op1 = ctxt->comp->last;
11078
11079     SKIP_BLANKS;
11080     if (CUR != '[') {
11081         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11082     }
11083     NEXT;
11084     SKIP_BLANKS;
11085
11086     ctxt->comp->last = -1;
11087     /*
11088     * This call to xmlXPathCompileExpr() will deactivate sorting
11089     * of the predicate result.
11090     * TODO: Sorting is still activated for filters, since I'm not
11091     *  sure if needed. Normally sorting should not be needed, since
11092     *  a filter can only diminish the number of items in a sequence,
11093     *  but won't change its order; so if the initial sequence is sorted,
11094     *  subsequent sorting is not needed.
11095     */
11096     if (! filter)
11097         xmlXPathCompileExpr(ctxt, 0);
11098     else
11099         xmlXPathCompileExpr(ctxt, 1);
11100     CHECK_ERROR;
11101
11102     if (CUR != ']') {
11103         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11104     }
11105
11106     if (filter)
11107         PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11108     else
11109         PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11110
11111     NEXT;
11112     SKIP_BLANKS;
11113 }
11114
11115 /**
11116  * xmlXPathCompNodeTest:
11117  * @ctxt:  the XPath Parser context
11118  * @test:  pointer to a xmlXPathTestVal
11119  * @type:  pointer to a xmlXPathTypeVal
11120  * @prefix:  placeholder for a possible name prefix
11121  *
11122  * [7] NodeTest ::=   NameTest
11123  *                  | NodeType '(' ')'
11124  *                  | 'processing-instruction' '(' Literal ')'
11125  *
11126  * [37] NameTest ::=  '*'
11127  *                  | NCName ':' '*'
11128  *                  | QName
11129  * [38] NodeType ::= 'comment'
11130  *                 | 'text'
11131  *                 | 'processing-instruction'
11132  *                 | 'node'
11133  *
11134  * Returns the name found and updates @test, @type and @prefix appropriately
11135  */
11136 static xmlChar *
11137 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11138                      xmlXPathTypeVal *type, const xmlChar **prefix,
11139                      xmlChar *name) {
11140     int blanks;
11141
11142     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11143         STRANGE;
11144         return(NULL);
11145     }
11146     *type = (xmlXPathTypeVal) 0;
11147     *test = (xmlXPathTestVal) 0;
11148     *prefix = NULL;
11149     SKIP_BLANKS;
11150
11151     if ((name == NULL) && (CUR == '*')) {
11152         /*
11153          * All elements
11154          */
11155         NEXT;
11156         *test = NODE_TEST_ALL;
11157         return(NULL);
11158     }
11159
11160     if (name == NULL)
11161         name = xmlXPathParseNCName(ctxt);
11162     if (name == NULL) {
11163         XP_ERRORNULL(XPATH_EXPR_ERROR);
11164     }
11165
11166     blanks = IS_BLANK_CH(CUR);
11167     SKIP_BLANKS;
11168     if (CUR == '(') {
11169         NEXT;
11170         /*
11171          * NodeType or PI search
11172          */
11173         if (xmlStrEqual(name, BAD_CAST "comment"))
11174             *type = NODE_TYPE_COMMENT;
11175         else if (xmlStrEqual(name, BAD_CAST "node"))
11176             *type = NODE_TYPE_NODE;
11177         else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11178             *type = NODE_TYPE_PI;
11179         else if (xmlStrEqual(name, BAD_CAST "text"))
11180             *type = NODE_TYPE_TEXT;
11181         else {
11182             if (name != NULL)
11183                 xmlFree(name);
11184             XP_ERRORNULL(XPATH_EXPR_ERROR);
11185         }
11186
11187         *test = NODE_TEST_TYPE;
11188
11189         SKIP_BLANKS;
11190         if (*type == NODE_TYPE_PI) {
11191             /*
11192              * Specific case: search a PI by name.
11193              */
11194             if (name != NULL)
11195                 xmlFree(name);
11196             name = NULL;
11197             if (CUR != ')') {
11198                 name = xmlXPathParseLiteral(ctxt);
11199                 CHECK_ERROR NULL;
11200                 *test = NODE_TEST_PI;
11201                 SKIP_BLANKS;
11202             }
11203         }
11204         if (CUR != ')') {
11205             if (name != NULL)
11206                 xmlFree(name);
11207             XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11208         }
11209         NEXT;
11210         return(name);
11211     }
11212     *test = NODE_TEST_NAME;
11213     if ((!blanks) && (CUR == ':')) {
11214         NEXT;
11215
11216         /*
11217          * Since currently the parser context don't have a
11218          * namespace list associated:
11219          * The namespace name for this prefix can be computed
11220          * only at evaluation time. The compilation is done
11221          * outside of any context.
11222          */
11223 #if 0
11224         *prefix = xmlXPathNsLookup(ctxt->context, name);
11225         if (name != NULL)
11226             xmlFree(name);
11227         if (*prefix == NULL) {
11228             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11229         }
11230 #else
11231         *prefix = name;
11232 #endif
11233
11234         if (CUR == '*') {
11235             /*
11236              * All elements
11237              */
11238             NEXT;
11239             *test = NODE_TEST_ALL;
11240             return(NULL);
11241         }
11242
11243         name = xmlXPathParseNCName(ctxt);
11244         if (name == NULL) {
11245             XP_ERRORNULL(XPATH_EXPR_ERROR);
11246         }
11247     }
11248     return(name);
11249 }
11250
11251 /**
11252  * xmlXPathIsAxisName:
11253  * @name:  a preparsed name token
11254  *
11255  * [6] AxisName ::=   'ancestor'
11256  *                  | 'ancestor-or-self'
11257  *                  | 'attribute'
11258  *                  | 'child'
11259  *                  | 'descendant'
11260  *                  | 'descendant-or-self'
11261  *                  | 'following'
11262  *                  | 'following-sibling'
11263  *                  | 'namespace'
11264  *                  | 'parent'
11265  *                  | 'preceding'
11266  *                  | 'preceding-sibling'
11267  *                  | 'self'
11268  *
11269  * Returns the axis or 0
11270  */
11271 static xmlXPathAxisVal
11272 xmlXPathIsAxisName(const xmlChar *name) {
11273     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11274     switch (name[0]) {
11275         case 'a':
11276             if (xmlStrEqual(name, BAD_CAST "ancestor"))
11277                 ret = AXIS_ANCESTOR;
11278             if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11279                 ret = AXIS_ANCESTOR_OR_SELF;
11280             if (xmlStrEqual(name, BAD_CAST "attribute"))
11281                 ret = AXIS_ATTRIBUTE;
11282             break;
11283         case 'c':
11284             if (xmlStrEqual(name, BAD_CAST "child"))
11285                 ret = AXIS_CHILD;
11286             break;
11287         case 'd':
11288             if (xmlStrEqual(name, BAD_CAST "descendant"))
11289                 ret = AXIS_DESCENDANT;
11290             if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11291                 ret = AXIS_DESCENDANT_OR_SELF;
11292             break;
11293         case 'f':
11294             if (xmlStrEqual(name, BAD_CAST "following"))
11295                 ret = AXIS_FOLLOWING;
11296             if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11297                 ret = AXIS_FOLLOWING_SIBLING;
11298             break;
11299         case 'n':
11300             if (xmlStrEqual(name, BAD_CAST "namespace"))
11301                 ret = AXIS_NAMESPACE;
11302             break;
11303         case 'p':
11304             if (xmlStrEqual(name, BAD_CAST "parent"))
11305                 ret = AXIS_PARENT;
11306             if (xmlStrEqual(name, BAD_CAST "preceding"))
11307                 ret = AXIS_PRECEDING;
11308             if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11309                 ret = AXIS_PRECEDING_SIBLING;
11310             break;
11311         case 's':
11312             if (xmlStrEqual(name, BAD_CAST "self"))
11313                 ret = AXIS_SELF;
11314             break;
11315     }
11316     return(ret);
11317 }
11318
11319 /**
11320  * xmlXPathCompStep:
11321  * @ctxt:  the XPath Parser context
11322  *
11323  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11324  *                  | AbbreviatedStep
11325  *
11326  * [12] AbbreviatedStep ::=   '.' | '..'
11327  *
11328  * [5] AxisSpecifier ::= AxisName '::'
11329  *                  | AbbreviatedAxisSpecifier
11330  *
11331  * [13] AbbreviatedAxisSpecifier ::= '@'?
11332  *
11333  * Modified for XPtr range support as:
11334  *
11335  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11336  *                     | AbbreviatedStep
11337  *                     | 'range-to' '(' Expr ')' Predicate*
11338  *
11339  * Compile one step in a Location Path
11340  * A location step of . is short for self::node(). This is
11341  * particularly useful in conjunction with //. For example, the
11342  * location path .//para is short for
11343  * self::node()/descendant-or-self::node()/child::para
11344  * and so will select all para descendant elements of the context
11345  * node.
11346  * Similarly, a location step of .. is short for parent::node().
11347  * For example, ../title is short for parent::node()/child::title
11348  * and so will select the title children of the parent of the context
11349  * node.
11350  */
11351 static void
11352 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11353 #ifdef LIBXML_XPTR_ENABLED
11354     int rangeto = 0;
11355     int op2 = -1;
11356 #endif
11357
11358     SKIP_BLANKS;
11359     if ((CUR == '.') && (NXT(1) == '.')) {
11360         SKIP(2);
11361         SKIP_BLANKS;
11362         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11363                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11364     } else if (CUR == '.') {
11365         NEXT;
11366         SKIP_BLANKS;
11367     } else {
11368         xmlChar *name = NULL;
11369         const xmlChar *prefix = NULL;
11370         xmlXPathTestVal test = (xmlXPathTestVal) 0;
11371         xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11372         xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11373         int op1;
11374
11375         /*
11376          * The modification needed for XPointer change to the production
11377          */
11378 #ifdef LIBXML_XPTR_ENABLED
11379         if (ctxt->xptr) {
11380             name = xmlXPathParseNCName(ctxt);
11381             if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11382                 op2 = ctxt->comp->last;
11383                 xmlFree(name);
11384                 SKIP_BLANKS;
11385                 if (CUR != '(') {
11386                     XP_ERROR(XPATH_EXPR_ERROR);
11387                 }
11388                 NEXT;
11389                 SKIP_BLANKS;
11390
11391                 xmlXPathCompileExpr(ctxt, 1);
11392                 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11393                 CHECK_ERROR;
11394
11395                 SKIP_BLANKS;
11396                 if (CUR != ')') {
11397                     XP_ERROR(XPATH_EXPR_ERROR);
11398                 }
11399                 NEXT;
11400                 rangeto = 1;
11401                 goto eval_predicates;
11402             }
11403         }
11404 #endif
11405         if (CUR == '*') {
11406             axis = AXIS_CHILD;
11407         } else {
11408             if (name == NULL)
11409                 name = xmlXPathParseNCName(ctxt);
11410             if (name != NULL) {
11411                 axis = xmlXPathIsAxisName(name);
11412                 if (axis != 0) {
11413                     SKIP_BLANKS;
11414                     if ((CUR == ':') && (NXT(1) == ':')) {
11415                         SKIP(2);
11416                         xmlFree(name);
11417                         name = NULL;
11418                     } else {
11419                         /* an element name can conflict with an axis one :-\ */
11420                         axis = AXIS_CHILD;
11421                     }
11422                 } else {
11423                     axis = AXIS_CHILD;
11424                 }
11425             } else if (CUR == '@') {
11426                 NEXT;
11427                 axis = AXIS_ATTRIBUTE;
11428             } else {
11429                 axis = AXIS_CHILD;
11430             }
11431         }
11432
11433         if (ctxt->error != XPATH_EXPRESSION_OK) {
11434             xmlFree(name);
11435             return;
11436         }
11437
11438         name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11439         if (test == 0)
11440             return;
11441
11442         if ((prefix != NULL) && (ctxt->context != NULL) &&
11443             (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11444             if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11445                 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11446             }
11447         }
11448 #ifdef DEBUG_STEP
11449         xmlGenericError(xmlGenericErrorContext,
11450                 "Basis : computing new set\n");
11451 #endif
11452
11453 #ifdef DEBUG_STEP
11454         xmlGenericError(xmlGenericErrorContext, "Basis : ");
11455         if (ctxt->value == NULL)
11456             xmlGenericError(xmlGenericErrorContext, "no value\n");
11457         else if (ctxt->value->nodesetval == NULL)
11458             xmlGenericError(xmlGenericErrorContext, "Empty\n");
11459         else
11460             xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11461 #endif
11462
11463 #ifdef LIBXML_XPTR_ENABLED
11464 eval_predicates:
11465 #endif
11466         op1 = ctxt->comp->last;
11467         ctxt->comp->last = -1;
11468
11469         SKIP_BLANKS;
11470         while (CUR == '[') {
11471             xmlXPathCompPredicate(ctxt, 0);
11472         }
11473
11474 #ifdef LIBXML_XPTR_ENABLED
11475         if (rangeto) {
11476             PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11477         } else
11478 #endif
11479             PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11480                            test, type, (void *)prefix, (void *)name);
11481
11482     }
11483 #ifdef DEBUG_STEP
11484     xmlGenericError(xmlGenericErrorContext, "Step : ");
11485     if (ctxt->value == NULL)
11486         xmlGenericError(xmlGenericErrorContext, "no value\n");
11487     else if (ctxt->value->nodesetval == NULL)
11488         xmlGenericError(xmlGenericErrorContext, "Empty\n");
11489     else
11490         xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11491                 ctxt->value->nodesetval);
11492 #endif
11493 }
11494
11495 /**
11496  * xmlXPathCompRelativeLocationPath:
11497  * @ctxt:  the XPath Parser context
11498  *
11499  *  [3]   RelativeLocationPath ::=   Step
11500  *                     | RelativeLocationPath '/' Step
11501  *                     | AbbreviatedRelativeLocationPath
11502  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11503  *
11504  * Compile a relative location path.
11505  */
11506 static void
11507 xmlXPathCompRelativeLocationPath
11508 (xmlXPathParserContextPtr ctxt) {
11509     SKIP_BLANKS;
11510     if ((CUR == '/') && (NXT(1) == '/')) {
11511         SKIP(2);
11512         SKIP_BLANKS;
11513         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11514                          NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11515     } else if (CUR == '/') {
11516             NEXT;
11517         SKIP_BLANKS;
11518     }
11519     xmlXPathCompStep(ctxt);
11520     CHECK_ERROR;
11521     SKIP_BLANKS;
11522     while (CUR == '/') {
11523         if ((CUR == '/') && (NXT(1) == '/')) {
11524             SKIP(2);
11525             SKIP_BLANKS;
11526             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11527                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11528             xmlXPathCompStep(ctxt);
11529         } else if (CUR == '/') {
11530             NEXT;
11531             SKIP_BLANKS;
11532             xmlXPathCompStep(ctxt);
11533         }
11534         SKIP_BLANKS;
11535     }
11536 }
11537
11538 /**
11539  * xmlXPathCompLocationPath:
11540  * @ctxt:  the XPath Parser context
11541  *
11542  *  [1]   LocationPath ::=   RelativeLocationPath
11543  *                     | AbsoluteLocationPath
11544  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11545  *                     | AbbreviatedAbsoluteLocationPath
11546  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11547  *                           '//' RelativeLocationPath
11548  *
11549  * Compile a location path
11550  *
11551  * // is short for /descendant-or-self::node()/. For example,
11552  * //para is short for /descendant-or-self::node()/child::para and
11553  * so will select any para element in the document (even a para element
11554  * that is a document element will be selected by //para since the
11555  * document element node is a child of the root node); div//para is
11556  * short for div/descendant-or-self::node()/child::para and so will
11557  * select all para descendants of div children.
11558  */
11559 static void
11560 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11561     SKIP_BLANKS;
11562     if (CUR != '/') {
11563         xmlXPathCompRelativeLocationPath(ctxt);
11564     } else {
11565         while (CUR == '/') {
11566             if ((CUR == '/') && (NXT(1) == '/')) {
11567                 SKIP(2);
11568                 SKIP_BLANKS;
11569                 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11570                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11571                 xmlXPathCompRelativeLocationPath(ctxt);
11572             } else if (CUR == '/') {
11573                 NEXT;
11574                 SKIP_BLANKS;
11575                 if ((CUR != 0 ) &&
11576                     ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11577                      (CUR == '@') || (CUR == '*')))
11578                     xmlXPathCompRelativeLocationPath(ctxt);
11579             }
11580             CHECK_ERROR;
11581         }
11582     }
11583 }
11584
11585 /************************************************************************
11586  *                                                                      *
11587  *              XPath precompiled expression evaluation                 *
11588  *                                                                      *
11589  ************************************************************************/
11590
11591 static int
11592 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11593
11594 #ifdef DEBUG_STEP
11595 static void
11596 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11597                           int nbNodes)
11598 {
11599     xmlGenericError(xmlGenericErrorContext, "new step : ");
11600     switch (op->value) {
11601         case AXIS_ANCESTOR:
11602             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11603             break;
11604         case AXIS_ANCESTOR_OR_SELF:
11605             xmlGenericError(xmlGenericErrorContext,
11606                             "axis 'ancestors-or-self' ");
11607             break;
11608         case AXIS_ATTRIBUTE:
11609             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11610             break;
11611         case AXIS_CHILD:
11612             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11613             break;
11614         case AXIS_DESCENDANT:
11615             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11616             break;
11617         case AXIS_DESCENDANT_OR_SELF:
11618             xmlGenericError(xmlGenericErrorContext,
11619                             "axis 'descendant-or-self' ");
11620             break;
11621         case AXIS_FOLLOWING:
11622             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11623             break;
11624         case AXIS_FOLLOWING_SIBLING:
11625             xmlGenericError(xmlGenericErrorContext,
11626                             "axis 'following-siblings' ");
11627             break;
11628         case AXIS_NAMESPACE:
11629             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11630             break;
11631         case AXIS_PARENT:
11632             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11633             break;
11634         case AXIS_PRECEDING:
11635             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11636             break;
11637         case AXIS_PRECEDING_SIBLING:
11638             xmlGenericError(xmlGenericErrorContext,
11639                             "axis 'preceding-sibling' ");
11640             break;
11641         case AXIS_SELF:
11642             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11643             break;
11644     }
11645     xmlGenericError(xmlGenericErrorContext,
11646         " context contains %d nodes\n", nbNodes);
11647     switch (op->value2) {
11648         case NODE_TEST_NONE:
11649             xmlGenericError(xmlGenericErrorContext,
11650                             "           searching for none !!!\n");
11651             break;
11652         case NODE_TEST_TYPE:
11653             xmlGenericError(xmlGenericErrorContext,
11654                             "           searching for type %d\n", op->value3);
11655             break;
11656         case NODE_TEST_PI:
11657             xmlGenericError(xmlGenericErrorContext,
11658                             "           searching for PI !!!\n");
11659             break;
11660         case NODE_TEST_ALL:
11661             xmlGenericError(xmlGenericErrorContext,
11662                             "           searching for *\n");
11663             break;
11664         case NODE_TEST_NS:
11665             xmlGenericError(xmlGenericErrorContext,
11666                             "           searching for namespace %s\n",
11667                             op->value5);
11668             break;
11669         case NODE_TEST_NAME:
11670             xmlGenericError(xmlGenericErrorContext,
11671                             "           searching for name %s\n", op->value5);
11672             if (op->value4)
11673                 xmlGenericError(xmlGenericErrorContext,
11674                                 "           with namespace %s\n", op->value4);
11675             break;
11676     }
11677     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11678 }
11679 #endif /* DEBUG_STEP */
11680
11681 static int
11682 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11683                             xmlXPathStepOpPtr op,
11684                             xmlNodeSetPtr set,
11685                             int contextSize,
11686                             int hasNsNodes)
11687 {
11688     if (op->ch1 != -1) {
11689         xmlXPathCompExprPtr comp = ctxt->comp;
11690         /*
11691         * Process inner predicates first.
11692         */
11693         if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11694             /*
11695             * TODO: raise an internal error.
11696             */
11697         }
11698         contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11699             &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11700         CHECK_ERROR0;
11701         if (contextSize <= 0)
11702             return(0);
11703     }
11704     if (op->ch2 != -1) {
11705         xmlXPathContextPtr xpctxt = ctxt->context;
11706         xmlNodePtr contextNode, oldContextNode;
11707         xmlDocPtr oldContextDoc;
11708         int i, res, contextPos = 0, newContextSize;
11709         xmlXPathStepOpPtr exprOp;
11710         xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11711
11712 #ifdef LIBXML_XPTR_ENABLED
11713         /*
11714         * URGENT TODO: Check the following:
11715         *  We don't expect location sets if evaluating prediates, right?
11716         *  Only filters should expect location sets, right?
11717         */
11718 #endif
11719         /*
11720         * SPEC XPath 1.0:
11721         *  "For each node in the node-set to be filtered, the
11722         *  PredicateExpr is evaluated with that node as the
11723         *  context node, with the number of nodes in the
11724         *  node-set as the context size, and with the proximity
11725         *  position of the node in the node-set with respect to
11726         *  the axis as the context position;"
11727         * @oldset is the node-set" to be filtered.
11728         *
11729         * SPEC XPath 1.0:
11730         *  "only predicates change the context position and
11731         *  context size (see [2.4 Predicates])."
11732         * Example:
11733         *   node-set  context pos
11734         *    nA         1
11735         *    nB         2
11736         *    nC         3
11737         *   After applying predicate [position() > 1] :
11738         *   node-set  context pos
11739         *    nB         1
11740         *    nC         2
11741         */
11742         oldContextNode = xpctxt->node;
11743         oldContextDoc = xpctxt->doc;
11744         /*
11745         * Get the expression of this predicate.
11746         */
11747         exprOp = &ctxt->comp->steps[op->ch2];
11748         newContextSize = 0;
11749         for (i = 0; i < set->nodeNr; i++) {
11750             if (set->nodeTab[i] == NULL)
11751                 continue;
11752
11753             contextNode = set->nodeTab[i];
11754             xpctxt->node = contextNode;
11755             xpctxt->contextSize = contextSize;
11756             xpctxt->proximityPosition = ++contextPos;
11757
11758             /*
11759             * Also set the xpath document in case things like
11760             * key() are evaluated in the predicate.
11761             */
11762             if ((contextNode->type != XML_NAMESPACE_DECL) &&
11763                 (contextNode->doc != NULL))
11764                 xpctxt->doc = contextNode->doc;
11765             /*
11766             * Evaluate the predicate expression with 1 context node
11767             * at a time; this node is packaged into a node set; this
11768             * node set is handed over to the evaluation mechanism.
11769             */
11770             if (contextObj == NULL)
11771                 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11772             else {
11773                 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11774                     contextNode) < 0) {
11775                     ctxt->error = XPATH_MEMORY_ERROR;
11776                     goto evaluation_exit;
11777                 }
11778             }
11779
11780             valuePush(ctxt, contextObj);
11781
11782             res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11783
11784             if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11785                 xmlXPathNodeSetClear(set, hasNsNodes);
11786                 newContextSize = 0;
11787                 goto evaluation_exit;
11788             }
11789
11790             if (res != 0) {
11791                 newContextSize++;
11792             } else {
11793                 /*
11794                 * Remove the entry from the initial node set.
11795                 */
11796                 set->nodeTab[i] = NULL;
11797                 if (contextNode->type == XML_NAMESPACE_DECL)
11798                     xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11799             }
11800             if (ctxt->value == contextObj) {
11801                 /*
11802                 * Don't free the temporary XPath object holding the
11803                 * context node, in order to avoid massive recreation
11804                 * inside this loop.
11805                 */
11806                 valuePop(ctxt);
11807                 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11808             } else {
11809                 /*
11810                 * TODO: The object was lost in the evaluation machinery.
11811                 *  Can this happen? Maybe in internal-error cases.
11812                 */
11813                 contextObj = NULL;
11814             }
11815         }
11816
11817         if (contextObj != NULL) {
11818             if (ctxt->value == contextObj)
11819                 valuePop(ctxt);
11820             xmlXPathReleaseObject(xpctxt, contextObj);
11821         }
11822 evaluation_exit:
11823         if (exprRes != NULL)
11824             xmlXPathReleaseObject(ctxt->context, exprRes);
11825         /*
11826         * Reset/invalidate the context.
11827         */
11828         xpctxt->node = oldContextNode;
11829         xpctxt->doc = oldContextDoc;
11830         xpctxt->contextSize = -1;
11831         xpctxt->proximityPosition = -1;
11832         return(newContextSize);
11833     }
11834     return(contextSize);
11835 }
11836
11837 static int
11838 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11839                                       xmlXPathStepOpPtr op,
11840                                       xmlNodeSetPtr set,
11841                                       int contextSize,
11842                                       int minPos,
11843                                       int maxPos,
11844                                       int hasNsNodes)
11845 {
11846     if (op->ch1 != -1) {
11847         xmlXPathCompExprPtr comp = ctxt->comp;
11848         if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11849             /*
11850             * TODO: raise an internal error.
11851             */
11852         }
11853         contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11854             &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11855         CHECK_ERROR0;
11856         if (contextSize <= 0)
11857             return(0);
11858     }
11859     /*
11860     * Check if the node set contains a sufficient number of nodes for
11861     * the requested range.
11862     */
11863     if (contextSize < minPos) {
11864         xmlXPathNodeSetClear(set, hasNsNodes);
11865         return(0);
11866     }
11867     if (op->ch2 == -1) {
11868         /*
11869         * TODO: Can this ever happen?
11870         */
11871         return (contextSize);
11872     } else {
11873         xmlDocPtr oldContextDoc;
11874         int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11875         xmlXPathStepOpPtr exprOp;
11876         xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11877         xmlNodePtr oldContextNode, contextNode = NULL;
11878         xmlXPathContextPtr xpctxt = ctxt->context;
11879         int frame;
11880
11881 #ifdef LIBXML_XPTR_ENABLED
11882             /*
11883             * URGENT TODO: Check the following:
11884             *  We don't expect location sets if evaluating prediates, right?
11885             *  Only filters should expect location sets, right?
11886         */
11887 #endif /* LIBXML_XPTR_ENABLED */
11888
11889         /*
11890         * Save old context.
11891         */
11892         oldContextNode = xpctxt->node;
11893         oldContextDoc = xpctxt->doc;
11894         /*
11895         * Get the expression of this predicate.
11896         */
11897         exprOp = &ctxt->comp->steps[op->ch2];
11898         for (i = 0; i < set->nodeNr; i++) {
11899             xmlXPathObjectPtr tmp;
11900
11901             if (set->nodeTab[i] == NULL)
11902                 continue;
11903
11904             contextNode = set->nodeTab[i];
11905             xpctxt->node = contextNode;
11906             xpctxt->contextSize = contextSize;
11907             xpctxt->proximityPosition = ++contextPos;
11908
11909             /*
11910             * Initialize the new set.
11911             * Also set the xpath document in case things like
11912             * key() evaluation are attempted on the predicate
11913             */
11914             if ((contextNode->type != XML_NAMESPACE_DECL) &&
11915                 (contextNode->doc != NULL))
11916                 xpctxt->doc = contextNode->doc;
11917             /*
11918             * Evaluate the predicate expression with 1 context node
11919             * at a time; this node is packaged into a node set; this
11920             * node set is handed over to the evaluation mechanism.
11921             */
11922             if (contextObj == NULL)
11923                 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11924             else {
11925                 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11926                     contextNode) < 0) {
11927                     ctxt->error = XPATH_MEMORY_ERROR;
11928                     goto evaluation_exit;
11929                 }
11930             }
11931
11932             valuePush(ctxt, contextObj);
11933             frame = xmlXPathSetFrame(ctxt);
11934             res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11935             xmlXPathPopFrame(ctxt, frame);
11936             tmp = valuePop(ctxt);
11937
11938             if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11939                 while (tmp != contextObj) {
11940                     /*
11941                      * Free up the result
11942                      * then pop off contextObj, which will be freed later
11943                      */
11944                     xmlXPathReleaseObject(xpctxt, tmp);
11945                     tmp = valuePop(ctxt);
11946                 }
11947                 goto evaluation_error;
11948             }
11949             /* push the result back onto the stack */
11950             valuePush(ctxt, tmp);
11951
11952             if (res)
11953                 pos++;
11954
11955             if (res && (pos >= minPos) && (pos <= maxPos)) {
11956                 /*
11957                 * Fits in the requested range.
11958                 */
11959                 newContextSize++;
11960                 if (minPos == maxPos) {
11961                     /*
11962                     * Only 1 node was requested.
11963                     */
11964                     if (contextNode->type == XML_NAMESPACE_DECL) {
11965                         /*
11966                         * As always: take care of those nasty
11967                         * namespace nodes.
11968                         */
11969                         set->nodeTab[i] = NULL;
11970                     }
11971                     xmlXPathNodeSetClear(set, hasNsNodes);
11972                     set->nodeNr = 1;
11973                     set->nodeTab[0] = contextNode;
11974                     goto evaluation_exit;
11975                 }
11976                 if (pos == maxPos) {
11977                     /*
11978                     * We are done.
11979                     */
11980                     xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11981                     goto evaluation_exit;
11982                 }
11983             } else {
11984                 /*
11985                 * Remove the entry from the initial node set.
11986                 */
11987                 set->nodeTab[i] = NULL;
11988                 if (contextNode->type == XML_NAMESPACE_DECL)
11989                     xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11990             }
11991             if (exprRes != NULL) {
11992                 xmlXPathReleaseObject(ctxt->context, exprRes);
11993                 exprRes = NULL;
11994             }
11995             if (ctxt->value == contextObj) {
11996                 /*
11997                 * Don't free the temporary XPath object holding the
11998                 * context node, in order to avoid massive recreation
11999                 * inside this loop.
12000                 */
12001                 valuePop(ctxt);
12002                 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
12003             } else {
12004                 /*
12005                 * The object was lost in the evaluation machinery.
12006                 * Can this happen? Maybe in case of internal-errors.
12007                 */
12008                 contextObj = NULL;
12009             }
12010         }
12011         goto evaluation_exit;
12012
12013 evaluation_error:
12014         xmlXPathNodeSetClear(set, hasNsNodes);
12015         newContextSize = 0;
12016
12017 evaluation_exit:
12018         if (contextObj != NULL) {
12019             if (ctxt->value == contextObj)
12020                 valuePop(ctxt);
12021             xmlXPathReleaseObject(xpctxt, contextObj);
12022         }
12023         if (exprRes != NULL)
12024             xmlXPathReleaseObject(ctxt->context, exprRes);
12025         /*
12026         * Reset/invalidate the context.
12027         */
12028         xpctxt->node = oldContextNode;
12029         xpctxt->doc = oldContextDoc;
12030         xpctxt->contextSize = -1;
12031         xpctxt->proximityPosition = -1;
12032         return(newContextSize);
12033     }
12034     return(contextSize);
12035 }
12036
12037 static int
12038 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12039                             xmlXPathStepOpPtr op,
12040                             int *maxPos)
12041 {
12042
12043     xmlXPathStepOpPtr exprOp;
12044
12045     /*
12046     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12047     */
12048
12049     /*
12050     * If not -1, then ch1 will point to:
12051     * 1) For predicates (XPATH_OP_PREDICATE):
12052     *    - an inner predicate operator
12053     * 2) For filters (XPATH_OP_FILTER):
12054     *    - an inner filter operater OR
12055     *    - an expression selecting the node set.
12056     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
12057     */
12058     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12059         return(0);
12060
12061     if (op->ch2 != -1) {
12062         exprOp = &ctxt->comp->steps[op->ch2];
12063     } else
12064         return(0);
12065
12066     if ((exprOp != NULL) &&
12067         (exprOp->op == XPATH_OP_VALUE) &&
12068         (exprOp->value4 != NULL) &&
12069         (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12070     {
12071         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12072
12073         /*
12074         * We have a "[n]" predicate here.
12075         * TODO: Unfortunately this simplistic test here is not
12076         * able to detect a position() predicate in compound
12077         * expressions like "[@attr = 'a" and position() = 1],
12078         * and even not the usage of position() in
12079         * "[position() = 1]"; thus - obviously - a position-range,
12080         * like it "[position() < 5]", is also not detected.
12081         * Maybe we could rewrite the AST to ease the optimization.
12082         */
12083
12084         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12085             *maxPos = (int) floatval;
12086             if (floatval == (double) *maxPos)
12087                 return(1);
12088         }
12089     }
12090     return(0);
12091 }
12092
12093 static int
12094 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12095                            xmlXPathStepOpPtr op,
12096                            xmlNodePtr * first, xmlNodePtr * last,
12097                            int toBool)
12098 {
12099
12100 #define XP_TEST_HIT \
12101     if (hasAxisRange != 0) { \
12102         if (++pos == maxPos) { \
12103             if (addNode(seq, cur) < 0) \
12104                 ctxt->error = XPATH_MEMORY_ERROR; \
12105             goto axis_range_end; } \
12106     } else { \
12107         if (addNode(seq, cur) < 0) \
12108             ctxt->error = XPATH_MEMORY_ERROR; \
12109         if (breakOnFirstHit) goto first_hit; }
12110
12111 #define XP_TEST_HIT_NS \
12112     if (hasAxisRange != 0) { \
12113         if (++pos == maxPos) { \
12114             hasNsNodes = 1; \
12115             if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12116                 ctxt->error = XPATH_MEMORY_ERROR; \
12117         goto axis_range_end; } \
12118     } else { \
12119         hasNsNodes = 1; \
12120         if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12121             ctxt->error = XPATH_MEMORY_ERROR; \
12122         if (breakOnFirstHit) goto first_hit; }
12123
12124     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12125     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12126     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12127     const xmlChar *prefix = op->value4;
12128     const xmlChar *name = op->value5;
12129     const xmlChar *URI = NULL;
12130
12131 #ifdef DEBUG_STEP
12132     int nbMatches = 0, prevMatches = 0;
12133 #endif
12134     int total = 0, hasNsNodes = 0;
12135     /* The popped object holding the context nodes */
12136     xmlXPathObjectPtr obj;
12137     /* The set of context nodes for the node tests */
12138     xmlNodeSetPtr contextSeq;
12139     int contextIdx;
12140     xmlNodePtr contextNode;
12141     /* The final resulting node set wrt to all context nodes */
12142     xmlNodeSetPtr outSeq;
12143     /*
12144     * The temporary resulting node set wrt 1 context node.
12145     * Used to feed predicate evaluation.
12146     */
12147     xmlNodeSetPtr seq;
12148     xmlNodePtr cur;
12149     /* First predicate operator */
12150     xmlXPathStepOpPtr predOp;
12151     int maxPos; /* The requested position() (when a "[n]" predicate) */
12152     int hasPredicateRange, hasAxisRange, pos, size, newSize;
12153     int breakOnFirstHit;
12154
12155     xmlXPathTraversalFunction next = NULL;
12156     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12157     xmlXPathNodeSetMergeFunction mergeAndClear;
12158     xmlNodePtr oldContextNode;
12159     xmlXPathContextPtr xpctxt = ctxt->context;
12160
12161
12162     CHECK_TYPE0(XPATH_NODESET);
12163     obj = valuePop(ctxt);
12164     /*
12165     * Setup namespaces.
12166     */
12167     if (prefix != NULL) {
12168         URI = xmlXPathNsLookup(xpctxt, prefix);
12169         if (URI == NULL) {
12170             xmlXPathReleaseObject(xpctxt, obj);
12171             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12172         }
12173     }
12174     /*
12175     * Setup axis.
12176     *
12177     * MAYBE FUTURE TODO: merging optimizations:
12178     * - If the nodes to be traversed wrt to the initial nodes and
12179     *   the current axis cannot overlap, then we could avoid searching
12180     *   for duplicates during the merge.
12181     *   But the question is how/when to evaluate if they cannot overlap.
12182     *   Example: if we know that for two initial nodes, the one is
12183     *   not in the ancestor-or-self axis of the other, then we could safely
12184     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12185     *   the descendant-or-self axis.
12186     */
12187     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12188     switch (axis) {
12189         case AXIS_ANCESTOR:
12190             first = NULL;
12191             next = xmlXPathNextAncestor;
12192             break;
12193         case AXIS_ANCESTOR_OR_SELF:
12194             first = NULL;
12195             next = xmlXPathNextAncestorOrSelf;
12196             break;
12197         case AXIS_ATTRIBUTE:
12198             first = NULL;
12199             last = NULL;
12200             next = xmlXPathNextAttribute;
12201             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12202             break;
12203         case AXIS_CHILD:
12204             last = NULL;
12205             if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12206                 (type == NODE_TYPE_NODE))
12207             {
12208                 /*
12209                 * Optimization if an element node type is 'element'.
12210                 */
12211                 next = xmlXPathNextChildElement;
12212             } else
12213                 next = xmlXPathNextChild;
12214             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12215             break;
12216         case AXIS_DESCENDANT:
12217             last = NULL;
12218             next = xmlXPathNextDescendant;
12219             break;
12220         case AXIS_DESCENDANT_OR_SELF:
12221             last = NULL;
12222             next = xmlXPathNextDescendantOrSelf;
12223             break;
12224         case AXIS_FOLLOWING:
12225             last = NULL;
12226             next = xmlXPathNextFollowing;
12227             break;
12228         case AXIS_FOLLOWING_SIBLING:
12229             last = NULL;
12230             next = xmlXPathNextFollowingSibling;
12231             break;
12232         case AXIS_NAMESPACE:
12233             first = NULL;
12234             last = NULL;
12235             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12236             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12237             break;
12238         case AXIS_PARENT:
12239             first = NULL;
12240             next = xmlXPathNextParent;
12241             break;
12242         case AXIS_PRECEDING:
12243             first = NULL;
12244             next = xmlXPathNextPrecedingInternal;
12245             break;
12246         case AXIS_PRECEDING_SIBLING:
12247             first = NULL;
12248             next = xmlXPathNextPrecedingSibling;
12249             break;
12250         case AXIS_SELF:
12251             first = NULL;
12252             last = NULL;
12253             next = xmlXPathNextSelf;
12254             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12255             break;
12256     }
12257
12258 #ifdef DEBUG_STEP
12259     xmlXPathDebugDumpStepAxis(op,
12260         (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12261 #endif
12262
12263     if (next == NULL) {
12264         xmlXPathReleaseObject(xpctxt, obj);
12265         return(0);
12266     }
12267     contextSeq = obj->nodesetval;
12268     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12269         xmlXPathReleaseObject(xpctxt, obj);
12270         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12271         return(0);
12272     }
12273     /*
12274     * Predicate optimization ---------------------------------------------
12275     * If this step has a last predicate, which contains a position(),
12276     * then we'll optimize (although not exactly "position()", but only
12277     * the  short-hand form, i.e., "[n]".
12278     *
12279     * Example - expression "/foo[parent::bar][1]":
12280     *
12281     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12282     *   ROOT                               -- op->ch1
12283     *   PREDICATE                          -- op->ch2 (predOp)
12284     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12285     *       SORT
12286     *         COLLECT  'parent' 'name' 'node' bar
12287     *           NODE
12288     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12289     *
12290     */
12291     maxPos = 0;
12292     predOp = NULL;
12293     hasPredicateRange = 0;
12294     hasAxisRange = 0;
12295     if (op->ch2 != -1) {
12296         /*
12297         * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12298         */
12299         predOp = &ctxt->comp->steps[op->ch2];
12300         if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12301             if (predOp->ch1 != -1) {
12302                 /*
12303                 * Use the next inner predicate operator.
12304                 */
12305                 predOp = &ctxt->comp->steps[predOp->ch1];
12306                 hasPredicateRange = 1;
12307             } else {
12308                 /*
12309                 * There's no other predicate than the [n] predicate.
12310                 */
12311                 predOp = NULL;
12312                 hasAxisRange = 1;
12313             }
12314         }
12315     }
12316     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12317     /*
12318     * Axis traversal -----------------------------------------------------
12319     */
12320     /*
12321      * 2.3 Node Tests
12322      *  - For the attribute axis, the principal node type is attribute.
12323      *  - For the namespace axis, the principal node type is namespace.
12324      *  - For other axes, the principal node type is element.
12325      *
12326      * A node test * is true for any node of the
12327      * principal node type. For example, child::* will
12328      * select all element children of the context node
12329      */
12330     oldContextNode = xpctxt->node;
12331     addNode = xmlXPathNodeSetAddUnique;
12332     outSeq = NULL;
12333     seq = NULL;
12334     contextNode = NULL;
12335     contextIdx = 0;
12336
12337
12338     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12339            (ctxt->error == XPATH_EXPRESSION_OK)) {
12340         xpctxt->node = contextSeq->nodeTab[contextIdx++];
12341
12342         if (seq == NULL) {
12343             seq = xmlXPathNodeSetCreate(NULL);
12344             if (seq == NULL) {
12345                 total = 0;
12346                 goto error;
12347             }
12348         }
12349         /*
12350         * Traverse the axis and test the nodes.
12351         */
12352         pos = 0;
12353         cur = NULL;
12354         hasNsNodes = 0;
12355         do {
12356             cur = next(ctxt, cur);
12357             if (cur == NULL)
12358                 break;
12359
12360             /*
12361             * QUESTION TODO: What does the "first" and "last" stuff do?
12362             */
12363             if ((first != NULL) && (*first != NULL)) {
12364                 if (*first == cur)
12365                     break;
12366                 if (((total % 256) == 0) &&
12367 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12368                     (xmlXPathCmpNodesExt(*first, cur) >= 0))
12369 #else
12370                     (xmlXPathCmpNodes(*first, cur) >= 0))
12371 #endif
12372                 {
12373                     break;
12374                 }
12375             }
12376             if ((last != NULL) && (*last != NULL)) {
12377                 if (*last == cur)
12378                     break;
12379                 if (((total % 256) == 0) &&
12380 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12381                     (xmlXPathCmpNodesExt(cur, *last) >= 0))
12382 #else
12383                     (xmlXPathCmpNodes(cur, *last) >= 0))
12384 #endif
12385                 {
12386                     break;
12387                 }
12388             }
12389
12390             total++;
12391
12392 #ifdef DEBUG_STEP
12393             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12394 #endif
12395
12396             switch (test) {
12397                 case NODE_TEST_NONE:
12398                     total = 0;
12399                     STRANGE
12400                     goto error;
12401                 case NODE_TEST_TYPE:
12402                     if (type == NODE_TYPE_NODE) {
12403                         switch (cur->type) {
12404                             case XML_DOCUMENT_NODE:
12405                             case XML_HTML_DOCUMENT_NODE:
12406 #ifdef LIBXML_DOCB_ENABLED
12407                             case XML_DOCB_DOCUMENT_NODE:
12408 #endif
12409                             case XML_ELEMENT_NODE:
12410                             case XML_ATTRIBUTE_NODE:
12411                             case XML_PI_NODE:
12412                             case XML_COMMENT_NODE:
12413                             case XML_CDATA_SECTION_NODE:
12414                             case XML_TEXT_NODE:
12415                                 XP_TEST_HIT
12416                                 break;
12417                             case XML_NAMESPACE_DECL: {
12418                                 if (axis == AXIS_NAMESPACE) {
12419                                     XP_TEST_HIT_NS
12420                                 } else {
12421                                     hasNsNodes = 1;
12422                                     XP_TEST_HIT
12423                                 }
12424                                 break;
12425                             }
12426                             default:
12427                                 break;
12428                         }
12429                     } else if (cur->type == type) {
12430                         if (cur->type == XML_NAMESPACE_DECL)
12431                             XP_TEST_HIT_NS
12432                         else
12433                             XP_TEST_HIT
12434                     } else if ((type == NODE_TYPE_TEXT) &&
12435                          (cur->type == XML_CDATA_SECTION_NODE))
12436                     {
12437                         XP_TEST_HIT
12438                     }
12439                     break;
12440                 case NODE_TEST_PI:
12441                     if ((cur->type == XML_PI_NODE) &&
12442                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12443                     {
12444                         XP_TEST_HIT
12445                     }
12446                     break;
12447                 case NODE_TEST_ALL:
12448                     if (axis == AXIS_ATTRIBUTE) {
12449                         if (cur->type == XML_ATTRIBUTE_NODE)
12450                         {
12451                             if (prefix == NULL)
12452                             {
12453                                 XP_TEST_HIT
12454                             } else if ((cur->ns != NULL) &&
12455                                 (xmlStrEqual(URI, cur->ns->href)))
12456                             {
12457                                 XP_TEST_HIT
12458                             }
12459                         }
12460                     } else if (axis == AXIS_NAMESPACE) {
12461                         if (cur->type == XML_NAMESPACE_DECL)
12462                         {
12463                             XP_TEST_HIT_NS
12464                         }
12465                     } else {
12466                         if (cur->type == XML_ELEMENT_NODE) {
12467                             if (prefix == NULL)
12468                             {
12469                                 XP_TEST_HIT
12470
12471                             } else if ((cur->ns != NULL) &&
12472                                 (xmlStrEqual(URI, cur->ns->href)))
12473                             {
12474                                 XP_TEST_HIT
12475                             }
12476                         }
12477                     }
12478                     break;
12479                 case NODE_TEST_NS:{
12480                         TODO;
12481                         break;
12482                     }
12483                 case NODE_TEST_NAME:
12484                     if (axis == AXIS_ATTRIBUTE) {
12485                         if (cur->type != XML_ATTRIBUTE_NODE)
12486                             break;
12487                     } else if (axis == AXIS_NAMESPACE) {
12488                         if (cur->type != XML_NAMESPACE_DECL)
12489                             break;
12490                     } else {
12491                         if (cur->type != XML_ELEMENT_NODE)
12492                             break;
12493                     }
12494                     switch (cur->type) {
12495                         case XML_ELEMENT_NODE:
12496                             if (xmlStrEqual(name, cur->name)) {
12497                                 if (prefix == NULL) {
12498                                     if (cur->ns == NULL)
12499                                     {
12500                                         XP_TEST_HIT
12501                                     }
12502                                 } else {
12503                                     if ((cur->ns != NULL) &&
12504                                         (xmlStrEqual(URI, cur->ns->href)))
12505                                     {
12506                                         XP_TEST_HIT
12507                                     }
12508                                 }
12509                             }
12510                             break;
12511                         case XML_ATTRIBUTE_NODE:{
12512                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12513
12514                                 if (xmlStrEqual(name, attr->name)) {
12515                                     if (prefix == NULL) {
12516                                         if ((attr->ns == NULL) ||
12517                                             (attr->ns->prefix == NULL))
12518                                         {
12519                                             XP_TEST_HIT
12520                                         }
12521                                     } else {
12522                                         if ((attr->ns != NULL) &&
12523                                             (xmlStrEqual(URI,
12524                                               attr->ns->href)))
12525                                         {
12526                                             XP_TEST_HIT
12527                                         }
12528                                     }
12529                                 }
12530                                 break;
12531                             }
12532                         case XML_NAMESPACE_DECL:
12533                             if (cur->type == XML_NAMESPACE_DECL) {
12534                                 xmlNsPtr ns = (xmlNsPtr) cur;
12535
12536                                 if ((ns->prefix != NULL) && (name != NULL)
12537                                     && (xmlStrEqual(ns->prefix, name)))
12538                                 {
12539                                     XP_TEST_HIT_NS
12540                                 }
12541                             }
12542                             break;
12543                         default:
12544                             break;
12545                     }
12546                     break;
12547             } /* switch(test) */
12548         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12549
12550         goto apply_predicates;
12551
12552 axis_range_end: /* ----------------------------------------------------- */
12553         /*
12554         * We have a "/foo[n]", and position() = n was reached.
12555         * Note that we can have as well "/foo/::parent::foo[1]", so
12556         * a duplicate-aware merge is still needed.
12557         * Merge with the result.
12558         */
12559         if (outSeq == NULL) {
12560             outSeq = seq;
12561             seq = NULL;
12562         } else
12563             outSeq = mergeAndClear(outSeq, seq, 0);
12564         /*
12565         * Break if only a true/false result was requested.
12566         */
12567         if (toBool)
12568             break;
12569         continue;
12570
12571 first_hit: /* ---------------------------------------------------------- */
12572         /*
12573         * Break if only a true/false result was requested and
12574         * no predicates existed and a node test succeeded.
12575         */
12576         if (outSeq == NULL) {
12577             outSeq = seq;
12578             seq = NULL;
12579         } else
12580             outSeq = mergeAndClear(outSeq, seq, 0);
12581         break;
12582
12583 #ifdef DEBUG_STEP
12584         if (seq != NULL)
12585             nbMatches += seq->nodeNr;
12586 #endif
12587
12588 apply_predicates: /* --------------------------------------------------- */
12589         if (ctxt->error != XPATH_EXPRESSION_OK)
12590             goto error;
12591
12592         /*
12593         * Apply predicates.
12594         */
12595         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12596             /*
12597             * E.g. when we have a "/foo[some expression][n]".
12598             */
12599             /*
12600             * QUESTION TODO: The old predicate evaluation took into
12601             *  account location-sets.
12602             *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12603             *  Do we expect such a set here?
12604             *  All what I learned now from the evaluation semantics
12605             *  does not indicate that a location-set will be processed
12606             *  here, so this looks OK.
12607             */
12608             /*
12609             * Iterate over all predicates, starting with the outermost
12610             * predicate.
12611             * TODO: Problem: we cannot execute the inner predicates first
12612             *  since we cannot go back *up* the operator tree!
12613             *  Options we have:
12614             *  1) Use of recursive functions (like is it currently done
12615             *     via xmlXPathCompOpEval())
12616             *  2) Add a predicate evaluation information stack to the
12617             *     context struct
12618             *  3) Change the way the operators are linked; we need a
12619             *     "parent" field on xmlXPathStepOp
12620             *
12621             * For the moment, I'll try to solve this with a recursive
12622             * function: xmlXPathCompOpEvalPredicate().
12623             */
12624             size = seq->nodeNr;
12625             if (hasPredicateRange != 0)
12626                 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12627                     predOp, seq, size, maxPos, maxPos, hasNsNodes);
12628             else
12629                 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12630                     predOp, seq, size, hasNsNodes);
12631
12632             if (ctxt->error != XPATH_EXPRESSION_OK) {
12633                 total = 0;
12634                 goto error;
12635             }
12636             /*
12637             * Add the filtered set of nodes to the result node set.
12638             */
12639             if (newSize == 0) {
12640                 /*
12641                 * The predicates filtered all nodes out.
12642                 */
12643                 xmlXPathNodeSetClear(seq, hasNsNodes);
12644             } else if (seq->nodeNr > 0) {
12645                 /*
12646                 * Add to result set.
12647                 */
12648                 if (outSeq == NULL) {
12649                     if (size != newSize) {
12650                         /*
12651                         * We need to merge and clear here, since
12652                         * the sequence will contained NULLed entries.
12653                         */
12654                         outSeq = mergeAndClear(NULL, seq, 1);
12655                     } else {
12656                         outSeq = seq;
12657                         seq = NULL;
12658                     }
12659                 } else
12660                     outSeq = mergeAndClear(outSeq, seq,
12661                         (size != newSize) ? 1: 0);
12662                 /*
12663                 * Break if only a true/false result was requested.
12664                 */
12665                 if (toBool)
12666                     break;
12667             }
12668         } else if (seq->nodeNr > 0) {
12669             /*
12670             * Add to result set.
12671             */
12672             if (outSeq == NULL) {
12673                 outSeq = seq;
12674                 seq = NULL;
12675             } else {
12676                 outSeq = mergeAndClear(outSeq, seq, 0);
12677             }
12678         }
12679     }
12680
12681 error:
12682     if ((obj->boolval) && (obj->user != NULL)) {
12683         /*
12684         * QUESTION TODO: What does this do and why?
12685         * TODO: Do we have to do this also for the "error"
12686         * cleanup further down?
12687         */
12688         ctxt->value->boolval = 1;
12689         ctxt->value->user = obj->user;
12690         obj->user = NULL;
12691         obj->boolval = 0;
12692     }
12693     xmlXPathReleaseObject(xpctxt, obj);
12694
12695     /*
12696     * Ensure we return at least an emtpy set.
12697     */
12698     if (outSeq == NULL) {
12699         if ((seq != NULL) && (seq->nodeNr == 0))
12700             outSeq = seq;
12701         else
12702             outSeq = xmlXPathNodeSetCreate(NULL);
12703         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12704     }
12705     if ((seq != NULL) && (seq != outSeq)) {
12706          xmlXPathFreeNodeSet(seq);
12707     }
12708     /*
12709     * Hand over the result. Better to push the set also in
12710     * case of errors.
12711     */
12712     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12713     /*
12714     * Reset the context node.
12715     */
12716     xpctxt->node = oldContextNode;
12717     /*
12718     * When traversing the namespace axis in "toBool" mode, it's
12719     * possible that tmpNsList wasn't freed.
12720     */
12721     if (xpctxt->tmpNsList != NULL) {
12722         xmlFree(xpctxt->tmpNsList);
12723         xpctxt->tmpNsList = NULL;
12724     }
12725
12726 #ifdef DEBUG_STEP
12727     xmlGenericError(xmlGenericErrorContext,
12728         "\nExamined %d nodes, found %d nodes at that step\n",
12729         total, nbMatches);
12730 #endif
12731
12732     return(total);
12733 }
12734
12735 static int
12736 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12737                               xmlXPathStepOpPtr op, xmlNodePtr * first);
12738
12739 /**
12740  * xmlXPathCompOpEvalFirst:
12741  * @ctxt:  the XPath parser context with the compiled expression
12742  * @op:  an XPath compiled operation
12743  * @first:  the first elem found so far
12744  *
12745  * Evaluate the Precompiled XPath operation searching only the first
12746  * element in document order
12747  *
12748  * Returns the number of examined objects.
12749  */
12750 static int
12751 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12752                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12753 {
12754     int total = 0, cur;
12755     xmlXPathCompExprPtr comp;
12756     xmlXPathObjectPtr arg1, arg2;
12757
12758     CHECK_ERROR0;
12759     comp = ctxt->comp;
12760     switch (op->op) {
12761         case XPATH_OP_END:
12762             return (0);
12763         case XPATH_OP_UNION:
12764             total =
12765                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12766                                         first);
12767             CHECK_ERROR0;
12768             if ((ctxt->value != NULL)
12769                 && (ctxt->value->type == XPATH_NODESET)
12770                 && (ctxt->value->nodesetval != NULL)
12771                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12772                 /*
12773                  * limit tree traversing to first node in the result
12774                  */
12775                 /*
12776                 * OPTIMIZE TODO: This implicitely sorts
12777                 *  the result, even if not needed. E.g. if the argument
12778                 *  of the count() function, no sorting is needed.
12779                 * OPTIMIZE TODO: How do we know if the node-list wasn't
12780                 *  aready sorted?
12781                 */
12782                 if (ctxt->value->nodesetval->nodeNr > 1)
12783                     xmlXPathNodeSetSort(ctxt->value->nodesetval);
12784                 *first = ctxt->value->nodesetval->nodeTab[0];
12785             }
12786             cur =
12787                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12788                                         first);
12789             CHECK_ERROR0;
12790
12791             arg2 = valuePop(ctxt);
12792             arg1 = valuePop(ctxt);
12793             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12794                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12795                 xmlXPathReleaseObject(ctxt->context, arg1);
12796                 xmlXPathReleaseObject(ctxt->context, arg2);
12797                 XP_ERROR0(XPATH_INVALID_TYPE);
12798             }
12799
12800             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12801                                                     arg2->nodesetval);
12802             valuePush(ctxt, arg1);
12803             xmlXPathReleaseObject(ctxt->context, arg2);
12804             /* optimizer */
12805             if (total > cur)
12806                 xmlXPathCompSwap(op);
12807             return (total + cur);
12808         case XPATH_OP_ROOT:
12809             xmlXPathRoot(ctxt);
12810             return (0);
12811         case XPATH_OP_NODE:
12812             if (op->ch1 != -1)
12813                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12814             CHECK_ERROR0;
12815             if (op->ch2 != -1)
12816                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12817             CHECK_ERROR0;
12818             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12819                 ctxt->context->node));
12820             return (total);
12821         case XPATH_OP_RESET:
12822             if (op->ch1 != -1)
12823                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12824             CHECK_ERROR0;
12825             if (op->ch2 != -1)
12826                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12827             CHECK_ERROR0;
12828             ctxt->context->node = NULL;
12829             return (total);
12830         case XPATH_OP_COLLECT:{
12831                 if (op->ch1 == -1)
12832                     return (total);
12833
12834                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12835                 CHECK_ERROR0;
12836
12837                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12838                 return (total);
12839             }
12840         case XPATH_OP_VALUE:
12841             valuePush(ctxt,
12842                       xmlXPathCacheObjectCopy(ctxt->context,
12843                         (xmlXPathObjectPtr) op->value4));
12844             return (0);
12845         case XPATH_OP_SORT:
12846             if (op->ch1 != -1)
12847                 total +=
12848                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12849                                             first);
12850             CHECK_ERROR0;
12851             if ((ctxt->value != NULL)
12852                 && (ctxt->value->type == XPATH_NODESET)
12853                 && (ctxt->value->nodesetval != NULL)
12854                 && (ctxt->value->nodesetval->nodeNr > 1))
12855                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12856             return (total);
12857 #ifdef XP_OPTIMIZED_FILTER_FIRST
12858         case XPATH_OP_FILTER:
12859                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12860             return (total);
12861 #endif
12862         default:
12863             return (xmlXPathCompOpEval(ctxt, op));
12864     }
12865 }
12866
12867 /**
12868  * xmlXPathCompOpEvalLast:
12869  * @ctxt:  the XPath parser context with the compiled expression
12870  * @op:  an XPath compiled operation
12871  * @last:  the last elem found so far
12872  *
12873  * Evaluate the Precompiled XPath operation searching only the last
12874  * element in document order
12875  *
12876  * Returns the number of nodes traversed
12877  */
12878 static int
12879 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12880                        xmlNodePtr * last)
12881 {
12882     int total = 0, cur;
12883     xmlXPathCompExprPtr comp;
12884     xmlXPathObjectPtr arg1, arg2;
12885     xmlNodePtr bak;
12886     xmlDocPtr bakd;
12887     int pp;
12888     int cs;
12889
12890     CHECK_ERROR0;
12891     comp = ctxt->comp;
12892     switch (op->op) {
12893         case XPATH_OP_END:
12894             return (0);
12895         case XPATH_OP_UNION:
12896             bakd = ctxt->context->doc;
12897             bak = ctxt->context->node;
12898             pp = ctxt->context->proximityPosition;
12899             cs = ctxt->context->contextSize;
12900             total =
12901                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12902             CHECK_ERROR0;
12903             if ((ctxt->value != NULL)
12904                 && (ctxt->value->type == XPATH_NODESET)
12905                 && (ctxt->value->nodesetval != NULL)
12906                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12907                 /*
12908                  * limit tree traversing to first node in the result
12909                  */
12910                 if (ctxt->value->nodesetval->nodeNr > 1)
12911                     xmlXPathNodeSetSort(ctxt->value->nodesetval);
12912                 *last =
12913                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12914                                                      nodesetval->nodeNr -
12915                                                      1];
12916             }
12917             ctxt->context->doc = bakd;
12918             ctxt->context->node = bak;
12919             ctxt->context->proximityPosition = pp;
12920             ctxt->context->contextSize = cs;
12921             cur =
12922                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12923             CHECK_ERROR0;
12924             if ((ctxt->value != NULL)
12925                 && (ctxt->value->type == XPATH_NODESET)
12926                 && (ctxt->value->nodesetval != NULL)
12927                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12928             }
12929
12930             arg2 = valuePop(ctxt);
12931             arg1 = valuePop(ctxt);
12932             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12933                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12934                 xmlXPathReleaseObject(ctxt->context, arg1);
12935                 xmlXPathReleaseObject(ctxt->context, arg2);
12936                 XP_ERROR0(XPATH_INVALID_TYPE);
12937             }
12938
12939             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12940                                                     arg2->nodesetval);
12941             valuePush(ctxt, arg1);
12942             xmlXPathReleaseObject(ctxt->context, arg2);
12943             /* optimizer */
12944             if (total > cur)
12945                 xmlXPathCompSwap(op);
12946             return (total + cur);
12947         case XPATH_OP_ROOT:
12948             xmlXPathRoot(ctxt);
12949             return (0);
12950         case XPATH_OP_NODE:
12951             if (op->ch1 != -1)
12952                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12953             CHECK_ERROR0;
12954             if (op->ch2 != -1)
12955                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12956             CHECK_ERROR0;
12957             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12958                 ctxt->context->node));
12959             return (total);
12960         case XPATH_OP_RESET:
12961             if (op->ch1 != -1)
12962                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12963             CHECK_ERROR0;
12964             if (op->ch2 != -1)
12965                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12966             CHECK_ERROR0;
12967             ctxt->context->node = NULL;
12968             return (total);
12969         case XPATH_OP_COLLECT:{
12970                 if (op->ch1 == -1)
12971                     return (0);
12972
12973                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12974                 CHECK_ERROR0;
12975
12976                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12977                 return (total);
12978             }
12979         case XPATH_OP_VALUE:
12980             valuePush(ctxt,
12981                       xmlXPathCacheObjectCopy(ctxt->context,
12982                         (xmlXPathObjectPtr) op->value4));
12983             return (0);
12984         case XPATH_OP_SORT:
12985             if (op->ch1 != -1)
12986                 total +=
12987                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12988                                            last);
12989             CHECK_ERROR0;
12990             if ((ctxt->value != NULL)
12991                 && (ctxt->value->type == XPATH_NODESET)
12992                 && (ctxt->value->nodesetval != NULL)
12993                 && (ctxt->value->nodesetval->nodeNr > 1))
12994                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12995             return (total);
12996         default:
12997             return (xmlXPathCompOpEval(ctxt, op));
12998     }
12999 }
13000
13001 #ifdef XP_OPTIMIZED_FILTER_FIRST
13002 static int
13003 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
13004                               xmlXPathStepOpPtr op, xmlNodePtr * first)
13005 {
13006     int total = 0;
13007     xmlXPathCompExprPtr comp;
13008     xmlXPathObjectPtr res;
13009     xmlXPathObjectPtr obj;
13010     xmlNodeSetPtr oldset;
13011     xmlNodePtr oldnode;
13012     xmlDocPtr oldDoc;
13013     int i;
13014
13015     CHECK_ERROR0;
13016     comp = ctxt->comp;
13017     /*
13018     * Optimization for ()[last()] selection i.e. the last elem
13019     */
13020     if ((op->ch1 != -1) && (op->ch2 != -1) &&
13021         (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13022         (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13023         int f = comp->steps[op->ch2].ch1;
13024
13025         if ((f != -1) &&
13026             (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13027             (comp->steps[f].value5 == NULL) &&
13028             (comp->steps[f].value == 0) &&
13029             (comp->steps[f].value4 != NULL) &&
13030             (xmlStrEqual
13031             (comp->steps[f].value4, BAD_CAST "last"))) {
13032             xmlNodePtr last = NULL;
13033
13034             total +=
13035                 xmlXPathCompOpEvalLast(ctxt,
13036                     &comp->steps[op->ch1],
13037                     &last);
13038             CHECK_ERROR0;
13039             /*
13040             * The nodeset should be in document order,
13041             * Keep only the last value
13042             */
13043             if ((ctxt->value != NULL) &&
13044                 (ctxt->value->type == XPATH_NODESET) &&
13045                 (ctxt->value->nodesetval != NULL) &&
13046                 (ctxt->value->nodesetval->nodeTab != NULL) &&
13047                 (ctxt->value->nodesetval->nodeNr > 1)) {
13048                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13049                 *first = *(ctxt->value->nodesetval->nodeTab);
13050             }
13051             return (total);
13052         }
13053     }
13054
13055     if (op->ch1 != -1)
13056         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13057     CHECK_ERROR0;
13058     if (op->ch2 == -1)
13059         return (total);
13060     if (ctxt->value == NULL)
13061         return (total);
13062
13063 #ifdef LIBXML_XPTR_ENABLED
13064     oldnode = ctxt->context->node;
13065     /*
13066     * Hum are we filtering the result of an XPointer expression
13067     */
13068     if (ctxt->value->type == XPATH_LOCATIONSET) {
13069         xmlXPathObjectPtr tmp = NULL;
13070         xmlLocationSetPtr newlocset = NULL;
13071         xmlLocationSetPtr oldlocset;
13072
13073         /*
13074         * Extract the old locset, and then evaluate the result of the
13075         * expression for all the element in the locset. use it to grow
13076         * up a new locset.
13077         */
13078         CHECK_TYPE0(XPATH_LOCATIONSET);
13079         obj = valuePop(ctxt);
13080         oldlocset = obj->user;
13081         ctxt->context->node = NULL;
13082
13083         if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13084             ctxt->context->contextSize = 0;
13085             ctxt->context->proximityPosition = 0;
13086             if (op->ch2 != -1)
13087                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13088             res = valuePop(ctxt);
13089             if (res != NULL) {
13090                 xmlXPathReleaseObject(ctxt->context, res);
13091             }
13092             valuePush(ctxt, obj);
13093             CHECK_ERROR0;
13094             return (total);
13095         }
13096         newlocset = xmlXPtrLocationSetCreate(NULL);
13097
13098         for (i = 0; i < oldlocset->locNr; i++) {
13099             /*
13100             * Run the evaluation with a node list made of a
13101             * single item in the nodelocset.
13102             */
13103             ctxt->context->node = oldlocset->locTab[i]->user;
13104             ctxt->context->contextSize = oldlocset->locNr;
13105             ctxt->context->proximityPosition = i + 1;
13106             if (tmp == NULL) {
13107                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13108                     ctxt->context->node);
13109             } else {
13110                 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13111                                              ctxt->context->node) < 0) {
13112                     ctxt->error = XPATH_MEMORY_ERROR;
13113                 }
13114             }
13115             valuePush(ctxt, tmp);
13116             if (op->ch2 != -1)
13117                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13118             if (ctxt->error != XPATH_EXPRESSION_OK) {
13119                 xmlXPathFreeObject(obj);
13120                 return(0);
13121             }
13122             /*
13123             * The result of the evaluation need to be tested to
13124             * decided whether the filter succeeded or not
13125             */
13126             res = valuePop(ctxt);
13127             if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13128                 xmlXPtrLocationSetAdd(newlocset,
13129                     xmlXPathCacheObjectCopy(ctxt->context,
13130                         oldlocset->locTab[i]));
13131             }
13132             /*
13133             * Cleanup
13134             */
13135             if (res != NULL) {
13136                 xmlXPathReleaseObject(ctxt->context, res);
13137             }
13138             if (ctxt->value == tmp) {
13139                 valuePop(ctxt);
13140                 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13141                 /*
13142                 * REVISIT TODO: Don't create a temporary nodeset
13143                 * for everly iteration.
13144                 */
13145                 /* OLD: xmlXPathFreeObject(res); */
13146             } else
13147                 tmp = NULL;
13148             ctxt->context->node = NULL;
13149             /*
13150             * Only put the first node in the result, then leave.
13151             */
13152             if (newlocset->locNr > 0) {
13153                 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13154                 break;
13155             }
13156         }
13157         if (tmp != NULL) {
13158             xmlXPathReleaseObject(ctxt->context, tmp);
13159         }
13160         /*
13161         * The result is used as the new evaluation locset.
13162         */
13163         xmlXPathReleaseObject(ctxt->context, obj);
13164         ctxt->context->node = NULL;
13165         ctxt->context->contextSize = -1;
13166         ctxt->context->proximityPosition = -1;
13167         valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13168         ctxt->context->node = oldnode;
13169         return (total);
13170     }
13171 #endif /* LIBXML_XPTR_ENABLED */
13172
13173     /*
13174     * Extract the old set, and then evaluate the result of the
13175     * expression for all the element in the set. use it to grow
13176     * up a new set.
13177     */
13178     CHECK_TYPE0(XPATH_NODESET);
13179     obj = valuePop(ctxt);
13180     oldset = obj->nodesetval;
13181
13182     oldnode = ctxt->context->node;
13183     oldDoc = ctxt->context->doc;
13184     ctxt->context->node = NULL;
13185
13186     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13187         ctxt->context->contextSize = 0;
13188         ctxt->context->proximityPosition = 0;
13189         /* QUESTION TODO: Why was this code commented out?
13190             if (op->ch2 != -1)
13191                 total +=
13192                     xmlXPathCompOpEval(ctxt,
13193                         &comp->steps[op->ch2]);
13194             CHECK_ERROR0;
13195             res = valuePop(ctxt);
13196             if (res != NULL)
13197                 xmlXPathFreeObject(res);
13198         */
13199         valuePush(ctxt, obj);
13200         ctxt->context->node = oldnode;
13201         CHECK_ERROR0;
13202     } else {
13203         xmlNodeSetPtr newset;
13204         xmlXPathObjectPtr tmp = NULL;
13205         /*
13206         * Initialize the new set.
13207         * Also set the xpath document in case things like
13208         * key() evaluation are attempted on the predicate
13209         */
13210         newset = xmlXPathNodeSetCreate(NULL);
13211         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13212
13213         for (i = 0; i < oldset->nodeNr; i++) {
13214             /*
13215             * Run the evaluation with a node list made of
13216             * a single item in the nodeset.
13217             */
13218             ctxt->context->node = oldset->nodeTab[i];
13219             if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13220                 (oldset->nodeTab[i]->doc != NULL))
13221                 ctxt->context->doc = oldset->nodeTab[i]->doc;
13222             if (tmp == NULL) {
13223                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13224                     ctxt->context->node);
13225             } else {
13226                 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13227                                              ctxt->context->node) < 0) {
13228                     ctxt->error = XPATH_MEMORY_ERROR;
13229                 }
13230             }
13231             valuePush(ctxt, tmp);
13232             ctxt->context->contextSize = oldset->nodeNr;
13233             ctxt->context->proximityPosition = i + 1;
13234             if (op->ch2 != -1)
13235                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13236             if (ctxt->error != XPATH_EXPRESSION_OK) {
13237                 xmlXPathFreeNodeSet(newset);
13238                 xmlXPathFreeObject(obj);
13239                 return(0);
13240             }
13241             /*
13242             * The result of the evaluation needs to be tested to
13243             * decide whether the filter succeeded or not
13244             */
13245             res = valuePop(ctxt);
13246             if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13247                 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13248                     ctxt->error = XPATH_MEMORY_ERROR;
13249             }
13250             /*
13251             * Cleanup
13252             */
13253             if (res != NULL) {
13254                 xmlXPathReleaseObject(ctxt->context, res);
13255             }
13256             if (ctxt->value == tmp) {
13257                 valuePop(ctxt);
13258                 /*
13259                 * Don't free the temporary nodeset
13260                 * in order to avoid massive recreation inside this
13261                 * loop.
13262                 */
13263                 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13264             } else
13265                 tmp = NULL;
13266             ctxt->context->node = NULL;
13267             /*
13268             * Only put the first node in the result, then leave.
13269             */
13270             if (newset->nodeNr > 0) {
13271                 *first = *(newset->nodeTab);
13272                 break;
13273             }
13274         }
13275         if (tmp != NULL) {
13276             xmlXPathReleaseObject(ctxt->context, tmp);
13277         }
13278         /*
13279         * The result is used as the new evaluation set.
13280         */
13281         xmlXPathReleaseObject(ctxt->context, obj);
13282         ctxt->context->node = NULL;
13283         ctxt->context->contextSize = -1;
13284         ctxt->context->proximityPosition = -1;
13285         /* may want to move this past the '}' later */
13286         ctxt->context->doc = oldDoc;
13287         valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13288     }
13289     ctxt->context->node = oldnode;
13290     return(total);
13291 }
13292 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13293
13294 /**
13295  * xmlXPathCompOpEval:
13296  * @ctxt:  the XPath parser context with the compiled expression
13297  * @op:  an XPath compiled operation
13298  *
13299  * Evaluate the Precompiled XPath operation
13300  * Returns the number of nodes traversed
13301  */
13302 static int
13303 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13304 {
13305     int total = 0;
13306     int equal, ret;
13307     xmlXPathCompExprPtr comp;
13308     xmlXPathObjectPtr arg1, arg2;
13309     xmlNodePtr bak;
13310     xmlDocPtr bakd;
13311     int pp;
13312     int cs;
13313
13314     CHECK_ERROR0;
13315     comp = ctxt->comp;
13316     switch (op->op) {
13317         case XPATH_OP_END:
13318             return (0);
13319         case XPATH_OP_AND:
13320             bakd = ctxt->context->doc;
13321             bak = ctxt->context->node;
13322             pp = ctxt->context->proximityPosition;
13323             cs = ctxt->context->contextSize;
13324             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13325             CHECK_ERROR0;
13326             xmlXPathBooleanFunction(ctxt, 1);
13327             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13328                 return (total);
13329             arg2 = valuePop(ctxt);
13330             ctxt->context->doc = bakd;
13331             ctxt->context->node = bak;
13332             ctxt->context->proximityPosition = pp;
13333             ctxt->context->contextSize = cs;
13334             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13335             if (ctxt->error) {
13336                 xmlXPathFreeObject(arg2);
13337                 return(0);
13338             }
13339             xmlXPathBooleanFunction(ctxt, 1);
13340             arg1 = valuePop(ctxt);
13341             arg1->boolval &= arg2->boolval;
13342             valuePush(ctxt, arg1);
13343             xmlXPathReleaseObject(ctxt->context, arg2);
13344             return (total);
13345         case XPATH_OP_OR:
13346             bakd = ctxt->context->doc;
13347             bak = ctxt->context->node;
13348             pp = ctxt->context->proximityPosition;
13349             cs = ctxt->context->contextSize;
13350             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13351             CHECK_ERROR0;
13352             xmlXPathBooleanFunction(ctxt, 1);
13353             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13354                 return (total);
13355             arg2 = valuePop(ctxt);
13356             ctxt->context->doc = bakd;
13357             ctxt->context->node = bak;
13358             ctxt->context->proximityPosition = pp;
13359             ctxt->context->contextSize = cs;
13360             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13361             if (ctxt->error) {
13362                 xmlXPathFreeObject(arg2);
13363                 return(0);
13364             }
13365             xmlXPathBooleanFunction(ctxt, 1);
13366             arg1 = valuePop(ctxt);
13367             arg1->boolval |= arg2->boolval;
13368             valuePush(ctxt, arg1);
13369             xmlXPathReleaseObject(ctxt->context, arg2);
13370             return (total);
13371         case XPATH_OP_EQUAL:
13372             bakd = ctxt->context->doc;
13373             bak = ctxt->context->node;
13374             pp = ctxt->context->proximityPosition;
13375             cs = ctxt->context->contextSize;
13376             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13377             CHECK_ERROR0;
13378             ctxt->context->doc = bakd;
13379             ctxt->context->node = bak;
13380             ctxt->context->proximityPosition = pp;
13381             ctxt->context->contextSize = cs;
13382             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13383             CHECK_ERROR0;
13384             if (op->value)
13385                 equal = xmlXPathEqualValues(ctxt);
13386             else
13387                 equal = xmlXPathNotEqualValues(ctxt);
13388             valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13389             return (total);
13390         case XPATH_OP_CMP:
13391             bakd = ctxt->context->doc;
13392             bak = ctxt->context->node;
13393             pp = ctxt->context->proximityPosition;
13394             cs = ctxt->context->contextSize;
13395             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13396             CHECK_ERROR0;
13397             ctxt->context->doc = bakd;
13398             ctxt->context->node = bak;
13399             ctxt->context->proximityPosition = pp;
13400             ctxt->context->contextSize = cs;
13401             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13402             CHECK_ERROR0;
13403             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13404             valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13405             return (total);
13406         case XPATH_OP_PLUS:
13407             bakd = ctxt->context->doc;
13408             bak = ctxt->context->node;
13409             pp = ctxt->context->proximityPosition;
13410             cs = ctxt->context->contextSize;
13411             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13412             CHECK_ERROR0;
13413             if (op->ch2 != -1) {
13414                 ctxt->context->doc = bakd;
13415                 ctxt->context->node = bak;
13416                 ctxt->context->proximityPosition = pp;
13417                 ctxt->context->contextSize = cs;
13418                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13419             }
13420             CHECK_ERROR0;
13421             if (op->value == 0)
13422                 xmlXPathSubValues(ctxt);
13423             else if (op->value == 1)
13424                 xmlXPathAddValues(ctxt);
13425             else if (op->value == 2)
13426                 xmlXPathValueFlipSign(ctxt);
13427             else if (op->value == 3) {
13428                 CAST_TO_NUMBER;
13429                 CHECK_TYPE0(XPATH_NUMBER);
13430             }
13431             return (total);
13432         case XPATH_OP_MULT:
13433             bakd = ctxt->context->doc;
13434             bak = ctxt->context->node;
13435             pp = ctxt->context->proximityPosition;
13436             cs = ctxt->context->contextSize;
13437             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13438             CHECK_ERROR0;
13439             ctxt->context->doc = bakd;
13440             ctxt->context->node = bak;
13441             ctxt->context->proximityPosition = pp;
13442             ctxt->context->contextSize = cs;
13443             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13444             CHECK_ERROR0;
13445             if (op->value == 0)
13446                 xmlXPathMultValues(ctxt);
13447             else if (op->value == 1)
13448                 xmlXPathDivValues(ctxt);
13449             else if (op->value == 2)
13450                 xmlXPathModValues(ctxt);
13451             return (total);
13452         case XPATH_OP_UNION:
13453             bakd = ctxt->context->doc;
13454             bak = ctxt->context->node;
13455             pp = ctxt->context->proximityPosition;
13456             cs = ctxt->context->contextSize;
13457             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13458             CHECK_ERROR0;
13459             ctxt->context->doc = bakd;
13460             ctxt->context->node = bak;
13461             ctxt->context->proximityPosition = pp;
13462             ctxt->context->contextSize = cs;
13463             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13464             CHECK_ERROR0;
13465
13466             arg2 = valuePop(ctxt);
13467             arg1 = valuePop(ctxt);
13468             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13469                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13470                 xmlXPathReleaseObject(ctxt->context, arg1);
13471                 xmlXPathReleaseObject(ctxt->context, arg2);
13472                 XP_ERROR0(XPATH_INVALID_TYPE);
13473             }
13474
13475             if ((arg1->nodesetval == NULL) ||
13476                 ((arg2->nodesetval != NULL) &&
13477                  (arg2->nodesetval->nodeNr != 0)))
13478             {
13479                 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13480                                                         arg2->nodesetval);
13481             }
13482
13483             valuePush(ctxt, arg1);
13484             xmlXPathReleaseObject(ctxt->context, arg2);
13485             return (total);
13486         case XPATH_OP_ROOT:
13487             xmlXPathRoot(ctxt);
13488             return (total);
13489         case XPATH_OP_NODE:
13490             if (op->ch1 != -1)
13491                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13492             CHECK_ERROR0;
13493             if (op->ch2 != -1)
13494                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13495             CHECK_ERROR0;
13496             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13497                 ctxt->context->node));
13498             return (total);
13499         case XPATH_OP_RESET:
13500             if (op->ch1 != -1)
13501                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13502             CHECK_ERROR0;
13503             if (op->ch2 != -1)
13504                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13505             CHECK_ERROR0;
13506             ctxt->context->node = NULL;
13507             return (total);
13508         case XPATH_OP_COLLECT:{
13509                 if (op->ch1 == -1)
13510                     return (total);
13511
13512                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13513                 CHECK_ERROR0;
13514
13515                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13516                 return (total);
13517             }
13518         case XPATH_OP_VALUE:
13519             valuePush(ctxt,
13520                       xmlXPathCacheObjectCopy(ctxt->context,
13521                         (xmlXPathObjectPtr) op->value4));
13522             return (total);
13523         case XPATH_OP_VARIABLE:{
13524                 xmlXPathObjectPtr val;
13525
13526                 if (op->ch1 != -1)
13527                     total +=
13528                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13529                 if (op->value5 == NULL) {
13530                     val = xmlXPathVariableLookup(ctxt->context, op->value4);
13531                     if (val == NULL)
13532                         XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13533                     valuePush(ctxt, val);
13534                 } else {
13535                     const xmlChar *URI;
13536
13537                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13538                     if (URI == NULL) {
13539                         xmlGenericError(xmlGenericErrorContext,
13540             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13541                                     (char *) op->value4, (char *)op->value5);
13542                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13543                         return (total);
13544                     }
13545                     val = xmlXPathVariableLookupNS(ctxt->context,
13546                                                        op->value4, URI);
13547                     if (val == NULL)
13548                         XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
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"