Imported Upstream version 2.9.4
[platform/upstream/libxml2.git] / xpath.c
1 /*
2  * xpath.c: XML Path Language implementation
3  *          XPath is a language for addressing parts of an XML document,
4  *          designed to be used by both XSLT and XPointer
5  *f
6  * Reference: W3C Recommendation 16 November 1999
7  *     http://www.w3.org/TR/1999/REC-xpath-19991116
8  * Public reference:
9  *     http://www.w3.org/TR/xpath
10  *
11  * See Copyright for the status of this software
12  *
13  * Author: daniel@veillard.com
14  *
15  */
16
17 #define IN_LIBXML
18 #include "libxml.h"
19
20 #include <string.h>
21
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
24 #endif
25 #ifdef HAVE_MATH_H
26 #include <math.h>
27 #endif
28 #ifdef HAVE_FLOAT_H
29 #include <float.h>
30 #endif
31 #ifdef HAVE_CTYPE_H
32 #include <ctype.h>
33 #endif
34 #ifdef HAVE_SIGNAL_H
35 #include <signal.h>
36 #endif
37
38 #include <libxml/xmlmemory.h>
39 #include <libxml/tree.h>
40 #include <libxml/valid.h>
41 #include <libxml/xpath.h>
42 #include <libxml/xpathInternals.h>
43 #include <libxml/parserInternals.h>
44 #include <libxml/hash.h>
45 #ifdef LIBXML_XPTR_ENABLED
46 #include <libxml/xpointer.h>
47 #endif
48 #ifdef LIBXML_DEBUG_ENABLED
49 #include <libxml/debugXML.h>
50 #endif
51 #include <libxml/xmlerror.h>
52 #include <libxml/threads.h>
53 #include <libxml/globals.h>
54 #ifdef LIBXML_PATTERN_ENABLED
55 #include <libxml/pattern.h>
56 #endif
57
58 #include "buf.h"
59
60 #ifdef LIBXML_PATTERN_ENABLED
61 #define XPATH_STREAMING
62 #endif
63
64 #define TODO                                                            \
65     xmlGenericError(xmlGenericErrorContext,                             \
66             "Unimplemented block at %s:%d\n",                           \
67             __FILE__, __LINE__);
68
69 /**
70  * WITH_TIM_SORT:
71  *
72  * Use the Timsort algorithm provided in timsort.h to sort
73  * nodeset as this is a great improvement over the old Shell sort
74  * used in xmlXPathNodeSetSort()
75  */
76 #define WITH_TIM_SORT
77
78 /*
79 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
80 * If defined, this will use xmlXPathCmpNodesExt() instead of
81 * xmlXPathCmpNodes(). The new function is optimized comparison of
82 * non-element nodes; actually it will speed up comparison only if
83 * xmlXPathOrderDocElems() was called in order to index the elements of
84 * a tree in document order; Libxslt does such an indexing, thus it will
85 * benefit from this optimization.
86 */
87 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
88
89 /*
90 * XP_OPTIMIZED_FILTER_FIRST:
91 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
92 * in a way, that it stop evaluation at the first node.
93 */
94 #define XP_OPTIMIZED_FILTER_FIRST
95
96 /*
97 * XP_DEBUG_OBJ_USAGE:
98 * Internal flag to enable tracking of how much XPath objects have been
99 * created.
100 */
101 /* #define XP_DEBUG_OBJ_USAGE */
102
103 /*
104  * XPATH_MAX_STEPS:
105  * when compiling an XPath expression we arbitrary limit the maximum
106  * number of step operation in the compiled expression. 1000000 is
107  * an insanely large value which should never be reached under normal
108  * circumstances
109  */
110 #define XPATH_MAX_STEPS 1000000
111
112 /*
113  * XPATH_MAX_STACK_DEPTH:
114  * when evaluating an XPath expression we arbitrary limit the maximum
115  * number of object allowed to be pushed on the stack. 1000000 is
116  * an insanely large value which should never be reached under normal
117  * circumstances
118  */
119 #define XPATH_MAX_STACK_DEPTH 1000000
120
121 /*
122  * XPATH_MAX_NODESET_LENGTH:
123  * when evaluating an XPath expression nodesets are created and we
124  * arbitrary limit the maximum length of those node set. 10000000 is
125  * an insanely large value which should never be reached under normal
126  * circumstances, one would first need to construct an in memory tree
127  * with more than 10 millions nodes.
128  */
129 #define XPATH_MAX_NODESET_LENGTH 10000000
130
131 /*
132  * TODO:
133  * There are a few spots where some tests are done which depend upon ascii
134  * data.  These should be enhanced for full UTF8 support (see particularly
135  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
136  */
137
138 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
139 /**
140  * xmlXPathCmpNodesExt:
141  * @node1:  the first node
142  * @node2:  the second node
143  *
144  * Compare two nodes w.r.t document order.
145  * This one is optimized for handling of non-element nodes.
146  *
147  * Returns -2 in case of error 1 if first point < second point, 0 if
148  *         it's the same node, -1 otherwise
149  */
150 static int
151 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
152     int depth1, depth2;
153     int misc = 0, precedence1 = 0, precedence2 = 0;
154     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
155     xmlNodePtr cur, root;
156     long l1, l2;
157
158     if ((node1 == NULL) || (node2 == NULL))
159         return(-2);
160
161     if (node1 == node2)
162         return(0);
163
164     /*
165      * a couple of optimizations which will avoid computations in most cases
166      */
167     switch (node1->type) {
168         case XML_ELEMENT_NODE:
169             if (node2->type == XML_ELEMENT_NODE) {
170                 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
171                     (0 > (long) node2->content) &&
172                     (node1->doc == node2->doc))
173                 {
174                     l1 = -((long) node1->content);
175                     l2 = -((long) node2->content);
176                     if (l1 < l2)
177                         return(1);
178                     if (l1 > l2)
179                         return(-1);
180                 } else
181                     goto turtle_comparison;
182             }
183             break;
184         case XML_ATTRIBUTE_NODE:
185             precedence1 = 1; /* element is owner */
186             miscNode1 = node1;
187             node1 = node1->parent;
188             misc = 1;
189             break;
190         case XML_TEXT_NODE:
191         case XML_CDATA_SECTION_NODE:
192         case XML_COMMENT_NODE:
193         case XML_PI_NODE: {
194             miscNode1 = node1;
195             /*
196             * Find nearest element node.
197             */
198             if (node1->prev != NULL) {
199                 do {
200                     node1 = node1->prev;
201                     if (node1->type == XML_ELEMENT_NODE) {
202                         precedence1 = 3; /* element in prev-sibl axis */
203                         break;
204                     }
205                     if (node1->prev == NULL) {
206                         precedence1 = 2; /* element is parent */
207                         /*
208                         * URGENT TODO: Are there any cases, where the
209                         * parent of such a node is not an element node?
210                         */
211                         node1 = node1->parent;
212                         break;
213                     }
214                 } while (1);
215             } else {
216                 precedence1 = 2; /* element is parent */
217                 node1 = node1->parent;
218             }
219             if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
220                 (0 <= (long) node1->content)) {
221                 /*
222                 * Fallback for whatever case.
223                 */
224                 node1 = miscNode1;
225                 precedence1 = 0;
226             } else
227                 misc = 1;
228         }
229             break;
230         case XML_NAMESPACE_DECL:
231             /*
232             * TODO: why do we return 1 for namespace nodes?
233             */
234             return(1);
235         default:
236             break;
237     }
238     switch (node2->type) {
239         case XML_ELEMENT_NODE:
240             break;
241         case XML_ATTRIBUTE_NODE:
242             precedence2 = 1; /* element is owner */
243             miscNode2 = node2;
244             node2 = node2->parent;
245             misc = 1;
246             break;
247         case XML_TEXT_NODE:
248         case XML_CDATA_SECTION_NODE:
249         case XML_COMMENT_NODE:
250         case XML_PI_NODE: {
251             miscNode2 = node2;
252             if (node2->prev != NULL) {
253                 do {
254                     node2 = node2->prev;
255                     if (node2->type == XML_ELEMENT_NODE) {
256                         precedence2 = 3; /* element in prev-sibl axis */
257                         break;
258                     }
259                     if (node2->prev == NULL) {
260                         precedence2 = 2; /* element is parent */
261                         node2 = node2->parent;
262                         break;
263                     }
264                 } while (1);
265             } else {
266                 precedence2 = 2; /* element is parent */
267                 node2 = node2->parent;
268             }
269             if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
270                 (0 <= (long) node2->content))
271             {
272                 node2 = miscNode2;
273                 precedence2 = 0;
274             } else
275                 misc = 1;
276         }
277             break;
278         case XML_NAMESPACE_DECL:
279             return(1);
280         default:
281             break;
282     }
283     if (misc) {
284         if (node1 == node2) {
285             if (precedence1 == precedence2) {
286                 /*
287                 * The ugly case; but normally there aren't many
288                 * adjacent non-element nodes around.
289                 */
290                 cur = miscNode2->prev;
291                 while (cur != NULL) {
292                     if (cur == miscNode1)
293                         return(1);
294                     if (cur->type == XML_ELEMENT_NODE)
295                         return(-1);
296                     cur = cur->prev;
297                 }
298                 return (-1);
299             } else {
300                 /*
301                 * Evaluate based on higher precedence wrt to the element.
302                 * TODO: This assumes attributes are sorted before content.
303                 *   Is this 100% correct?
304                 */
305                 if (precedence1 < precedence2)
306                     return(1);
307                 else
308                     return(-1);
309             }
310         }
311         /*
312         * Special case: One of the helper-elements is contained by the other.
313         * <foo>
314         *   <node2>
315         *     <node1>Text-1(precedence1 == 2)</node1>
316         *   </node2>
317         *   Text-6(precedence2 == 3)
318         * </foo>
319         */
320         if ((precedence2 == 3) && (precedence1 > 1)) {
321             cur = node1->parent;
322             while (cur) {
323                 if (cur == node2)
324                     return(1);
325                 cur = cur->parent;
326             }
327         }
328         if ((precedence1 == 3) && (precedence2 > 1)) {
329             cur = node2->parent;
330             while (cur) {
331                 if (cur == node1)
332                     return(-1);
333                 cur = cur->parent;
334             }
335         }
336     }
337
338     /*
339      * Speedup using document order if availble.
340      */
341     if ((node1->type == XML_ELEMENT_NODE) &&
342         (node2->type == XML_ELEMENT_NODE) &&
343         (0 > (long) node1->content) &&
344         (0 > (long) node2->content) &&
345         (node1->doc == node2->doc)) {
346
347         l1 = -((long) node1->content);
348         l2 = -((long) node2->content);
349         if (l1 < l2)
350             return(1);
351         if (l1 > l2)
352             return(-1);
353     }
354
355 turtle_comparison:
356
357     if (node1 == node2->prev)
358         return(1);
359     if (node1 == node2->next)
360         return(-1);
361     /*
362      * compute depth to root
363      */
364     for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
365         if (cur->parent == node1)
366             return(1);
367         depth2++;
368     }
369     root = cur;
370     for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
371         if (cur->parent == node2)
372             return(-1);
373         depth1++;
374     }
375     /*
376      * Distinct document (or distinct entities :-( ) case.
377      */
378     if (root != cur) {
379         return(-2);
380     }
381     /*
382      * get the nearest common ancestor.
383      */
384     while (depth1 > depth2) {
385         depth1--;
386         node1 = node1->parent;
387     }
388     while (depth2 > depth1) {
389         depth2--;
390         node2 = node2->parent;
391     }
392     while (node1->parent != node2->parent) {
393         node1 = node1->parent;
394         node2 = node2->parent;
395         /* should not happen but just in case ... */
396         if ((node1 == NULL) || (node2 == NULL))
397             return(-2);
398     }
399     /*
400      * Find who's first.
401      */
402     if (node1 == node2->prev)
403         return(1);
404     if (node1 == node2->next)
405         return(-1);
406     /*
407      * Speedup using document order if availble.
408      */
409     if ((node1->type == XML_ELEMENT_NODE) &&
410         (node2->type == XML_ELEMENT_NODE) &&
411         (0 > (long) node1->content) &&
412         (0 > (long) node2->content) &&
413         (node1->doc == node2->doc)) {
414
415         l1 = -((long) node1->content);
416         l2 = -((long) node2->content);
417         if (l1 < l2)
418             return(1);
419         if (l1 > l2)
420             return(-1);
421     }
422
423     for (cur = node1->next;cur != NULL;cur = cur->next)
424         if (cur == node2)
425             return(1);
426     return(-1); /* assume there is no sibling list corruption */
427 }
428 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
429
430 /*
431  * Wrapper for the Timsort argorithm from timsort.h
432  */
433 #ifdef WITH_TIM_SORT
434 #define SORT_NAME libxml_domnode
435 #define SORT_TYPE xmlNodePtr
436 /**
437  * wrap_cmp:
438  * @x: a node
439  * @y: another node
440  *
441  * Comparison function for the Timsort implementation
442  *
443  * Returns -2 in case of error -1 if first point < second point, 0 if
444  *         it's the same node, +1 otherwise
445  */
446 static
447 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
448 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
449     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
450     {
451         int res = xmlXPathCmpNodesExt(x, y);
452         return res == -2 ? res : -res;
453     }
454 #else
455     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
456     {
457         int res = xmlXPathCmpNodes(x, y);
458         return res == -2 ? res : -res;
459     }
460 #endif
461 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
462 #include "timsort.h"
463 #endif /* WITH_TIM_SORT */
464
465 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
466
467 /************************************************************************
468  *                                                                      *
469  *                      Floating point stuff                            *
470  *                                                                      *
471  ************************************************************************/
472
473 #ifndef TRIO_REPLACE_STDIO
474 #define TRIO_PUBLIC static
475 #endif
476 #include "trionan.c"
477
478 /*
479  * The lack of portability of this section of the libc is annoying !
480  */
481 double xmlXPathNAN = 0;
482 double xmlXPathPINF = 1;
483 double xmlXPathNINF = -1;
484 static double xmlXPathNZERO = 0; /* not exported from headers */
485 static int xmlXPathInitialized = 0;
486
487 /**
488  * xmlXPathInit:
489  *
490  * Initialize the XPath environment
491  */
492 void
493 xmlXPathInit(void) {
494     if (xmlXPathInitialized) return;
495
496     xmlXPathPINF = trio_pinf();
497     xmlXPathNINF = trio_ninf();
498     xmlXPathNAN = trio_nan();
499     xmlXPathNZERO = trio_nzero();
500
501     xmlXPathInitialized = 1;
502 }
503
504 /**
505  * xmlXPathIsNaN:
506  * @val:  a double value
507  *
508  * Provides a portable isnan() function to detect whether a double
509  * is a NotaNumber. Based on trio code
510  * http://sourceforge.net/projects/ctrio/
511  *
512  * Returns 1 if the value is a NaN, 0 otherwise
513  */
514 int
515 xmlXPathIsNaN(double val) {
516     return(trio_isnan(val));
517 }
518
519 /**
520  * xmlXPathIsInf:
521  * @val:  a double value
522  *
523  * Provides a portable isinf() function to detect whether a double
524  * is a +Infinite or -Infinite. Based on trio code
525  * http://sourceforge.net/projects/ctrio/
526  *
527  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
528  */
529 int
530 xmlXPathIsInf(double val) {
531     return(trio_isinf(val));
532 }
533
534 #endif /* SCHEMAS or XPATH */
535 #ifdef LIBXML_XPATH_ENABLED
536 /**
537  * xmlXPathGetSign:
538  * @val:  a double value
539  *
540  * Provides a portable function to detect the sign of a double
541  * Modified from trio code
542  * http://sourceforge.net/projects/ctrio/
543  *
544  * Returns 1 if the value is Negative, 0 if positive
545  */
546 static int
547 xmlXPathGetSign(double val) {
548     return(trio_signbit(val));
549 }
550
551
552 /*
553  * TODO: when compatibility allows remove all "fake node libxslt" strings
554  *       the test should just be name[0] = ' '
555  */
556 #ifdef DEBUG_XPATH_EXPRESSION
557 #define DEBUG_STEP
558 #define DEBUG_EXPR
559 #define DEBUG_EVAL_COUNTS
560 #endif
561
562 static xmlNs xmlXPathXMLNamespaceStruct = {
563     NULL,
564     XML_NAMESPACE_DECL,
565     XML_XML_NAMESPACE,
566     BAD_CAST "xml",
567     NULL,
568     NULL
569 };
570 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
571 #ifndef LIBXML_THREAD_ENABLED
572 /*
573  * Optimizer is disabled only when threaded apps are detected while
574  * the library ain't compiled for thread safety.
575  */
576 static int xmlXPathDisableOptimizer = 0;
577 #endif
578
579 /************************************************************************
580  *                                                                      *
581  *                      Error handling routines                         *
582  *                                                                      *
583  ************************************************************************/
584
585 /**
586  * XP_ERRORNULL:
587  * @X:  the error code
588  *
589  * Macro to raise an XPath error and return NULL.
590  */
591 #define XP_ERRORNULL(X)                                                 \
592     { xmlXPathErr(ctxt, X); return(NULL); }
593
594 /*
595  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
596  */
597 static const char *xmlXPathErrorMessages[] = {
598     "Ok\n",
599     "Number encoding\n",
600     "Unfinished literal\n",
601     "Start of literal\n",
602     "Expected $ for variable reference\n",
603     "Undefined variable\n",
604     "Invalid predicate\n",
605     "Invalid expression\n",
606     "Missing closing curly brace\n",
607     "Unregistered function\n",
608     "Invalid operand\n",
609     "Invalid type\n",
610     "Invalid number of arguments\n",
611     "Invalid context size\n",
612     "Invalid context position\n",
613     "Memory allocation error\n",
614     "Syntax error\n",
615     "Resource error\n",
616     "Sub resource error\n",
617     "Undefined namespace prefix\n",
618     "Encoding error\n",
619     "Char out of XML range\n",
620     "Invalid or incomplete context\n",
621     "Stack usage error\n",
622     "Forbidden variable\n",
623     "?? Unknown error ??\n"     /* Must be last in the list! */
624 };
625 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
626                    sizeof(xmlXPathErrorMessages[0])) - 1)
627 /**
628  * xmlXPathErrMemory:
629  * @ctxt:  an XPath context
630  * @extra:  extra informations
631  *
632  * Handle a redefinition of attribute error
633  */
634 static void
635 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
636 {
637     if (ctxt != NULL) {
638         if (extra) {
639             xmlChar buf[200];
640
641             xmlStrPrintf(buf, 200,
642                          "Memory allocation failed : %s\n",
643                          extra);
644             ctxt->lastError.message = (char *) xmlStrdup(buf);
645         } else {
646             ctxt->lastError.message = (char *)
647                xmlStrdup(BAD_CAST "Memory allocation failed\n");
648         }
649         ctxt->lastError.domain = XML_FROM_XPATH;
650         ctxt->lastError.code = XML_ERR_NO_MEMORY;
651         if (ctxt->error != NULL)
652             ctxt->error(ctxt->userData, &ctxt->lastError);
653     } else {
654         if (extra)
655             __xmlRaiseError(NULL, NULL, NULL,
656                             NULL, NULL, XML_FROM_XPATH,
657                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
658                             extra, NULL, NULL, 0, 0,
659                             "Memory allocation failed : %s\n", extra);
660         else
661             __xmlRaiseError(NULL, NULL, NULL,
662                             NULL, NULL, XML_FROM_XPATH,
663                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
664                             NULL, NULL, NULL, 0, 0,
665                             "Memory allocation failed\n");
666     }
667 }
668
669 /**
670  * xmlXPathPErrMemory:
671  * @ctxt:  an XPath parser context
672  * @extra:  extra informations
673  *
674  * Handle a redefinition of attribute error
675  */
676 static void
677 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
678 {
679     if (ctxt == NULL)
680         xmlXPathErrMemory(NULL, extra);
681     else {
682         ctxt->error = XPATH_MEMORY_ERROR;
683         xmlXPathErrMemory(ctxt->context, extra);
684     }
685 }
686
687 /**
688  * xmlXPathErr:
689  * @ctxt:  a XPath parser context
690  * @error:  the error code
691  *
692  * Handle an XPath error
693  */
694 void
695 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
696 {
697     if ((error < 0) || (error > MAXERRNO))
698         error = MAXERRNO;
699     if (ctxt == NULL) {
700         __xmlRaiseError(NULL, NULL, NULL,
701                         NULL, NULL, XML_FROM_XPATH,
702                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
703                         XML_ERR_ERROR, NULL, 0,
704                         NULL, NULL, NULL, 0, 0,
705                         "%s", xmlXPathErrorMessages[error]);
706         return;
707     }
708     ctxt->error = error;
709     if (ctxt->context == NULL) {
710         __xmlRaiseError(NULL, NULL, NULL,
711                         NULL, NULL, XML_FROM_XPATH,
712                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
713                         XML_ERR_ERROR, NULL, 0,
714                         (const char *) ctxt->base, NULL, NULL,
715                         ctxt->cur - ctxt->base, 0,
716                         "%s", xmlXPathErrorMessages[error]);
717         return;
718     }
719
720     /* cleanup current last error */
721     xmlResetError(&ctxt->context->lastError);
722
723     ctxt->context->lastError.domain = XML_FROM_XPATH;
724     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
725                            XPATH_EXPRESSION_OK;
726     ctxt->context->lastError.level = XML_ERR_ERROR;
727     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
728     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
729     ctxt->context->lastError.node = ctxt->context->debugNode;
730     if (ctxt->context->error != NULL) {
731         ctxt->context->error(ctxt->context->userData,
732                              &ctxt->context->lastError);
733     } else {
734         __xmlRaiseError(NULL, NULL, NULL,
735                         NULL, ctxt->context->debugNode, XML_FROM_XPATH,
736                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
737                         XML_ERR_ERROR, NULL, 0,
738                         (const char *) ctxt->base, NULL, NULL,
739                         ctxt->cur - ctxt->base, 0,
740                         "%s", xmlXPathErrorMessages[error]);
741     }
742
743 }
744
745 /**
746  * xmlXPatherror:
747  * @ctxt:  the XPath Parser context
748  * @file:  the file name
749  * @line:  the line number
750  * @no:  the error number
751  *
752  * Formats an error message.
753  */
754 void
755 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
756               int line ATTRIBUTE_UNUSED, int no) {
757     xmlXPathErr(ctxt, no);
758 }
759
760 /************************************************************************
761  *                                                                      *
762  *                      Utilities                                       *
763  *                                                                      *
764  ************************************************************************/
765
766 /**
767  * xsltPointerList:
768  *
769  * Pointer-list for various purposes.
770  */
771 typedef struct _xmlPointerList xmlPointerList;
772 typedef xmlPointerList *xmlPointerListPtr;
773 struct _xmlPointerList {
774     void **items;
775     int number;
776     int size;
777 };
778 /*
779 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
780 * and here, we should make the functions public.
781 */
782 static int
783 xmlPointerListAddSize(xmlPointerListPtr list,
784                        void *item,
785                        int initialSize)
786 {
787     if (list->items == NULL) {
788         if (initialSize <= 0)
789             initialSize = 1;
790         list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
791         if (list->items == NULL) {
792             xmlXPathErrMemory(NULL,
793                 "xmlPointerListCreate: allocating item\n");
794             return(-1);
795         }
796         list->number = 0;
797         list->size = initialSize;
798     } else if (list->size <= list->number) {
799         if (list->size > 50000000) {
800             xmlXPathErrMemory(NULL,
801                 "xmlPointerListAddSize: re-allocating item\n");
802             return(-1);
803         }
804         list->size *= 2;
805         list->items = (void **) xmlRealloc(list->items,
806             list->size * sizeof(void *));
807         if (list->items == NULL) {
808             xmlXPathErrMemory(NULL,
809                 "xmlPointerListAddSize: re-allocating item\n");
810             list->size = 0;
811             return(-1);
812         }
813     }
814     list->items[list->number++] = item;
815     return(0);
816 }
817
818 /**
819  * xsltPointerListCreate:
820  *
821  * Creates an xsltPointerList structure.
822  *
823  * Returns a xsltPointerList structure or NULL in case of an error.
824  */
825 static xmlPointerListPtr
826 xmlPointerListCreate(int initialSize)
827 {
828     xmlPointerListPtr ret;
829
830     ret = xmlMalloc(sizeof(xmlPointerList));
831     if (ret == NULL) {
832         xmlXPathErrMemory(NULL,
833             "xmlPointerListCreate: allocating item\n");
834         return (NULL);
835     }
836     memset(ret, 0, sizeof(xmlPointerList));
837     if (initialSize > 0) {
838         xmlPointerListAddSize(ret, NULL, initialSize);
839         ret->number = 0;
840     }
841     return (ret);
842 }
843
844 /**
845  * xsltPointerListFree:
846  *
847  * Frees the xsltPointerList structure. This does not free
848  * the content of the list.
849  */
850 static void
851 xmlPointerListFree(xmlPointerListPtr list)
852 {
853     if (list == NULL)
854         return;
855     if (list->items != NULL)
856         xmlFree(list->items);
857     xmlFree(list);
858 }
859
860 /************************************************************************
861  *                                                                      *
862  *                      Parser Types                                    *
863  *                                                                      *
864  ************************************************************************/
865
866 /*
867  * Types are private:
868  */
869
870 typedef enum {
871     XPATH_OP_END=0,
872     XPATH_OP_AND,
873     XPATH_OP_OR,
874     XPATH_OP_EQUAL,
875     XPATH_OP_CMP,
876     XPATH_OP_PLUS,
877     XPATH_OP_MULT,
878     XPATH_OP_UNION,
879     XPATH_OP_ROOT,
880     XPATH_OP_NODE,
881     XPATH_OP_RESET, /* 10 */
882     XPATH_OP_COLLECT,
883     XPATH_OP_VALUE, /* 12 */
884     XPATH_OP_VARIABLE,
885     XPATH_OP_FUNCTION,
886     XPATH_OP_ARG,
887     XPATH_OP_PREDICATE,
888     XPATH_OP_FILTER, /* 17 */
889     XPATH_OP_SORT /* 18 */
890 #ifdef LIBXML_XPTR_ENABLED
891     ,XPATH_OP_RANGETO
892 #endif
893 } xmlXPathOp;
894
895 typedef enum {
896     AXIS_ANCESTOR = 1,
897     AXIS_ANCESTOR_OR_SELF,
898     AXIS_ATTRIBUTE,
899     AXIS_CHILD,
900     AXIS_DESCENDANT,
901     AXIS_DESCENDANT_OR_SELF,
902     AXIS_FOLLOWING,
903     AXIS_FOLLOWING_SIBLING,
904     AXIS_NAMESPACE,
905     AXIS_PARENT,
906     AXIS_PRECEDING,
907     AXIS_PRECEDING_SIBLING,
908     AXIS_SELF
909 } xmlXPathAxisVal;
910
911 typedef enum {
912     NODE_TEST_NONE = 0,
913     NODE_TEST_TYPE = 1,
914     NODE_TEST_PI = 2,
915     NODE_TEST_ALL = 3,
916     NODE_TEST_NS = 4,
917     NODE_TEST_NAME = 5
918 } xmlXPathTestVal;
919
920 typedef enum {
921     NODE_TYPE_NODE = 0,
922     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
923     NODE_TYPE_TEXT = XML_TEXT_NODE,
924     NODE_TYPE_PI = XML_PI_NODE
925 } xmlXPathTypeVal;
926
927 typedef struct _xmlXPathStepOp xmlXPathStepOp;
928 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
929 struct _xmlXPathStepOp {
930     xmlXPathOp op;              /* The identifier of the operation */
931     int ch1;                    /* First child */
932     int ch2;                    /* Second child */
933     int value;
934     int value2;
935     int value3;
936     void *value4;
937     void *value5;
938     void *cache;
939     void *cacheURI;
940 };
941
942 struct _xmlXPathCompExpr {
943     int nbStep;                 /* Number of steps in this expression */
944     int maxStep;                /* Maximum number of steps allocated */
945     xmlXPathStepOp *steps;      /* ops for computation of this expression */
946     int last;                   /* index of last step in expression */
947     xmlChar *expr;              /* the expression being computed */
948     xmlDictPtr dict;            /* the dictionary to use if any */
949 #ifdef DEBUG_EVAL_COUNTS
950     int nb;
951     xmlChar *string;
952 #endif
953 #ifdef XPATH_STREAMING
954     xmlPatternPtr stream;
955 #endif
956 };
957
958 /************************************************************************
959  *                                                                      *
960  *                      Forward declarations                            *
961  *                                                                      *
962  ************************************************************************/
963 static void
964 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
965 static void
966 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
967 static int
968 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
969                         xmlXPathStepOpPtr op, xmlNodePtr *first);
970 static int
971 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
972                             xmlXPathStepOpPtr op,
973                             int isPredicate);
974
975 /************************************************************************
976  *                                                                      *
977  *                      Parser Type functions                           *
978  *                                                                      *
979  ************************************************************************/
980
981 /**
982  * xmlXPathNewCompExpr:
983  *
984  * Create a new Xpath component
985  *
986  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
987  */
988 static xmlXPathCompExprPtr
989 xmlXPathNewCompExpr(void) {
990     xmlXPathCompExprPtr cur;
991
992     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
993     if (cur == NULL) {
994         xmlXPathErrMemory(NULL, "allocating component\n");
995         return(NULL);
996     }
997     memset(cur, 0, sizeof(xmlXPathCompExpr));
998     cur->maxStep = 10;
999     cur->nbStep = 0;
1000     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1001                                            sizeof(xmlXPathStepOp));
1002     if (cur->steps == NULL) {
1003         xmlXPathErrMemory(NULL, "allocating steps\n");
1004         xmlFree(cur);
1005         return(NULL);
1006     }
1007     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1008     cur->last = -1;
1009 #ifdef DEBUG_EVAL_COUNTS
1010     cur->nb = 0;
1011 #endif
1012     return(cur);
1013 }
1014
1015 /**
1016  * xmlXPathFreeCompExpr:
1017  * @comp:  an XPATH comp
1018  *
1019  * Free up the memory allocated by @comp
1020  */
1021 void
1022 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1023 {
1024     xmlXPathStepOpPtr op;
1025     int i;
1026
1027     if (comp == NULL)
1028         return;
1029     if (comp->dict == NULL) {
1030         for (i = 0; i < comp->nbStep; i++) {
1031             op = &comp->steps[i];
1032             if (op->value4 != NULL) {
1033                 if (op->op == XPATH_OP_VALUE)
1034                     xmlXPathFreeObject(op->value4);
1035                 else
1036                     xmlFree(op->value4);
1037             }
1038             if (op->value5 != NULL)
1039                 xmlFree(op->value5);
1040         }
1041     } else {
1042         for (i = 0; i < comp->nbStep; i++) {
1043             op = &comp->steps[i];
1044             if (op->value4 != NULL) {
1045                 if (op->op == XPATH_OP_VALUE)
1046                     xmlXPathFreeObject(op->value4);
1047             }
1048         }
1049         xmlDictFree(comp->dict);
1050     }
1051     if (comp->steps != NULL) {
1052         xmlFree(comp->steps);
1053     }
1054 #ifdef DEBUG_EVAL_COUNTS
1055     if (comp->string != NULL) {
1056         xmlFree(comp->string);
1057     }
1058 #endif
1059 #ifdef XPATH_STREAMING
1060     if (comp->stream != NULL) {
1061         xmlFreePatternList(comp->stream);
1062     }
1063 #endif
1064     if (comp->expr != NULL) {
1065         xmlFree(comp->expr);
1066     }
1067
1068     xmlFree(comp);
1069 }
1070
1071 /**
1072  * xmlXPathCompExprAdd:
1073  * @comp:  the compiled expression
1074  * @ch1: first child index
1075  * @ch2: second child index
1076  * @op:  an op
1077  * @value:  the first int value
1078  * @value2:  the second int value
1079  * @value3:  the third int value
1080  * @value4:  the first string value
1081  * @value5:  the second string value
1082  *
1083  * Add a step to an XPath Compiled Expression
1084  *
1085  * Returns -1 in case of failure, the index otherwise
1086  */
1087 static int
1088 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1089    xmlXPathOp op, int value,
1090    int value2, int value3, void *value4, void *value5) {
1091     if (comp->nbStep >= comp->maxStep) {
1092         xmlXPathStepOp *real;
1093
1094         if (comp->maxStep >= XPATH_MAX_STEPS) {
1095             xmlXPathErrMemory(NULL, "adding step\n");
1096             return(-1);
1097         }
1098         comp->maxStep *= 2;
1099         real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1100                                       comp->maxStep * sizeof(xmlXPathStepOp));
1101         if (real == NULL) {
1102             comp->maxStep /= 2;
1103             xmlXPathErrMemory(NULL, "adding step\n");
1104             return(-1);
1105         }
1106         comp->steps = real;
1107     }
1108     comp->last = comp->nbStep;
1109     comp->steps[comp->nbStep].ch1 = ch1;
1110     comp->steps[comp->nbStep].ch2 = ch2;
1111     comp->steps[comp->nbStep].op = op;
1112     comp->steps[comp->nbStep].value = value;
1113     comp->steps[comp->nbStep].value2 = value2;
1114     comp->steps[comp->nbStep].value3 = value3;
1115     if ((comp->dict != NULL) &&
1116         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1117          (op == XPATH_OP_COLLECT))) {
1118         if (value4 != NULL) {
1119             comp->steps[comp->nbStep].value4 = (xmlChar *)
1120                 (void *)xmlDictLookup(comp->dict, value4, -1);
1121             xmlFree(value4);
1122         } else
1123             comp->steps[comp->nbStep].value4 = NULL;
1124         if (value5 != NULL) {
1125             comp->steps[comp->nbStep].value5 = (xmlChar *)
1126                 (void *)xmlDictLookup(comp->dict, value5, -1);
1127             xmlFree(value5);
1128         } else
1129             comp->steps[comp->nbStep].value5 = NULL;
1130     } else {
1131         comp->steps[comp->nbStep].value4 = value4;
1132         comp->steps[comp->nbStep].value5 = value5;
1133     }
1134     comp->steps[comp->nbStep].cache = NULL;
1135     return(comp->nbStep++);
1136 }
1137
1138 /**
1139  * xmlXPathCompSwap:
1140  * @comp:  the compiled expression
1141  * @op: operation index
1142  *
1143  * Swaps 2 operations in the compiled expression
1144  */
1145 static void
1146 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1147     int tmp;
1148
1149 #ifndef LIBXML_THREAD_ENABLED
1150     /*
1151      * Since this manipulates possibly shared variables, this is
1152      * disabled if one detects that the library is used in a multithreaded
1153      * application
1154      */
1155     if (xmlXPathDisableOptimizer)
1156         return;
1157 #endif
1158
1159     tmp = op->ch1;
1160     op->ch1 = op->ch2;
1161     op->ch2 = tmp;
1162 }
1163
1164 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)       \
1165     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),                       \
1166                         (op), (val), (val2), (val3), (val4), (val5))
1167 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)                 \
1168     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,               \
1169                         (op), (val), (val2), (val3), (val4), (val5))
1170
1171 #define PUSH_LEAVE_EXPR(op, val, val2)                                  \
1172 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1173
1174 #define PUSH_UNARY_EXPR(op, ch, val, val2)                              \
1175 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1176
1177 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)                       \
1178 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),                     \
1179                         (val), (val2), 0 ,NULL ,NULL)
1180
1181 /************************************************************************
1182  *                                                                      *
1183  *              XPath object cache structures                           *
1184  *                                                                      *
1185  ************************************************************************/
1186
1187 /* #define XP_DEFAULT_CACHE_ON */
1188
1189 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1190
1191 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1192 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1193 struct _xmlXPathContextCache {
1194     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1195     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1196     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1197     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1198     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1199     int maxNodeset;
1200     int maxString;
1201     int maxBoolean;
1202     int maxNumber;
1203     int maxMisc;
1204 #ifdef XP_DEBUG_OBJ_USAGE
1205     int dbgCachedAll;
1206     int dbgCachedNodeset;
1207     int dbgCachedString;
1208     int dbgCachedBool;
1209     int dbgCachedNumber;
1210     int dbgCachedPoint;
1211     int dbgCachedRange;
1212     int dbgCachedLocset;
1213     int dbgCachedUsers;
1214     int dbgCachedXSLTTree;
1215     int dbgCachedUndefined;
1216
1217
1218     int dbgReusedAll;
1219     int dbgReusedNodeset;
1220     int dbgReusedString;
1221     int dbgReusedBool;
1222     int dbgReusedNumber;
1223     int dbgReusedPoint;
1224     int dbgReusedRange;
1225     int dbgReusedLocset;
1226     int dbgReusedUsers;
1227     int dbgReusedXSLTTree;
1228     int dbgReusedUndefined;
1229
1230 #endif
1231 };
1232
1233 /************************************************************************
1234  *                                                                      *
1235  *              Debugging related functions                             *
1236  *                                                                      *
1237  ************************************************************************/
1238
1239 #define STRANGE                                                 \
1240     xmlGenericError(xmlGenericErrorContext,                             \
1241             "Internal error at %s:%d\n",                                \
1242             __FILE__, __LINE__);
1243
1244 #ifdef LIBXML_DEBUG_ENABLED
1245 static void
1246 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1247     int i;
1248     char shift[100];
1249
1250     for (i = 0;((i < depth) && (i < 25));i++)
1251         shift[2 * i] = shift[2 * i + 1] = ' ';
1252     shift[2 * i] = shift[2 * i + 1] = 0;
1253     if (cur == NULL) {
1254         fprintf(output, "%s", shift);
1255         fprintf(output, "Node is NULL !\n");
1256         return;
1257
1258     }
1259
1260     if ((cur->type == XML_DOCUMENT_NODE) ||
1261              (cur->type == XML_HTML_DOCUMENT_NODE)) {
1262         fprintf(output, "%s", shift);
1263         fprintf(output, " /\n");
1264     } else if (cur->type == XML_ATTRIBUTE_NODE)
1265         xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1266     else
1267         xmlDebugDumpOneNode(output, cur, depth);
1268 }
1269 static void
1270 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1271     xmlNodePtr tmp;
1272     int i;
1273     char shift[100];
1274
1275     for (i = 0;((i < depth) && (i < 25));i++)
1276         shift[2 * i] = shift[2 * i + 1] = ' ';
1277     shift[2 * i] = shift[2 * i + 1] = 0;
1278     if (cur == NULL) {
1279         fprintf(output, "%s", shift);
1280         fprintf(output, "Node is NULL !\n");
1281         return;
1282
1283     }
1284
1285     while (cur != NULL) {
1286         tmp = cur;
1287         cur = cur->next;
1288         xmlDebugDumpOneNode(output, tmp, depth);
1289     }
1290 }
1291
1292 static void
1293 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1294     int i;
1295     char shift[100];
1296
1297     for (i = 0;((i < depth) && (i < 25));i++)
1298         shift[2 * i] = shift[2 * i + 1] = ' ';
1299     shift[2 * i] = shift[2 * i + 1] = 0;
1300
1301     if (cur == NULL) {
1302         fprintf(output, "%s", shift);
1303         fprintf(output, "NodeSet is NULL !\n");
1304         return;
1305
1306     }
1307
1308     if (cur != NULL) {
1309         fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1310         for (i = 0;i < cur->nodeNr;i++) {
1311             fprintf(output, "%s", shift);
1312             fprintf(output, "%d", i + 1);
1313             xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1314         }
1315     }
1316 }
1317
1318 static void
1319 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1320     int i;
1321     char shift[100];
1322
1323     for (i = 0;((i < depth) && (i < 25));i++)
1324         shift[2 * i] = shift[2 * i + 1] = ' ';
1325     shift[2 * i] = shift[2 * i + 1] = 0;
1326
1327     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1328         fprintf(output, "%s", shift);
1329         fprintf(output, "Value Tree is NULL !\n");
1330         return;
1331
1332     }
1333
1334     fprintf(output, "%s", shift);
1335     fprintf(output, "%d", i + 1);
1336     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1337 }
1338 #if defined(LIBXML_XPTR_ENABLED)
1339 static void
1340 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1341     int i;
1342     char shift[100];
1343
1344     for (i = 0;((i < depth) && (i < 25));i++)
1345         shift[2 * i] = shift[2 * i + 1] = ' ';
1346     shift[2 * i] = shift[2 * i + 1] = 0;
1347
1348     if (cur == NULL) {
1349         fprintf(output, "%s", shift);
1350         fprintf(output, "LocationSet is NULL !\n");
1351         return;
1352
1353     }
1354
1355     for (i = 0;i < cur->locNr;i++) {
1356         fprintf(output, "%s", shift);
1357         fprintf(output, "%d : ", i + 1);
1358         xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1359     }
1360 }
1361 #endif /* LIBXML_XPTR_ENABLED */
1362
1363 /**
1364  * xmlXPathDebugDumpObject:
1365  * @output:  the FILE * to dump the output
1366  * @cur:  the object to inspect
1367  * @depth:  indentation level
1368  *
1369  * Dump the content of the object for debugging purposes
1370  */
1371 void
1372 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1373     int i;
1374     char shift[100];
1375
1376     if (output == NULL) return;
1377
1378     for (i = 0;((i < depth) && (i < 25));i++)
1379         shift[2 * i] = shift[2 * i + 1] = ' ';
1380     shift[2 * i] = shift[2 * i + 1] = 0;
1381
1382
1383     fprintf(output, "%s", shift);
1384
1385     if (cur == NULL) {
1386         fprintf(output, "Object is empty (NULL)\n");
1387         return;
1388     }
1389     switch(cur->type) {
1390         case XPATH_UNDEFINED:
1391             fprintf(output, "Object is uninitialized\n");
1392             break;
1393         case XPATH_NODESET:
1394             fprintf(output, "Object is a Node Set :\n");
1395             xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1396             break;
1397         case XPATH_XSLT_TREE:
1398             fprintf(output, "Object is an XSLT value tree :\n");
1399             xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1400             break;
1401         case XPATH_BOOLEAN:
1402             fprintf(output, "Object is a Boolean : ");
1403             if (cur->boolval) fprintf(output, "true\n");
1404             else fprintf(output, "false\n");
1405             break;
1406         case XPATH_NUMBER:
1407             switch (xmlXPathIsInf(cur->floatval)) {
1408             case 1:
1409                 fprintf(output, "Object is a number : Infinity\n");
1410                 break;
1411             case -1:
1412                 fprintf(output, "Object is a number : -Infinity\n");
1413                 break;
1414             default:
1415                 if (xmlXPathIsNaN(cur->floatval)) {
1416                     fprintf(output, "Object is a number : NaN\n");
1417                 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1418                     fprintf(output, "Object is a number : 0\n");
1419                 } else {
1420                     fprintf(output, "Object is a number : %0g\n", cur->floatval);
1421                 }
1422             }
1423             break;
1424         case XPATH_STRING:
1425             fprintf(output, "Object is a string : ");
1426             xmlDebugDumpString(output, cur->stringval);
1427             fprintf(output, "\n");
1428             break;
1429         case XPATH_POINT:
1430             fprintf(output, "Object is a point : index %d in node", cur->index);
1431             xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1432             fprintf(output, "\n");
1433             break;
1434         case XPATH_RANGE:
1435             if ((cur->user2 == NULL) ||
1436                 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1437                 fprintf(output, "Object is a collapsed range :\n");
1438                 fprintf(output, "%s", shift);
1439                 if (cur->index >= 0)
1440                     fprintf(output, "index %d in ", cur->index);
1441                 fprintf(output, "node\n");
1442                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1443                                       depth + 1);
1444             } else  {
1445                 fprintf(output, "Object is a range :\n");
1446                 fprintf(output, "%s", shift);
1447                 fprintf(output, "From ");
1448                 if (cur->index >= 0)
1449                     fprintf(output, "index %d in ", cur->index);
1450                 fprintf(output, "node\n");
1451                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1452                                       depth + 1);
1453                 fprintf(output, "%s", shift);
1454                 fprintf(output, "To ");
1455                 if (cur->index2 >= 0)
1456                     fprintf(output, "index %d in ", cur->index2);
1457                 fprintf(output, "node\n");
1458                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1459                                       depth + 1);
1460                 fprintf(output, "\n");
1461             }
1462             break;
1463         case XPATH_LOCATIONSET:
1464 #if defined(LIBXML_XPTR_ENABLED)
1465             fprintf(output, "Object is a Location Set:\n");
1466             xmlXPathDebugDumpLocationSet(output,
1467                     (xmlLocationSetPtr) cur->user, depth);
1468 #endif
1469             break;
1470         case XPATH_USERS:
1471             fprintf(output, "Object is user defined\n");
1472             break;
1473     }
1474 }
1475
1476 static void
1477 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1478                              xmlXPathStepOpPtr op, int depth) {
1479     int i;
1480     char shift[100];
1481
1482     for (i = 0;((i < depth) && (i < 25));i++)
1483         shift[2 * i] = shift[2 * i + 1] = ' ';
1484     shift[2 * i] = shift[2 * i + 1] = 0;
1485
1486     fprintf(output, "%s", shift);
1487     if (op == NULL) {
1488         fprintf(output, "Step is NULL\n");
1489         return;
1490     }
1491     switch (op->op) {
1492         case XPATH_OP_END:
1493             fprintf(output, "END"); break;
1494         case XPATH_OP_AND:
1495             fprintf(output, "AND"); break;
1496         case XPATH_OP_OR:
1497             fprintf(output, "OR"); break;
1498         case XPATH_OP_EQUAL:
1499              if (op->value)
1500                  fprintf(output, "EQUAL =");
1501              else
1502                  fprintf(output, "EQUAL !=");
1503              break;
1504         case XPATH_OP_CMP:
1505              if (op->value)
1506                  fprintf(output, "CMP <");
1507              else
1508                  fprintf(output, "CMP >");
1509              if (!op->value2)
1510                  fprintf(output, "=");
1511              break;
1512         case XPATH_OP_PLUS:
1513              if (op->value == 0)
1514                  fprintf(output, "PLUS -");
1515              else if (op->value == 1)
1516                  fprintf(output, "PLUS +");
1517              else if (op->value == 2)
1518                  fprintf(output, "PLUS unary -");
1519              else if (op->value == 3)
1520                  fprintf(output, "PLUS unary - -");
1521              break;
1522         case XPATH_OP_MULT:
1523              if (op->value == 0)
1524                  fprintf(output, "MULT *");
1525              else if (op->value == 1)
1526                  fprintf(output, "MULT div");
1527              else
1528                  fprintf(output, "MULT mod");
1529              break;
1530         case XPATH_OP_UNION:
1531              fprintf(output, "UNION"); break;
1532         case XPATH_OP_ROOT:
1533              fprintf(output, "ROOT"); break;
1534         case XPATH_OP_NODE:
1535              fprintf(output, "NODE"); break;
1536         case XPATH_OP_RESET:
1537              fprintf(output, "RESET"); break;
1538         case XPATH_OP_SORT:
1539              fprintf(output, "SORT"); break;
1540         case XPATH_OP_COLLECT: {
1541             xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1542             xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1543             xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1544             const xmlChar *prefix = op->value4;
1545             const xmlChar *name = op->value5;
1546
1547             fprintf(output, "COLLECT ");
1548             switch (axis) {
1549                 case AXIS_ANCESTOR:
1550                     fprintf(output, " 'ancestors' "); break;
1551                 case AXIS_ANCESTOR_OR_SELF:
1552                     fprintf(output, " 'ancestors-or-self' "); break;
1553                 case AXIS_ATTRIBUTE:
1554                     fprintf(output, " 'attributes' "); break;
1555                 case AXIS_CHILD:
1556                     fprintf(output, " 'child' "); break;
1557                 case AXIS_DESCENDANT:
1558                     fprintf(output, " 'descendant' "); break;
1559                 case AXIS_DESCENDANT_OR_SELF:
1560                     fprintf(output, " 'descendant-or-self' "); break;
1561                 case AXIS_FOLLOWING:
1562                     fprintf(output, " 'following' "); break;
1563                 case AXIS_FOLLOWING_SIBLING:
1564                     fprintf(output, " 'following-siblings' "); break;
1565                 case AXIS_NAMESPACE:
1566                     fprintf(output, " 'namespace' "); break;
1567                 case AXIS_PARENT:
1568                     fprintf(output, " 'parent' "); break;
1569                 case AXIS_PRECEDING:
1570                     fprintf(output, " 'preceding' "); break;
1571                 case AXIS_PRECEDING_SIBLING:
1572                     fprintf(output, " 'preceding-sibling' "); break;
1573                 case AXIS_SELF:
1574                     fprintf(output, " 'self' "); break;
1575             }
1576             switch (test) {
1577                 case NODE_TEST_NONE:
1578                     fprintf(output, "'none' "); break;
1579                 case NODE_TEST_TYPE:
1580                     fprintf(output, "'type' "); break;
1581                 case NODE_TEST_PI:
1582                     fprintf(output, "'PI' "); break;
1583                 case NODE_TEST_ALL:
1584                     fprintf(output, "'all' "); break;
1585                 case NODE_TEST_NS:
1586                     fprintf(output, "'namespace' "); break;
1587                 case NODE_TEST_NAME:
1588                     fprintf(output, "'name' "); break;
1589             }
1590             switch (type) {
1591                 case NODE_TYPE_NODE:
1592                     fprintf(output, "'node' "); break;
1593                 case NODE_TYPE_COMMENT:
1594                     fprintf(output, "'comment' "); break;
1595                 case NODE_TYPE_TEXT:
1596                     fprintf(output, "'text' "); break;
1597                 case NODE_TYPE_PI:
1598                     fprintf(output, "'PI' "); break;
1599             }
1600             if (prefix != NULL)
1601                 fprintf(output, "%s:", prefix);
1602             if (name != NULL)
1603                 fprintf(output, "%s", (const char *) name);
1604             break;
1605
1606         }
1607         case XPATH_OP_VALUE: {
1608             xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1609
1610             fprintf(output, "ELEM ");
1611             xmlXPathDebugDumpObject(output, object, 0);
1612             goto finish;
1613         }
1614         case XPATH_OP_VARIABLE: {
1615             const xmlChar *prefix = op->value5;
1616             const xmlChar *name = op->value4;
1617
1618             if (prefix != NULL)
1619                 fprintf(output, "VARIABLE %s:%s", prefix, name);
1620             else
1621                 fprintf(output, "VARIABLE %s", name);
1622             break;
1623         }
1624         case XPATH_OP_FUNCTION: {
1625             int nbargs = op->value;
1626             const xmlChar *prefix = op->value5;
1627             const xmlChar *name = op->value4;
1628
1629             if (prefix != NULL)
1630                 fprintf(output, "FUNCTION %s:%s(%d args)",
1631                         prefix, name, nbargs);
1632             else
1633                 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1634             break;
1635         }
1636         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1637         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1638         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1639 #ifdef LIBXML_XPTR_ENABLED
1640         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1641 #endif
1642         default:
1643         fprintf(output, "UNKNOWN %d\n", op->op); return;
1644     }
1645     fprintf(output, "\n");
1646 finish:
1647     if (op->ch1 >= 0)
1648         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1649     if (op->ch2 >= 0)
1650         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1651 }
1652
1653 /**
1654  * xmlXPathDebugDumpCompExpr:
1655  * @output:  the FILE * for the output
1656  * @comp:  the precompiled XPath expression
1657  * @depth:  the indentation level.
1658  *
1659  * Dumps the tree of the compiled XPath expression.
1660  */
1661 void
1662 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1663                           int depth) {
1664     int i;
1665     char shift[100];
1666
1667     if ((output == NULL) || (comp == NULL)) return;
1668
1669     for (i = 0;((i < depth) && (i < 25));i++)
1670         shift[2 * i] = shift[2 * i + 1] = ' ';
1671     shift[2 * i] = shift[2 * i + 1] = 0;
1672
1673     fprintf(output, "%s", shift);
1674
1675     fprintf(output, "Compiled Expression : %d elements\n",
1676             comp->nbStep);
1677     i = comp->last;
1678     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1679 }
1680
1681 #ifdef XP_DEBUG_OBJ_USAGE
1682
1683 /*
1684 * XPath object usage related debugging variables.
1685 */
1686 static int xmlXPathDebugObjCounterUndefined = 0;
1687 static int xmlXPathDebugObjCounterNodeset = 0;
1688 static int xmlXPathDebugObjCounterBool = 0;
1689 static int xmlXPathDebugObjCounterNumber = 0;
1690 static int xmlXPathDebugObjCounterString = 0;
1691 static int xmlXPathDebugObjCounterPoint = 0;
1692 static int xmlXPathDebugObjCounterRange = 0;
1693 static int xmlXPathDebugObjCounterLocset = 0;
1694 static int xmlXPathDebugObjCounterUsers = 0;
1695 static int xmlXPathDebugObjCounterXSLTTree = 0;
1696 static int xmlXPathDebugObjCounterAll = 0;
1697
1698 static int xmlXPathDebugObjTotalUndefined = 0;
1699 static int xmlXPathDebugObjTotalNodeset = 0;
1700 static int xmlXPathDebugObjTotalBool = 0;
1701 static int xmlXPathDebugObjTotalNumber = 0;
1702 static int xmlXPathDebugObjTotalString = 0;
1703 static int xmlXPathDebugObjTotalPoint = 0;
1704 static int xmlXPathDebugObjTotalRange = 0;
1705 static int xmlXPathDebugObjTotalLocset = 0;
1706 static int xmlXPathDebugObjTotalUsers = 0;
1707 static int xmlXPathDebugObjTotalXSLTTree = 0;
1708 static int xmlXPathDebugObjTotalAll = 0;
1709
1710 static int xmlXPathDebugObjMaxUndefined = 0;
1711 static int xmlXPathDebugObjMaxNodeset = 0;
1712 static int xmlXPathDebugObjMaxBool = 0;
1713 static int xmlXPathDebugObjMaxNumber = 0;
1714 static int xmlXPathDebugObjMaxString = 0;
1715 static int xmlXPathDebugObjMaxPoint = 0;
1716 static int xmlXPathDebugObjMaxRange = 0;
1717 static int xmlXPathDebugObjMaxLocset = 0;
1718 static int xmlXPathDebugObjMaxUsers = 0;
1719 static int xmlXPathDebugObjMaxXSLTTree = 0;
1720 static int xmlXPathDebugObjMaxAll = 0;
1721
1722 /* REVISIT TODO: Make this static when committing */
1723 static void
1724 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1725 {
1726     if (ctxt != NULL) {
1727         if (ctxt->cache != NULL) {
1728             xmlXPathContextCachePtr cache =
1729                 (xmlXPathContextCachePtr) ctxt->cache;
1730
1731             cache->dbgCachedAll = 0;
1732             cache->dbgCachedNodeset = 0;
1733             cache->dbgCachedString = 0;
1734             cache->dbgCachedBool = 0;
1735             cache->dbgCachedNumber = 0;
1736             cache->dbgCachedPoint = 0;
1737             cache->dbgCachedRange = 0;
1738             cache->dbgCachedLocset = 0;
1739             cache->dbgCachedUsers = 0;
1740             cache->dbgCachedXSLTTree = 0;
1741             cache->dbgCachedUndefined = 0;
1742
1743             cache->dbgReusedAll = 0;
1744             cache->dbgReusedNodeset = 0;
1745             cache->dbgReusedString = 0;
1746             cache->dbgReusedBool = 0;
1747             cache->dbgReusedNumber = 0;
1748             cache->dbgReusedPoint = 0;
1749             cache->dbgReusedRange = 0;
1750             cache->dbgReusedLocset = 0;
1751             cache->dbgReusedUsers = 0;
1752             cache->dbgReusedXSLTTree = 0;
1753             cache->dbgReusedUndefined = 0;
1754         }
1755     }
1756
1757     xmlXPathDebugObjCounterUndefined = 0;
1758     xmlXPathDebugObjCounterNodeset = 0;
1759     xmlXPathDebugObjCounterBool = 0;
1760     xmlXPathDebugObjCounterNumber = 0;
1761     xmlXPathDebugObjCounterString = 0;
1762     xmlXPathDebugObjCounterPoint = 0;
1763     xmlXPathDebugObjCounterRange = 0;
1764     xmlXPathDebugObjCounterLocset = 0;
1765     xmlXPathDebugObjCounterUsers = 0;
1766     xmlXPathDebugObjCounterXSLTTree = 0;
1767     xmlXPathDebugObjCounterAll = 0;
1768
1769     xmlXPathDebugObjTotalUndefined = 0;
1770     xmlXPathDebugObjTotalNodeset = 0;
1771     xmlXPathDebugObjTotalBool = 0;
1772     xmlXPathDebugObjTotalNumber = 0;
1773     xmlXPathDebugObjTotalString = 0;
1774     xmlXPathDebugObjTotalPoint = 0;
1775     xmlXPathDebugObjTotalRange = 0;
1776     xmlXPathDebugObjTotalLocset = 0;
1777     xmlXPathDebugObjTotalUsers = 0;
1778     xmlXPathDebugObjTotalXSLTTree = 0;
1779     xmlXPathDebugObjTotalAll = 0;
1780
1781     xmlXPathDebugObjMaxUndefined = 0;
1782     xmlXPathDebugObjMaxNodeset = 0;
1783     xmlXPathDebugObjMaxBool = 0;
1784     xmlXPathDebugObjMaxNumber = 0;
1785     xmlXPathDebugObjMaxString = 0;
1786     xmlXPathDebugObjMaxPoint = 0;
1787     xmlXPathDebugObjMaxRange = 0;
1788     xmlXPathDebugObjMaxLocset = 0;
1789     xmlXPathDebugObjMaxUsers = 0;
1790     xmlXPathDebugObjMaxXSLTTree = 0;
1791     xmlXPathDebugObjMaxAll = 0;
1792
1793 }
1794
1795 static void
1796 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1797                               xmlXPathObjectType objType)
1798 {
1799     int isCached = 0;
1800
1801     if (ctxt != NULL) {
1802         if (ctxt->cache != NULL) {
1803             xmlXPathContextCachePtr cache =
1804                 (xmlXPathContextCachePtr) ctxt->cache;
1805
1806             isCached = 1;
1807
1808             cache->dbgReusedAll++;
1809             switch (objType) {
1810                 case XPATH_UNDEFINED:
1811                     cache->dbgReusedUndefined++;
1812                     break;
1813                 case XPATH_NODESET:
1814                     cache->dbgReusedNodeset++;
1815                     break;
1816                 case XPATH_BOOLEAN:
1817                     cache->dbgReusedBool++;
1818                     break;
1819                 case XPATH_NUMBER:
1820                     cache->dbgReusedNumber++;
1821                     break;
1822                 case XPATH_STRING:
1823                     cache->dbgReusedString++;
1824                     break;
1825                 case XPATH_POINT:
1826                     cache->dbgReusedPoint++;
1827                     break;
1828                 case XPATH_RANGE:
1829                     cache->dbgReusedRange++;
1830                     break;
1831                 case XPATH_LOCATIONSET:
1832                     cache->dbgReusedLocset++;
1833                     break;
1834                 case XPATH_USERS:
1835                     cache->dbgReusedUsers++;
1836                     break;
1837                 case XPATH_XSLT_TREE:
1838                     cache->dbgReusedXSLTTree++;
1839                     break;
1840                 default:
1841                     break;
1842             }
1843         }
1844     }
1845
1846     switch (objType) {
1847         case XPATH_UNDEFINED:
1848             if (! isCached)
1849                 xmlXPathDebugObjTotalUndefined++;
1850             xmlXPathDebugObjCounterUndefined++;
1851             if (xmlXPathDebugObjCounterUndefined >
1852                 xmlXPathDebugObjMaxUndefined)
1853                 xmlXPathDebugObjMaxUndefined =
1854                     xmlXPathDebugObjCounterUndefined;
1855             break;
1856         case XPATH_NODESET:
1857             if (! isCached)
1858                 xmlXPathDebugObjTotalNodeset++;
1859             xmlXPathDebugObjCounterNodeset++;
1860             if (xmlXPathDebugObjCounterNodeset >
1861                 xmlXPathDebugObjMaxNodeset)
1862                 xmlXPathDebugObjMaxNodeset =
1863                     xmlXPathDebugObjCounterNodeset;
1864             break;
1865         case XPATH_BOOLEAN:
1866             if (! isCached)
1867                 xmlXPathDebugObjTotalBool++;
1868             xmlXPathDebugObjCounterBool++;
1869             if (xmlXPathDebugObjCounterBool >
1870                 xmlXPathDebugObjMaxBool)
1871                 xmlXPathDebugObjMaxBool =
1872                     xmlXPathDebugObjCounterBool;
1873             break;
1874         case XPATH_NUMBER:
1875             if (! isCached)
1876                 xmlXPathDebugObjTotalNumber++;
1877             xmlXPathDebugObjCounterNumber++;
1878             if (xmlXPathDebugObjCounterNumber >
1879                 xmlXPathDebugObjMaxNumber)
1880                 xmlXPathDebugObjMaxNumber =
1881                     xmlXPathDebugObjCounterNumber;
1882             break;
1883         case XPATH_STRING:
1884             if (! isCached)
1885                 xmlXPathDebugObjTotalString++;
1886             xmlXPathDebugObjCounterString++;
1887             if (xmlXPathDebugObjCounterString >
1888                 xmlXPathDebugObjMaxString)
1889                 xmlXPathDebugObjMaxString =
1890                     xmlXPathDebugObjCounterString;
1891             break;
1892         case XPATH_POINT:
1893             if (! isCached)
1894                 xmlXPathDebugObjTotalPoint++;
1895             xmlXPathDebugObjCounterPoint++;
1896             if (xmlXPathDebugObjCounterPoint >
1897                 xmlXPathDebugObjMaxPoint)
1898                 xmlXPathDebugObjMaxPoint =
1899                     xmlXPathDebugObjCounterPoint;
1900             break;
1901         case XPATH_RANGE:
1902             if (! isCached)
1903                 xmlXPathDebugObjTotalRange++;
1904             xmlXPathDebugObjCounterRange++;
1905             if (xmlXPathDebugObjCounterRange >
1906                 xmlXPathDebugObjMaxRange)
1907                 xmlXPathDebugObjMaxRange =
1908                     xmlXPathDebugObjCounterRange;
1909             break;
1910         case XPATH_LOCATIONSET:
1911             if (! isCached)
1912                 xmlXPathDebugObjTotalLocset++;
1913             xmlXPathDebugObjCounterLocset++;
1914             if (xmlXPathDebugObjCounterLocset >
1915                 xmlXPathDebugObjMaxLocset)
1916                 xmlXPathDebugObjMaxLocset =
1917                     xmlXPathDebugObjCounterLocset;
1918             break;
1919         case XPATH_USERS:
1920             if (! isCached)
1921                 xmlXPathDebugObjTotalUsers++;
1922             xmlXPathDebugObjCounterUsers++;
1923             if (xmlXPathDebugObjCounterUsers >
1924                 xmlXPathDebugObjMaxUsers)
1925                 xmlXPathDebugObjMaxUsers =
1926                     xmlXPathDebugObjCounterUsers;
1927             break;
1928         case XPATH_XSLT_TREE:
1929             if (! isCached)
1930                 xmlXPathDebugObjTotalXSLTTree++;
1931             xmlXPathDebugObjCounterXSLTTree++;
1932             if (xmlXPathDebugObjCounterXSLTTree >
1933                 xmlXPathDebugObjMaxXSLTTree)
1934                 xmlXPathDebugObjMaxXSLTTree =
1935                     xmlXPathDebugObjCounterXSLTTree;
1936             break;
1937         default:
1938             break;
1939     }
1940     if (! isCached)
1941         xmlXPathDebugObjTotalAll++;
1942     xmlXPathDebugObjCounterAll++;
1943     if (xmlXPathDebugObjCounterAll >
1944         xmlXPathDebugObjMaxAll)
1945         xmlXPathDebugObjMaxAll =
1946             xmlXPathDebugObjCounterAll;
1947 }
1948
1949 static void
1950 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1951                               xmlXPathObjectType objType)
1952 {
1953     int isCached = 0;
1954
1955     if (ctxt != NULL) {
1956         if (ctxt->cache != NULL) {
1957             xmlXPathContextCachePtr cache =
1958                 (xmlXPathContextCachePtr) ctxt->cache;
1959
1960             isCached = 1;
1961
1962             cache->dbgCachedAll++;
1963             switch (objType) {
1964                 case XPATH_UNDEFINED:
1965                     cache->dbgCachedUndefined++;
1966                     break;
1967                 case XPATH_NODESET:
1968                     cache->dbgCachedNodeset++;
1969                     break;
1970                 case XPATH_BOOLEAN:
1971                     cache->dbgCachedBool++;
1972                     break;
1973                 case XPATH_NUMBER:
1974                     cache->dbgCachedNumber++;
1975                     break;
1976                 case XPATH_STRING:
1977                     cache->dbgCachedString++;
1978                     break;
1979                 case XPATH_POINT:
1980                     cache->dbgCachedPoint++;
1981                     break;
1982                 case XPATH_RANGE:
1983                     cache->dbgCachedRange++;
1984                     break;
1985                 case XPATH_LOCATIONSET:
1986                     cache->dbgCachedLocset++;
1987                     break;
1988                 case XPATH_USERS:
1989                     cache->dbgCachedUsers++;
1990                     break;
1991                 case XPATH_XSLT_TREE:
1992                     cache->dbgCachedXSLTTree++;
1993                     break;
1994                 default:
1995                     break;
1996             }
1997
1998         }
1999     }
2000     switch (objType) {
2001         case XPATH_UNDEFINED:
2002             xmlXPathDebugObjCounterUndefined--;
2003             break;
2004         case XPATH_NODESET:
2005             xmlXPathDebugObjCounterNodeset--;
2006             break;
2007         case XPATH_BOOLEAN:
2008             xmlXPathDebugObjCounterBool--;
2009             break;
2010         case XPATH_NUMBER:
2011             xmlXPathDebugObjCounterNumber--;
2012             break;
2013         case XPATH_STRING:
2014             xmlXPathDebugObjCounterString--;
2015             break;
2016         case XPATH_POINT:
2017             xmlXPathDebugObjCounterPoint--;
2018             break;
2019         case XPATH_RANGE:
2020             xmlXPathDebugObjCounterRange--;
2021             break;
2022         case XPATH_LOCATIONSET:
2023             xmlXPathDebugObjCounterLocset--;
2024             break;
2025         case XPATH_USERS:
2026             xmlXPathDebugObjCounterUsers--;
2027             break;
2028         case XPATH_XSLT_TREE:
2029             xmlXPathDebugObjCounterXSLTTree--;
2030             break;
2031         default:
2032             break;
2033     }
2034     xmlXPathDebugObjCounterAll--;
2035 }
2036
2037 /* REVISIT TODO: Make this static when committing */
2038 static void
2039 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2040 {
2041     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2042         reqXSLTTree, reqUndefined;
2043     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2044         caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2045     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2046         reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2047     int leftObjs = xmlXPathDebugObjCounterAll;
2048
2049     reqAll = xmlXPathDebugObjTotalAll;
2050     reqNodeset = xmlXPathDebugObjTotalNodeset;
2051     reqString = xmlXPathDebugObjTotalString;
2052     reqBool = xmlXPathDebugObjTotalBool;
2053     reqNumber = xmlXPathDebugObjTotalNumber;
2054     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2055     reqUndefined = xmlXPathDebugObjTotalUndefined;
2056
2057     printf("# XPath object usage:\n");
2058
2059     if (ctxt != NULL) {
2060         if (ctxt->cache != NULL) {
2061             xmlXPathContextCachePtr cache =
2062                 (xmlXPathContextCachePtr) ctxt->cache;
2063
2064             reAll = cache->dbgReusedAll;
2065             reqAll += reAll;
2066             reNodeset = cache->dbgReusedNodeset;
2067             reqNodeset += reNodeset;
2068             reString = cache->dbgReusedString;
2069             reqString += reString;
2070             reBool = cache->dbgReusedBool;
2071             reqBool += reBool;
2072             reNumber = cache->dbgReusedNumber;
2073             reqNumber += reNumber;
2074             reXSLTTree = cache->dbgReusedXSLTTree;
2075             reqXSLTTree += reXSLTTree;
2076             reUndefined = cache->dbgReusedUndefined;
2077             reqUndefined += reUndefined;
2078
2079             caAll = cache->dbgCachedAll;
2080             caBool = cache->dbgCachedBool;
2081             caNodeset = cache->dbgCachedNodeset;
2082             caString = cache->dbgCachedString;
2083             caNumber = cache->dbgCachedNumber;
2084             caXSLTTree = cache->dbgCachedXSLTTree;
2085             caUndefined = cache->dbgCachedUndefined;
2086
2087             if (cache->nodesetObjs)
2088                 leftObjs -= cache->nodesetObjs->number;
2089             if (cache->stringObjs)
2090                 leftObjs -= cache->stringObjs->number;
2091             if (cache->booleanObjs)
2092                 leftObjs -= cache->booleanObjs->number;
2093             if (cache->numberObjs)
2094                 leftObjs -= cache->numberObjs->number;
2095             if (cache->miscObjs)
2096                 leftObjs -= cache->miscObjs->number;
2097         }
2098     }
2099
2100     printf("# all\n");
2101     printf("#   total  : %d\n", reqAll);
2102     printf("#   left  : %d\n", leftObjs);
2103     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2104     printf("#   reused : %d\n", reAll);
2105     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2106
2107     printf("# node-sets\n");
2108     printf("#   total  : %d\n", reqNodeset);
2109     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2110     printf("#   reused : %d\n", reNodeset);
2111     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2112
2113     printf("# strings\n");
2114     printf("#   total  : %d\n", reqString);
2115     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2116     printf("#   reused : %d\n", reString);
2117     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2118
2119     printf("# booleans\n");
2120     printf("#   total  : %d\n", reqBool);
2121     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2122     printf("#   reused : %d\n", reBool);
2123     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2124
2125     printf("# numbers\n");
2126     printf("#   total  : %d\n", reqNumber);
2127     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2128     printf("#   reused : %d\n", reNumber);
2129     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2130
2131     printf("# XSLT result tree fragments\n");
2132     printf("#   total  : %d\n", reqXSLTTree);
2133     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2134     printf("#   reused : %d\n", reXSLTTree);
2135     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2136
2137     printf("# undefined\n");
2138     printf("#   total  : %d\n", reqUndefined);
2139     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2140     printf("#   reused : %d\n", reUndefined);
2141     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2142
2143 }
2144
2145 #endif /* XP_DEBUG_OBJ_USAGE */
2146
2147 #endif /* LIBXML_DEBUG_ENABLED */
2148
2149 /************************************************************************
2150  *                                                                      *
2151  *                      XPath object caching                            *
2152  *                                                                      *
2153  ************************************************************************/
2154
2155 /**
2156  * xmlXPathNewCache:
2157  *
2158  * Create a new object cache
2159  *
2160  * Returns the xmlXPathCache just allocated.
2161  */
2162 static xmlXPathContextCachePtr
2163 xmlXPathNewCache(void)
2164 {
2165     xmlXPathContextCachePtr ret;
2166
2167     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2168     if (ret == NULL) {
2169         xmlXPathErrMemory(NULL, "creating object cache\n");
2170         return(NULL);
2171     }
2172     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2173     ret->maxNodeset = 100;
2174     ret->maxString = 100;
2175     ret->maxBoolean = 100;
2176     ret->maxNumber = 100;
2177     ret->maxMisc = 100;
2178     return(ret);
2179 }
2180
2181 static void
2182 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2183 {
2184     int i;
2185     xmlXPathObjectPtr obj;
2186
2187     if (list == NULL)
2188         return;
2189
2190     for (i = 0; i < list->number; i++) {
2191         obj = list->items[i];
2192         /*
2193         * Note that it is already assured that we don't need to
2194         * look out for namespace nodes in the node-set.
2195         */
2196         if (obj->nodesetval != NULL) {
2197             if (obj->nodesetval->nodeTab != NULL)
2198                 xmlFree(obj->nodesetval->nodeTab);
2199             xmlFree(obj->nodesetval);
2200         }
2201         xmlFree(obj);
2202 #ifdef XP_DEBUG_OBJ_USAGE
2203         xmlXPathDebugObjCounterAll--;
2204 #endif
2205     }
2206     xmlPointerListFree(list);
2207 }
2208
2209 static void
2210 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2211 {
2212     if (cache == NULL)
2213         return;
2214     if (cache->nodesetObjs)
2215         xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2216     if (cache->stringObjs)
2217         xmlXPathCacheFreeObjectList(cache->stringObjs);
2218     if (cache->booleanObjs)
2219         xmlXPathCacheFreeObjectList(cache->booleanObjs);
2220     if (cache->numberObjs)
2221         xmlXPathCacheFreeObjectList(cache->numberObjs);
2222     if (cache->miscObjs)
2223         xmlXPathCacheFreeObjectList(cache->miscObjs);
2224     xmlFree(cache);
2225 }
2226
2227 /**
2228  * xmlXPathContextSetCache:
2229  *
2230  * @ctxt:  the XPath context
2231  * @active: enables/disables (creates/frees) the cache
2232  * @value: a value with semantics dependant on @options
2233  * @options: options (currently only the value 0 is used)
2234  *
2235  * Creates/frees an object cache on the XPath context.
2236  * If activates XPath objects (xmlXPathObject) will be cached internally
2237  * to be reused.
2238  * @options:
2239  *   0: This will set the XPath object caching:
2240  *      @value:
2241  *        This will set the maximum number of XPath objects
2242  *        to be cached per slot
2243  *        There are 5 slots for: node-set, string, number, boolean, and
2244  *        misc objects. Use <0 for the default number (100).
2245  *   Other values for @options have currently no effect.
2246  *
2247  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2248  */
2249 int
2250 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2251                         int active,
2252                         int value,
2253                         int options)
2254 {
2255     if (ctxt == NULL)
2256         return(-1);
2257     if (active) {
2258         xmlXPathContextCachePtr cache;
2259
2260         if (ctxt->cache == NULL) {
2261             ctxt->cache = xmlXPathNewCache();
2262             if (ctxt->cache == NULL)
2263                 return(-1);
2264         }
2265         cache = (xmlXPathContextCachePtr) ctxt->cache;
2266         if (options == 0) {
2267             if (value < 0)
2268                 value = 100;
2269             cache->maxNodeset = value;
2270             cache->maxString = value;
2271             cache->maxNumber = value;
2272             cache->maxBoolean = value;
2273             cache->maxMisc = value;
2274         }
2275     } else if (ctxt->cache != NULL) {
2276         xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2277         ctxt->cache = NULL;
2278     }
2279     return(0);
2280 }
2281
2282 /**
2283  * xmlXPathCacheWrapNodeSet:
2284  * @ctxt: the XPath context
2285  * @val:  the NodePtr value
2286  *
2287  * This is the cached version of xmlXPathWrapNodeSet().
2288  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2289  *
2290  * Returns the created or reused object.
2291  */
2292 static xmlXPathObjectPtr
2293 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2294 {
2295     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2296         xmlXPathContextCachePtr cache =
2297             (xmlXPathContextCachePtr) ctxt->cache;
2298
2299         if ((cache->miscObjs != NULL) &&
2300             (cache->miscObjs->number != 0))
2301         {
2302             xmlXPathObjectPtr ret;
2303
2304             ret = (xmlXPathObjectPtr)
2305                 cache->miscObjs->items[--cache->miscObjs->number];
2306             ret->type = XPATH_NODESET;
2307             ret->nodesetval = val;
2308 #ifdef XP_DEBUG_OBJ_USAGE
2309             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2310 #endif
2311             return(ret);
2312         }
2313     }
2314
2315     return(xmlXPathWrapNodeSet(val));
2316
2317 }
2318
2319 /**
2320  * xmlXPathCacheWrapString:
2321  * @ctxt: the XPath context
2322  * @val:  the xmlChar * value
2323  *
2324  * This is the cached version of xmlXPathWrapString().
2325  * Wraps the @val string into an XPath object.
2326  *
2327  * Returns the created or reused object.
2328  */
2329 static xmlXPathObjectPtr
2330 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2331 {
2332     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2333         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2334
2335         if ((cache->stringObjs != NULL) &&
2336             (cache->stringObjs->number != 0))
2337         {
2338
2339             xmlXPathObjectPtr ret;
2340
2341             ret = (xmlXPathObjectPtr)
2342                 cache->stringObjs->items[--cache->stringObjs->number];
2343             ret->type = XPATH_STRING;
2344             ret->stringval = val;
2345 #ifdef XP_DEBUG_OBJ_USAGE
2346             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2347 #endif
2348             return(ret);
2349         } else if ((cache->miscObjs != NULL) &&
2350             (cache->miscObjs->number != 0))
2351         {
2352             xmlXPathObjectPtr ret;
2353             /*
2354             * Fallback to misc-cache.
2355             */
2356             ret = (xmlXPathObjectPtr)
2357                 cache->miscObjs->items[--cache->miscObjs->number];
2358
2359             ret->type = XPATH_STRING;
2360             ret->stringval = val;
2361 #ifdef XP_DEBUG_OBJ_USAGE
2362             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2363 #endif
2364             return(ret);
2365         }
2366     }
2367     return(xmlXPathWrapString(val));
2368 }
2369
2370 /**
2371  * xmlXPathCacheNewNodeSet:
2372  * @ctxt: the XPath context
2373  * @val:  the NodePtr value
2374  *
2375  * This is the cached version of xmlXPathNewNodeSet().
2376  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2377  * it with the single Node @val
2378  *
2379  * Returns the created or reused object.
2380  */
2381 static xmlXPathObjectPtr
2382 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2383 {
2384     if ((ctxt != NULL) && (ctxt->cache)) {
2385         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2386
2387         if ((cache->nodesetObjs != NULL) &&
2388             (cache->nodesetObjs->number != 0))
2389         {
2390             xmlXPathObjectPtr ret;
2391             /*
2392             * Use the nodset-cache.
2393             */
2394             ret = (xmlXPathObjectPtr)
2395                 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2396             ret->type = XPATH_NODESET;
2397             ret->boolval = 0;
2398             if (val) {
2399                 if ((ret->nodesetval->nodeMax == 0) ||
2400                     (val->type == XML_NAMESPACE_DECL))
2401                 {
2402                     xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2403                 } else {
2404                     ret->nodesetval->nodeTab[0] = val;
2405                     ret->nodesetval->nodeNr = 1;
2406                 }
2407             }
2408 #ifdef XP_DEBUG_OBJ_USAGE
2409             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2410 #endif
2411             return(ret);
2412         } else if ((cache->miscObjs != NULL) &&
2413             (cache->miscObjs->number != 0))
2414         {
2415             xmlXPathObjectPtr ret;
2416             /*
2417             * Fallback to misc-cache.
2418             */
2419
2420             ret = (xmlXPathObjectPtr)
2421                 cache->miscObjs->items[--cache->miscObjs->number];
2422
2423             ret->type = XPATH_NODESET;
2424             ret->boolval = 0;
2425             ret->nodesetval = xmlXPathNodeSetCreate(val);
2426             if (ret->nodesetval == NULL) {
2427                 ctxt->lastError.domain = XML_FROM_XPATH;
2428                 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2429                 return(NULL);
2430             }
2431 #ifdef XP_DEBUG_OBJ_USAGE
2432             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2433 #endif
2434             return(ret);
2435         }
2436     }
2437     return(xmlXPathNewNodeSet(val));
2438 }
2439
2440 /**
2441  * xmlXPathCacheNewCString:
2442  * @ctxt: the XPath context
2443  * @val:  the char * value
2444  *
2445  * This is the cached version of xmlXPathNewCString().
2446  * Acquire an xmlXPathObjectPtr of type string and of value @val
2447  *
2448  * Returns the created or reused object.
2449  */
2450 static xmlXPathObjectPtr
2451 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2452 {
2453     if ((ctxt != NULL) && (ctxt->cache)) {
2454         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2455
2456         if ((cache->stringObjs != NULL) &&
2457             (cache->stringObjs->number != 0))
2458         {
2459             xmlXPathObjectPtr ret;
2460
2461             ret = (xmlXPathObjectPtr)
2462                 cache->stringObjs->items[--cache->stringObjs->number];
2463
2464             ret->type = XPATH_STRING;
2465             ret->stringval = xmlStrdup(BAD_CAST val);
2466 #ifdef XP_DEBUG_OBJ_USAGE
2467             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2468 #endif
2469             return(ret);
2470         } else if ((cache->miscObjs != NULL) &&
2471             (cache->miscObjs->number != 0))
2472         {
2473             xmlXPathObjectPtr ret;
2474
2475             ret = (xmlXPathObjectPtr)
2476                 cache->miscObjs->items[--cache->miscObjs->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         }
2485     }
2486     return(xmlXPathNewCString(val));
2487 }
2488
2489 /**
2490  * xmlXPathCacheNewString:
2491  * @ctxt: the XPath context
2492  * @val:  the xmlChar * value
2493  *
2494  * This is the cached version of xmlXPathNewString().
2495  * Acquire an xmlXPathObjectPtr of type string and of value @val
2496  *
2497  * Returns the created or reused object.
2498  */
2499 static xmlXPathObjectPtr
2500 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2501 {
2502     if ((ctxt != NULL) && (ctxt->cache)) {
2503         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2504
2505         if ((cache->stringObjs != NULL) &&
2506             (cache->stringObjs->number != 0))
2507         {
2508             xmlXPathObjectPtr ret;
2509
2510             ret = (xmlXPathObjectPtr)
2511                 cache->stringObjs->items[--cache->stringObjs->number];
2512             ret->type = XPATH_STRING;
2513             if (val != NULL)
2514                 ret->stringval = xmlStrdup(val);
2515             else
2516                 ret->stringval = xmlStrdup((const xmlChar *)"");
2517 #ifdef XP_DEBUG_OBJ_USAGE
2518             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2519 #endif
2520             return(ret);
2521         } else if ((cache->miscObjs != NULL) &&
2522             (cache->miscObjs->number != 0))
2523         {
2524             xmlXPathObjectPtr ret;
2525
2526             ret = (xmlXPathObjectPtr)
2527                 cache->miscObjs->items[--cache->miscObjs->number];
2528
2529             ret->type = XPATH_STRING;
2530             if (val != NULL)
2531                 ret->stringval = xmlStrdup(val);
2532             else
2533                 ret->stringval = xmlStrdup((const xmlChar *)"");
2534 #ifdef XP_DEBUG_OBJ_USAGE
2535             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2536 #endif
2537             return(ret);
2538         }
2539     }
2540     return(xmlXPathNewString(val));
2541 }
2542
2543 /**
2544  * xmlXPathCacheNewBoolean:
2545  * @ctxt: the XPath context
2546  * @val:  the boolean value
2547  *
2548  * This is the cached version of xmlXPathNewBoolean().
2549  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2550  *
2551  * Returns the created or reused object.
2552  */
2553 static xmlXPathObjectPtr
2554 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2555 {
2556     if ((ctxt != NULL) && (ctxt->cache)) {
2557         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2558
2559         if ((cache->booleanObjs != NULL) &&
2560             (cache->booleanObjs->number != 0))
2561         {
2562             xmlXPathObjectPtr ret;
2563
2564             ret = (xmlXPathObjectPtr)
2565                 cache->booleanObjs->items[--cache->booleanObjs->number];
2566             ret->type = XPATH_BOOLEAN;
2567             ret->boolval = (val != 0);
2568 #ifdef XP_DEBUG_OBJ_USAGE
2569             xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2570 #endif
2571             return(ret);
2572         } else if ((cache->miscObjs != NULL) &&
2573             (cache->miscObjs->number != 0))
2574         {
2575             xmlXPathObjectPtr ret;
2576
2577             ret = (xmlXPathObjectPtr)
2578                 cache->miscObjs->items[--cache->miscObjs->number];
2579
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         }
2587     }
2588     return(xmlXPathNewBoolean(val));
2589 }
2590
2591 /**
2592  * xmlXPathCacheNewFloat:
2593  * @ctxt: the XPath context
2594  * @val:  the double value
2595  *
2596  * This is the cached version of xmlXPathNewFloat().
2597  * Acquires an xmlXPathObjectPtr of type double and of value @val
2598  *
2599  * Returns the created or reused object.
2600  */
2601 static xmlXPathObjectPtr
2602 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2603 {
2604      if ((ctxt != NULL) && (ctxt->cache)) {
2605         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2606
2607         if ((cache->numberObjs != NULL) &&
2608             (cache->numberObjs->number != 0))
2609         {
2610             xmlXPathObjectPtr ret;
2611
2612             ret = (xmlXPathObjectPtr)
2613                 cache->numberObjs->items[--cache->numberObjs->number];
2614             ret->type = XPATH_NUMBER;
2615             ret->floatval = val;
2616 #ifdef XP_DEBUG_OBJ_USAGE
2617             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2618 #endif
2619             return(ret);
2620         } else if ((cache->miscObjs != NULL) &&
2621             (cache->miscObjs->number != 0))
2622         {
2623             xmlXPathObjectPtr ret;
2624
2625             ret = (xmlXPathObjectPtr)
2626                 cache->miscObjs->items[--cache->miscObjs->number];
2627
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         }
2635     }
2636     return(xmlXPathNewFloat(val));
2637 }
2638
2639 /**
2640  * xmlXPathCacheConvertString:
2641  * @ctxt: the XPath context
2642  * @val:  an XPath object
2643  *
2644  * This is the cached version of xmlXPathConvertString().
2645  * Converts an existing object to its string() equivalent
2646  *
2647  * Returns a created or reused object, the old one is freed (cached)
2648  *         (or the operation is done directly on @val)
2649  */
2650
2651 static xmlXPathObjectPtr
2652 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2653     xmlChar *res = NULL;
2654
2655     if (val == NULL)
2656         return(xmlXPathCacheNewCString(ctxt, ""));
2657
2658     switch (val->type) {
2659     case XPATH_UNDEFINED:
2660 #ifdef DEBUG_EXPR
2661         xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2662 #endif
2663         break;
2664     case XPATH_NODESET:
2665     case XPATH_XSLT_TREE:
2666         res = xmlXPathCastNodeSetToString(val->nodesetval);
2667         break;
2668     case XPATH_STRING:
2669         return(val);
2670     case XPATH_BOOLEAN:
2671         res = xmlXPathCastBooleanToString(val->boolval);
2672         break;
2673     case XPATH_NUMBER:
2674         res = xmlXPathCastNumberToString(val->floatval);
2675         break;
2676     case XPATH_USERS:
2677     case XPATH_POINT:
2678     case XPATH_RANGE:
2679     case XPATH_LOCATIONSET:
2680         TODO;
2681         break;
2682     }
2683     xmlXPathReleaseObject(ctxt, val);
2684     if (res == NULL)
2685         return(xmlXPathCacheNewCString(ctxt, ""));
2686     return(xmlXPathCacheWrapString(ctxt, res));
2687 }
2688
2689 /**
2690  * xmlXPathCacheObjectCopy:
2691  * @ctxt: the XPath context
2692  * @val:  the original object
2693  *
2694  * This is the cached version of xmlXPathObjectCopy().
2695  * Acquire a copy of a given object
2696  *
2697  * Returns a created or reused created object.
2698  */
2699 static xmlXPathObjectPtr
2700 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2701 {
2702     if (val == NULL)
2703         return(NULL);
2704
2705     if (XP_HAS_CACHE(ctxt)) {
2706         switch (val->type) {
2707             case XPATH_NODESET:
2708                 return(xmlXPathCacheWrapNodeSet(ctxt,
2709                     xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2710             case XPATH_STRING:
2711                 return(xmlXPathCacheNewString(ctxt, val->stringval));
2712             case XPATH_BOOLEAN:
2713                 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2714             case XPATH_NUMBER:
2715                 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2716             default:
2717                 break;
2718         }
2719     }
2720     return(xmlXPathObjectCopy(val));
2721 }
2722
2723 /**
2724  * xmlXPathCacheConvertBoolean:
2725  * @ctxt: the XPath context
2726  * @val:  an XPath object
2727  *
2728  * This is the cached version of xmlXPathConvertBoolean().
2729  * Converts an existing object to its boolean() equivalent
2730  *
2731  * Returns a created or reused object, the old one is freed (or the operation
2732  *         is done directly on @val)
2733  */
2734 static xmlXPathObjectPtr
2735 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2736     xmlXPathObjectPtr ret;
2737
2738     if (val == NULL)
2739         return(xmlXPathCacheNewBoolean(ctxt, 0));
2740     if (val->type == XPATH_BOOLEAN)
2741         return(val);
2742     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2743     xmlXPathReleaseObject(ctxt, val);
2744     return(ret);
2745 }
2746
2747 /**
2748  * xmlXPathCacheConvertNumber:
2749  * @ctxt: the XPath context
2750  * @val:  an XPath object
2751  *
2752  * This is the cached version of xmlXPathConvertNumber().
2753  * Converts an existing object to its number() equivalent
2754  *
2755  * Returns a created or reused object, the old one is freed (or the operation
2756  *         is done directly on @val)
2757  */
2758 static xmlXPathObjectPtr
2759 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2760     xmlXPathObjectPtr ret;
2761
2762     if (val == NULL)
2763         return(xmlXPathCacheNewFloat(ctxt, 0.0));
2764     if (val->type == XPATH_NUMBER)
2765         return(val);
2766     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2767     xmlXPathReleaseObject(ctxt, val);
2768     return(ret);
2769 }
2770
2771 /************************************************************************
2772  *                                                                      *
2773  *              Parser stacks related functions and macros              *
2774  *                                                                      *
2775  ************************************************************************/
2776
2777 /**
2778  * xmlXPathSetFrame:
2779  * @ctxt: an XPath parser context
2780  *
2781  * Set the callee evaluation frame
2782  *
2783  * Returns the previous frame value to be restored once done
2784  */
2785 static int
2786 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2787     int ret;
2788
2789     if (ctxt == NULL)
2790         return(0);
2791     ret = ctxt->valueFrame;
2792     ctxt->valueFrame = ctxt->valueNr;
2793     return(ret);
2794 }
2795
2796 /**
2797  * xmlXPathPopFrame:
2798  * @ctxt: an XPath parser context
2799  * @frame: the previous frame value
2800  *
2801  * Remove the callee evaluation frame
2802  */
2803 static void
2804 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2805     if (ctxt == NULL)
2806         return;
2807     if (ctxt->valueNr < ctxt->valueFrame) {
2808         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2809     }
2810     ctxt->valueFrame = frame;
2811 }
2812
2813 /**
2814  * valuePop:
2815  * @ctxt: an XPath evaluation context
2816  *
2817  * Pops the top XPath object from the value stack
2818  *
2819  * Returns the XPath object just removed
2820  */
2821 xmlXPathObjectPtr
2822 valuePop(xmlXPathParserContextPtr ctxt)
2823 {
2824     xmlXPathObjectPtr ret;
2825
2826     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2827         return (NULL);
2828
2829     if (ctxt->valueNr <= ctxt->valueFrame) {
2830         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2831         return (NULL);
2832     }
2833
2834     ctxt->valueNr--;
2835     if (ctxt->valueNr > 0)
2836         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2837     else
2838         ctxt->value = NULL;
2839     ret = ctxt->valueTab[ctxt->valueNr];
2840     ctxt->valueTab[ctxt->valueNr] = NULL;
2841     return (ret);
2842 }
2843 /**
2844  * valuePush:
2845  * @ctxt:  an XPath evaluation context
2846  * @value:  the XPath object
2847  *
2848  * Pushes a new XPath object on top of the value stack
2849  *
2850  * returns the number of items on the value stack
2851  */
2852 int
2853 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2854 {
2855     if ((ctxt == NULL) || (value == NULL)) return(-1);
2856     if (ctxt->valueNr >= ctxt->valueMax) {
2857         xmlXPathObjectPtr *tmp;
2858
2859         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2860             xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2861             ctxt->error = XPATH_MEMORY_ERROR;
2862             return (0);
2863         }
2864         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2865                                              2 * ctxt->valueMax *
2866                                              sizeof(ctxt->valueTab[0]));
2867         if (tmp == NULL) {
2868             xmlXPathErrMemory(NULL, "pushing value\n");
2869             ctxt->error = XPATH_MEMORY_ERROR;
2870             return (0);
2871         }
2872         ctxt->valueMax *= 2;
2873         ctxt->valueTab = tmp;
2874     }
2875     ctxt->valueTab[ctxt->valueNr] = value;
2876     ctxt->value = value;
2877     return (ctxt->valueNr++);
2878 }
2879
2880 /**
2881  * xmlXPathPopBoolean:
2882  * @ctxt:  an XPath parser context
2883  *
2884  * Pops a boolean from the stack, handling conversion if needed.
2885  * Check error with #xmlXPathCheckError.
2886  *
2887  * Returns the boolean
2888  */
2889 int
2890 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2891     xmlXPathObjectPtr obj;
2892     int ret;
2893
2894     obj = valuePop(ctxt);
2895     if (obj == NULL) {
2896         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2897         return(0);
2898     }
2899     if (obj->type != XPATH_BOOLEAN)
2900         ret = xmlXPathCastToBoolean(obj);
2901     else
2902         ret = obj->boolval;
2903     xmlXPathReleaseObject(ctxt->context, obj);
2904     return(ret);
2905 }
2906
2907 /**
2908  * xmlXPathPopNumber:
2909  * @ctxt:  an XPath parser context
2910  *
2911  * Pops a number from the stack, handling conversion if needed.
2912  * Check error with #xmlXPathCheckError.
2913  *
2914  * Returns the number
2915  */
2916 double
2917 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2918     xmlXPathObjectPtr obj;
2919     double ret;
2920
2921     obj = valuePop(ctxt);
2922     if (obj == NULL) {
2923         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2924         return(0);
2925     }
2926     if (obj->type != XPATH_NUMBER)
2927         ret = xmlXPathCastToNumber(obj);
2928     else
2929         ret = obj->floatval;
2930     xmlXPathReleaseObject(ctxt->context, obj);
2931     return(ret);
2932 }
2933
2934 /**
2935  * xmlXPathPopString:
2936  * @ctxt:  an XPath parser context
2937  *
2938  * Pops a string from the stack, handling conversion if needed.
2939  * Check error with #xmlXPathCheckError.
2940  *
2941  * Returns the string
2942  */
2943 xmlChar *
2944 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2945     xmlXPathObjectPtr obj;
2946     xmlChar * ret;
2947
2948     obj = valuePop(ctxt);
2949     if (obj == NULL) {
2950         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2951         return(NULL);
2952     }
2953     ret = xmlXPathCastToString(obj);    /* this does required strdup */
2954     /* TODO: needs refactoring somewhere else */
2955     if (obj->stringval == ret)
2956         obj->stringval = NULL;
2957     xmlXPathReleaseObject(ctxt->context, obj);
2958     return(ret);
2959 }
2960
2961 /**
2962  * xmlXPathPopNodeSet:
2963  * @ctxt:  an XPath parser context
2964  *
2965  * Pops a node-set from the stack, handling conversion if needed.
2966  * Check error with #xmlXPathCheckError.
2967  *
2968  * Returns the node-set
2969  */
2970 xmlNodeSetPtr
2971 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2972     xmlXPathObjectPtr obj;
2973     xmlNodeSetPtr ret;
2974
2975     if (ctxt == NULL) return(NULL);
2976     if (ctxt->value == NULL) {
2977         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2978         return(NULL);
2979     }
2980     if (!xmlXPathStackIsNodeSet(ctxt)) {
2981         xmlXPathSetTypeError(ctxt);
2982         return(NULL);
2983     }
2984     obj = valuePop(ctxt);
2985     ret = obj->nodesetval;
2986 #if 0
2987     /* to fix memory leak of not clearing obj->user */
2988     if (obj->boolval && obj->user != NULL)
2989         xmlFreeNodeList((xmlNodePtr) obj->user);
2990 #endif
2991     obj->nodesetval = NULL;
2992     xmlXPathReleaseObject(ctxt->context, obj);
2993     return(ret);
2994 }
2995
2996 /**
2997  * xmlXPathPopExternal:
2998  * @ctxt:  an XPath parser context
2999  *
3000  * Pops an external object from the stack, handling conversion if needed.
3001  * Check error with #xmlXPathCheckError.
3002  *
3003  * Returns the object
3004  */
3005 void *
3006 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3007     xmlXPathObjectPtr obj;
3008     void * ret;
3009
3010     if ((ctxt == NULL) || (ctxt->value == NULL)) {
3011         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3012         return(NULL);
3013     }
3014     if (ctxt->value->type != XPATH_USERS) {
3015         xmlXPathSetTypeError(ctxt);
3016         return(NULL);
3017     }
3018     obj = valuePop(ctxt);
3019     ret = obj->user;
3020     obj->user = NULL;
3021     xmlXPathReleaseObject(ctxt->context, obj);
3022     return(ret);
3023 }
3024
3025 /*
3026  * Macros for accessing the content. Those should be used only by the parser,
3027  * and not exported.
3028  *
3029  * Dirty macros, i.e. one need to make assumption on the context to use them
3030  *
3031  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3032  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3033  *           in ISO-Latin or UTF-8.
3034  *           This should be used internally by the parser
3035  *           only to compare to ASCII values otherwise it would break when
3036  *           running with UTF-8 encoding.
3037  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3038  *           to compare on ASCII based substring.
3039  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3040  *           strings within the parser.
3041  *   CURRENT Returns the current char value, with the full decoding of
3042  *           UTF-8 if we are using this mode. It returns an int.
3043  *   NEXT    Skip to the next character, this does the proper decoding
3044  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3045  *           It returns the pointer to the current xmlChar.
3046  */
3047
3048 #define CUR (*ctxt->cur)
3049 #define SKIP(val) ctxt->cur += (val)
3050 #define NXT(val) ctxt->cur[(val)]
3051 #define CUR_PTR ctxt->cur
3052 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3053
3054 #define COPY_BUF(l,b,i,v)                                              \
3055     if (l == 1) b[i++] = (xmlChar) v;                                  \
3056     else i += xmlCopyChar(l,&b[i],v)
3057
3058 #define NEXTL(l)  ctxt->cur += l
3059
3060 #define SKIP_BLANKS                                                     \
3061     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3062
3063 #define CURRENT (*ctxt->cur)
3064 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3065
3066
3067 #ifndef DBL_DIG
3068 #define DBL_DIG 16
3069 #endif
3070 #ifndef DBL_EPSILON
3071 #define DBL_EPSILON 1E-9
3072 #endif
3073
3074 #define UPPER_DOUBLE 1E9
3075 #define LOWER_DOUBLE 1E-5
3076 #define LOWER_DOUBLE_EXP 5
3077
3078 #define INTEGER_DIGITS DBL_DIG
3079 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3080 #define EXPONENT_DIGITS (3 + 2)
3081
3082 /**
3083  * xmlXPathFormatNumber:
3084  * @number:     number to format
3085  * @buffer:     output buffer
3086  * @buffersize: size of output buffer
3087  *
3088  * Convert the number into a string representation.
3089  */
3090 static void
3091 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3092 {
3093     switch (xmlXPathIsInf(number)) {
3094     case 1:
3095         if (buffersize > (int)sizeof("Infinity"))
3096             snprintf(buffer, buffersize, "Infinity");
3097         break;
3098     case -1:
3099         if (buffersize > (int)sizeof("-Infinity"))
3100             snprintf(buffer, buffersize, "-Infinity");
3101         break;
3102     default:
3103         if (xmlXPathIsNaN(number)) {
3104             if (buffersize > (int)sizeof("NaN"))
3105                 snprintf(buffer, buffersize, "NaN");
3106         } else if (number == 0 && xmlXPathGetSign(number) != 0) {
3107             snprintf(buffer, buffersize, "0");
3108         } else if (number == ((int) number)) {
3109             char work[30];
3110             char *ptr, *cur;
3111             int value = (int) number;
3112
3113             ptr = &buffer[0];
3114             if (value == 0) {
3115                 *ptr++ = '0';
3116             } else {
3117                 snprintf(work, 29, "%d", value);
3118                 cur = &work[0];
3119                 while ((*cur) && (ptr - buffer < buffersize)) {
3120                     *ptr++ = *cur++;
3121                 }
3122             }
3123             if (ptr - buffer < buffersize) {
3124                 *ptr = 0;
3125             } else if (buffersize > 0) {
3126                 ptr--;
3127                 *ptr = 0;
3128             }
3129         } else {
3130             /*
3131               For the dimension of work,
3132                   DBL_DIG is number of significant digits
3133                   EXPONENT is only needed for "scientific notation"
3134                   3 is sign, decimal point, and terminating zero
3135                   LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3136               Note that this dimension is slightly (a few characters)
3137               larger than actually necessary.
3138             */
3139             char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3140             int integer_place, fraction_place;
3141             char *ptr;
3142             char *after_fraction;
3143             double absolute_value;
3144             int size;
3145
3146             absolute_value = fabs(number);
3147
3148             /*
3149              * First choose format - scientific or regular floating point.
3150              * In either case, result is in work, and after_fraction points
3151              * just past the fractional part.
3152             */
3153             if ( ((absolute_value > UPPER_DOUBLE) ||
3154                   (absolute_value < LOWER_DOUBLE)) &&
3155                  (absolute_value != 0.0) ) {
3156                 /* Use scientific notation */
3157                 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3158                 fraction_place = DBL_DIG - 1;
3159                 size = snprintf(work, sizeof(work),"%*.*e",
3160                          integer_place, fraction_place, number);
3161                 while ((size > 0) && (work[size] != 'e')) size--;
3162
3163             }
3164             else {
3165                 /* Use regular notation */
3166                 if (absolute_value > 0.0) {
3167                     integer_place = (int)log10(absolute_value);
3168                     if (integer_place > 0)
3169                         fraction_place = DBL_DIG - integer_place - 1;
3170                     else
3171                         fraction_place = DBL_DIG - integer_place;
3172                 } else {
3173                     fraction_place = 1;
3174                 }
3175                 size = snprintf(work, sizeof(work), "%0.*f",
3176                                 fraction_place, number);
3177             }
3178
3179             /* Remove leading spaces sometimes inserted by snprintf */
3180             while (work[0] == ' ') {
3181                 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3182                 size--;
3183             }
3184
3185             /* Remove fractional trailing zeroes */
3186             after_fraction = work + size;
3187             ptr = after_fraction;
3188             while (*(--ptr) == '0')
3189                 ;
3190             if (*ptr != '.')
3191                 ptr++;
3192             while ((*ptr++ = *after_fraction++) != 0);
3193
3194             /* Finally copy result back to caller */
3195             size = strlen(work) + 1;
3196             if (size > buffersize) {
3197                 work[buffersize - 1] = 0;
3198                 size = buffersize;
3199             }
3200             memmove(buffer, work, size);
3201         }
3202         break;
3203     }
3204 }
3205
3206
3207 /************************************************************************
3208  *                                                                      *
3209  *                      Routines to handle NodeSets                     *
3210  *                                                                      *
3211  ************************************************************************/
3212
3213 /**
3214  * xmlXPathOrderDocElems:
3215  * @doc:  an input document
3216  *
3217  * Call this routine to speed up XPath computation on static documents.
3218  * This stamps all the element nodes with the document order
3219  * Like for line information, the order is kept in the element->content
3220  * field, the value stored is actually - the node number (starting at -1)
3221  * to be able to differentiate from line numbers.
3222  *
3223  * Returns the number of elements found in the document or -1 in case
3224  *    of error.
3225  */
3226 long
3227 xmlXPathOrderDocElems(xmlDocPtr doc) {
3228     long count = 0;
3229     xmlNodePtr cur;
3230
3231     if (doc == NULL)
3232         return(-1);
3233     cur = doc->children;
3234     while (cur != NULL) {
3235         if (cur->type == XML_ELEMENT_NODE) {
3236             cur->content = (void *) (-(++count));
3237             if (cur->children != NULL) {
3238                 cur = cur->children;
3239                 continue;
3240             }
3241         }
3242         if (cur->next != NULL) {
3243             cur = cur->next;
3244             continue;
3245         }
3246         do {
3247             cur = cur->parent;
3248             if (cur == NULL)
3249                 break;
3250             if (cur == (xmlNodePtr) doc) {
3251                 cur = NULL;
3252                 break;
3253             }
3254             if (cur->next != NULL) {
3255                 cur = cur->next;
3256                 break;
3257             }
3258         } while (cur != NULL);
3259     }
3260     return(count);
3261 }
3262
3263 /**
3264  * xmlXPathCmpNodes:
3265  * @node1:  the first node
3266  * @node2:  the second node
3267  *
3268  * Compare two nodes w.r.t document order
3269  *
3270  * Returns -2 in case of error 1 if first point < second point, 0 if
3271  *         it's the same node, -1 otherwise
3272  */
3273 int
3274 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3275     int depth1, depth2;
3276     int attr1 = 0, attr2 = 0;
3277     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3278     xmlNodePtr cur, root;
3279
3280     if ((node1 == NULL) || (node2 == NULL))
3281         return(-2);
3282     /*
3283      * a couple of optimizations which will avoid computations in most cases
3284      */
3285     if (node1 == node2)         /* trivial case */
3286         return(0);
3287     if (node1->type == XML_ATTRIBUTE_NODE) {
3288         attr1 = 1;
3289         attrNode1 = node1;
3290         node1 = node1->parent;
3291     }
3292     if (node2->type == XML_ATTRIBUTE_NODE) {
3293         attr2 = 1;
3294         attrNode2 = node2;
3295         node2 = node2->parent;
3296     }
3297     if (node1 == node2) {
3298         if (attr1 == attr2) {
3299             /* not required, but we keep attributes in order */
3300             if (attr1 != 0) {
3301                 cur = attrNode2->prev;
3302                 while (cur != NULL) {
3303                     if (cur == attrNode1)
3304                         return (1);
3305                     cur = cur->prev;
3306                 }
3307                 return (-1);
3308             }
3309             return(0);
3310         }
3311         if (attr2 == 1)
3312             return(1);
3313         return(-1);
3314     }
3315     if ((node1->type == XML_NAMESPACE_DECL) ||
3316         (node2->type == XML_NAMESPACE_DECL))
3317         return(1);
3318     if (node1 == node2->prev)
3319         return(1);
3320     if (node1 == node2->next)
3321         return(-1);
3322
3323     /*
3324      * Speedup using document order if availble.
3325      */
3326     if ((node1->type == XML_ELEMENT_NODE) &&
3327         (node2->type == XML_ELEMENT_NODE) &&
3328         (0 > (long) node1->content) &&
3329         (0 > (long) node2->content) &&
3330         (node1->doc == node2->doc)) {
3331         long l1, l2;
3332
3333         l1 = -((long) node1->content);
3334         l2 = -((long) node2->content);
3335         if (l1 < l2)
3336             return(1);
3337         if (l1 > l2)
3338             return(-1);
3339     }
3340
3341     /*
3342      * compute depth to root
3343      */
3344     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3345         if (cur == node1)
3346             return(1);
3347         depth2++;
3348     }
3349     root = cur;
3350     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3351         if (cur == node2)
3352             return(-1);
3353         depth1++;
3354     }
3355     /*
3356      * Distinct document (or distinct entities :-( ) case.
3357      */
3358     if (root != cur) {
3359         return(-2);
3360     }
3361     /*
3362      * get the nearest common ancestor.
3363      */
3364     while (depth1 > depth2) {
3365         depth1--;
3366         node1 = node1->parent;
3367     }
3368     while (depth2 > depth1) {
3369         depth2--;
3370         node2 = node2->parent;
3371     }
3372     while (node1->parent != node2->parent) {
3373         node1 = node1->parent;
3374         node2 = node2->parent;
3375         /* should not happen but just in case ... */
3376         if ((node1 == NULL) || (node2 == NULL))
3377             return(-2);
3378     }
3379     /*
3380      * Find who's first.
3381      */
3382     if (node1 == node2->prev)
3383         return(1);
3384     if (node1 == node2->next)
3385         return(-1);
3386     /*
3387      * Speedup using document order if availble.
3388      */
3389     if ((node1->type == XML_ELEMENT_NODE) &&
3390         (node2->type == XML_ELEMENT_NODE) &&
3391         (0 > (long) node1->content) &&
3392         (0 > (long) node2->content) &&
3393         (node1->doc == node2->doc)) {
3394         long l1, l2;
3395
3396         l1 = -((long) node1->content);
3397         l2 = -((long) node2->content);
3398         if (l1 < l2)
3399             return(1);
3400         if (l1 > l2)
3401             return(-1);
3402     }
3403
3404     for (cur = node1->next;cur != NULL;cur = cur->next)
3405         if (cur == node2)
3406             return(1);
3407     return(-1); /* assume there is no sibling list corruption */
3408 }
3409
3410 /**
3411  * xmlXPathNodeSetSort:
3412  * @set:  the node set
3413  *
3414  * Sort the node set in document order
3415  */
3416 void
3417 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3418 #ifndef WITH_TIM_SORT
3419     int i, j, incr, len;
3420     xmlNodePtr tmp;
3421 #endif
3422
3423     if (set == NULL)
3424         return;
3425
3426 #ifndef WITH_TIM_SORT
3427     /*
3428      * Use the old Shell's sort implementation to sort the node-set
3429      * Timsort ought to be quite faster
3430      */
3431     len = set->nodeNr;
3432     for (incr = len / 2; incr > 0; incr /= 2) {
3433         for (i = incr; i < len; i++) {
3434             j = i - incr;
3435             while (j >= 0) {
3436 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3437                 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3438                         set->nodeTab[j + incr]) == -1)
3439 #else
3440                 if (xmlXPathCmpNodes(set->nodeTab[j],
3441                         set->nodeTab[j + incr]) == -1)
3442 #endif
3443                 {
3444                     tmp = set->nodeTab[j];
3445                     set->nodeTab[j] = set->nodeTab[j + incr];
3446                     set->nodeTab[j + incr] = tmp;
3447                     j -= incr;
3448                 } else
3449                     break;
3450             }
3451         }
3452     }
3453 #else /* WITH_TIM_SORT */
3454     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3455 #endif /* WITH_TIM_SORT */
3456 }
3457
3458 #define XML_NODESET_DEFAULT     10
3459 /**
3460  * xmlXPathNodeSetDupNs:
3461  * @node:  the parent node of the namespace XPath node
3462  * @ns:  the libxml namespace declaration node.
3463  *
3464  * Namespace node in libxml don't match the XPath semantic. In a node set
3465  * the namespace nodes are duplicated and the next pointer is set to the
3466  * parent node in the XPath semantic.
3467  *
3468  * Returns the newly created object.
3469  */
3470 static xmlNodePtr
3471 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3472     xmlNsPtr cur;
3473
3474     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3475         return(NULL);
3476     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3477         return((xmlNodePtr) ns);
3478
3479     /*
3480      * Allocate a new Namespace and fill the fields.
3481      */
3482     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3483     if (cur == NULL) {
3484         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3485         return(NULL);
3486     }
3487     memset(cur, 0, sizeof(xmlNs));
3488     cur->type = XML_NAMESPACE_DECL;
3489     if (ns->href != NULL)
3490         cur->href = xmlStrdup(ns->href);
3491     if (ns->prefix != NULL)
3492         cur->prefix = xmlStrdup(ns->prefix);
3493     cur->next = (xmlNsPtr) node;
3494     return((xmlNodePtr) cur);
3495 }
3496
3497 /**
3498  * xmlXPathNodeSetFreeNs:
3499  * @ns:  the XPath namespace node found in a nodeset.
3500  *
3501  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3502  * the namespace nodes are duplicated and the next pointer is set to the
3503  * parent node in the XPath semantic. Check if such a node needs to be freed
3504  */
3505 void
3506 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3507     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3508         return;
3509
3510     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3511         if (ns->href != NULL)
3512             xmlFree((xmlChar *)ns->href);
3513         if (ns->prefix != NULL)
3514             xmlFree((xmlChar *)ns->prefix);
3515         xmlFree(ns);
3516     }
3517 }
3518
3519 /**
3520  * xmlXPathNodeSetCreate:
3521  * @val:  an initial xmlNodePtr, or NULL
3522  *
3523  * Create a new xmlNodeSetPtr of type double and of value @val
3524  *
3525  * Returns the newly created object.
3526  */
3527 xmlNodeSetPtr
3528 xmlXPathNodeSetCreate(xmlNodePtr val) {
3529     xmlNodeSetPtr ret;
3530
3531     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3532     if (ret == NULL) {
3533         xmlXPathErrMemory(NULL, "creating nodeset\n");
3534         return(NULL);
3535     }
3536     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3537     if (val != NULL) {
3538         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3539                                              sizeof(xmlNodePtr));
3540         if (ret->nodeTab == NULL) {
3541             xmlXPathErrMemory(NULL, "creating nodeset\n");
3542             xmlFree(ret);
3543             return(NULL);
3544         }
3545         memset(ret->nodeTab, 0 ,
3546                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3547         ret->nodeMax = XML_NODESET_DEFAULT;
3548         if (val->type == XML_NAMESPACE_DECL) {
3549             xmlNsPtr ns = (xmlNsPtr) val;
3550
3551             ret->nodeTab[ret->nodeNr++] =
3552                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3553         } else
3554             ret->nodeTab[ret->nodeNr++] = val;
3555     }
3556     return(ret);
3557 }
3558
3559 /**
3560  * xmlXPathNodeSetCreateSize:
3561  * @size:  the initial size of the set
3562  *
3563  * Create a new xmlNodeSetPtr of type double and of value @val
3564  *
3565  * Returns the newly created object.
3566  */
3567 static xmlNodeSetPtr
3568 xmlXPathNodeSetCreateSize(int size) {
3569     xmlNodeSetPtr ret;
3570
3571     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3572     if (ret == NULL) {
3573         xmlXPathErrMemory(NULL, "creating nodeset\n");
3574         return(NULL);
3575     }
3576     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3577     if (size < XML_NODESET_DEFAULT)
3578         size = XML_NODESET_DEFAULT;
3579     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3580     if (ret->nodeTab == NULL) {
3581         xmlXPathErrMemory(NULL, "creating nodeset\n");
3582         xmlFree(ret);
3583         return(NULL);
3584     }
3585     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3586     ret->nodeMax = size;
3587     return(ret);
3588 }
3589
3590 /**
3591  * xmlXPathNodeSetContains:
3592  * @cur:  the node-set
3593  * @val:  the node
3594  *
3595  * checks whether @cur contains @val
3596  *
3597  * Returns true (1) if @cur contains @val, false (0) otherwise
3598  */
3599 int
3600 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3601     int i;
3602
3603     if ((cur == NULL) || (val == NULL)) return(0);
3604     if (val->type == XML_NAMESPACE_DECL) {
3605         for (i = 0; i < cur->nodeNr; i++) {
3606             if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3607                 xmlNsPtr ns1, ns2;
3608
3609                 ns1 = (xmlNsPtr) val;
3610                 ns2 = (xmlNsPtr) cur->nodeTab[i];
3611                 if (ns1 == ns2)
3612                     return(1);
3613                 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3614                     (xmlStrEqual(ns1->prefix, ns2->prefix)))
3615                     return(1);
3616             }
3617         }
3618     } else {
3619         for (i = 0; i < cur->nodeNr; i++) {
3620             if (cur->nodeTab[i] == val)
3621                 return(1);
3622         }
3623     }
3624     return(0);
3625 }
3626
3627 /**
3628  * xmlXPathNodeSetAddNs:
3629  * @cur:  the initial node set
3630  * @node:  the hosting node
3631  * @ns:  a the namespace node
3632  *
3633  * add a new namespace node to an existing NodeSet
3634  *
3635  * Returns 0 in case of success and -1 in case of error
3636  */
3637 int
3638 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3639     int i;
3640
3641
3642     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3643         (ns->type != XML_NAMESPACE_DECL) ||
3644         (node->type != XML_ELEMENT_NODE))
3645         return(-1);
3646
3647     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3648     /*
3649      * prevent duplicates
3650      */
3651     for (i = 0;i < cur->nodeNr;i++) {
3652         if ((cur->nodeTab[i] != NULL) &&
3653             (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3654             (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3655             (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3656             return(0);
3657     }
3658
3659     /*
3660      * grow the nodeTab if needed
3661      */
3662     if (cur->nodeMax == 0) {
3663         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3664                                              sizeof(xmlNodePtr));
3665         if (cur->nodeTab == NULL) {
3666             xmlXPathErrMemory(NULL, "growing nodeset\n");
3667             return(-1);
3668         }
3669         memset(cur->nodeTab, 0 ,
3670                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3671         cur->nodeMax = XML_NODESET_DEFAULT;
3672     } else if (cur->nodeNr == cur->nodeMax) {
3673         xmlNodePtr *temp;
3674
3675         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3676             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3677             return(-1);
3678         }
3679         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3680                                       sizeof(xmlNodePtr));
3681         if (temp == NULL) {
3682             xmlXPathErrMemory(NULL, "growing nodeset\n");
3683             return(-1);
3684         }
3685         cur->nodeMax *= 2;
3686         cur->nodeTab = temp;
3687     }
3688     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3689     return(0);
3690 }
3691
3692 /**
3693  * xmlXPathNodeSetAdd:
3694  * @cur:  the initial node set
3695  * @val:  a new xmlNodePtr
3696  *
3697  * add a new xmlNodePtr to an existing NodeSet
3698  *
3699  * Returns 0 in case of success, and -1 in case of error
3700  */
3701 int
3702 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3703     int i;
3704
3705     if ((cur == NULL) || (val == NULL)) return(-1);
3706
3707     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3708     /*
3709      * prevent duplicates
3710      */
3711     for (i = 0;i < cur->nodeNr;i++)
3712         if (cur->nodeTab[i] == val) return(0);
3713
3714     /*
3715      * grow the nodeTab if needed
3716      */
3717     if (cur->nodeMax == 0) {
3718         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3719                                              sizeof(xmlNodePtr));
3720         if (cur->nodeTab == NULL) {
3721             xmlXPathErrMemory(NULL, "growing nodeset\n");
3722             return(-1);
3723         }
3724         memset(cur->nodeTab, 0 ,
3725                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3726         cur->nodeMax = XML_NODESET_DEFAULT;
3727     } else if (cur->nodeNr == cur->nodeMax) {
3728         xmlNodePtr *temp;
3729
3730         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3731             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3732             return(-1);
3733         }
3734         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3735                                       sizeof(xmlNodePtr));
3736         if (temp == NULL) {
3737             xmlXPathErrMemory(NULL, "growing nodeset\n");
3738             return(-1);
3739         }
3740         cur->nodeMax *= 2;
3741         cur->nodeTab = temp;
3742     }
3743     if (val->type == XML_NAMESPACE_DECL) {
3744         xmlNsPtr ns = (xmlNsPtr) val;
3745
3746         cur->nodeTab[cur->nodeNr++] =
3747             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3748     } else
3749         cur->nodeTab[cur->nodeNr++] = val;
3750     return(0);
3751 }
3752
3753 /**
3754  * xmlXPathNodeSetAddUnique:
3755  * @cur:  the initial node set
3756  * @val:  a new xmlNodePtr
3757  *
3758  * add a new xmlNodePtr to an existing NodeSet, optimized version
3759  * when we are sure the node is not already in the set.
3760  *
3761  * Returns 0 in case of success and -1 in case of failure
3762  */
3763 int
3764 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3765     if ((cur == NULL) || (val == NULL)) return(-1);
3766
3767     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3768     /*
3769      * grow the nodeTab if needed
3770      */
3771     if (cur->nodeMax == 0) {
3772         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3773                                              sizeof(xmlNodePtr));
3774         if (cur->nodeTab == NULL) {
3775             xmlXPathErrMemory(NULL, "growing nodeset\n");
3776             return(-1);
3777         }
3778         memset(cur->nodeTab, 0 ,
3779                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3780         cur->nodeMax = XML_NODESET_DEFAULT;
3781     } else if (cur->nodeNr == cur->nodeMax) {
3782         xmlNodePtr *temp;
3783
3784         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3785             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3786             return(-1);
3787         }
3788         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3789                                       sizeof(xmlNodePtr));
3790         if (temp == NULL) {
3791             xmlXPathErrMemory(NULL, "growing nodeset\n");
3792             return(-1);
3793         }
3794         cur->nodeTab = temp;
3795         cur->nodeMax *= 2;
3796     }
3797     if (val->type == XML_NAMESPACE_DECL) {
3798         xmlNsPtr ns = (xmlNsPtr) val;
3799
3800         cur->nodeTab[cur->nodeNr++] =
3801             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3802     } else
3803         cur->nodeTab[cur->nodeNr++] = val;
3804     return(0);
3805 }
3806
3807 /**
3808  * xmlXPathNodeSetMerge:
3809  * @val1:  the first NodeSet or NULL
3810  * @val2:  the second NodeSet
3811  *
3812  * Merges two nodesets, all nodes from @val2 are added to @val1
3813  * if @val1 is NULL, a new set is created and copied from @val2
3814  *
3815  * Returns @val1 once extended or NULL in case of error.
3816  */
3817 xmlNodeSetPtr
3818 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3819     int i, j, initNr, skip;
3820     xmlNodePtr n1, n2;
3821
3822     if (val2 == NULL) return(val1);
3823     if (val1 == NULL) {
3824         val1 = xmlXPathNodeSetCreate(NULL);
3825     if (val1 == NULL)
3826         return (NULL);
3827 #if 0
3828         /*
3829         * TODO: The optimization won't work in every case, since
3830         *  those nasty namespace nodes need to be added with
3831         *  xmlXPathNodeSetDupNs() to the set; thus a pure
3832         *  memcpy is not possible.
3833         *  If there was a flag on the nodesetval, indicating that
3834         *  some temporary nodes are in, that would be helpfull.
3835         */
3836         /*
3837         * Optimization: Create an equally sized node-set
3838         * and memcpy the content.
3839         */
3840         val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3841         if (val1 == NULL)
3842             return(NULL);
3843         if (val2->nodeNr != 0) {
3844             if (val2->nodeNr == 1)
3845                 *(val1->nodeTab) = *(val2->nodeTab);
3846             else {
3847                 memcpy(val1->nodeTab, val2->nodeTab,
3848                     val2->nodeNr * sizeof(xmlNodePtr));
3849             }
3850             val1->nodeNr = val2->nodeNr;
3851         }
3852         return(val1);
3853 #endif
3854     }
3855
3856     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3857     initNr = val1->nodeNr;
3858
3859     for (i = 0;i < val2->nodeNr;i++) {
3860         n2 = val2->nodeTab[i];
3861         /*
3862          * check against duplicates
3863          */
3864         skip = 0;
3865         for (j = 0; j < initNr; j++) {
3866             n1 = val1->nodeTab[j];
3867             if (n1 == n2) {
3868                 skip = 1;
3869                 break;
3870             } else if ((n1->type == XML_NAMESPACE_DECL) &&
3871                        (n2->type == XML_NAMESPACE_DECL)) {
3872                 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3873                     (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3874                         ((xmlNsPtr) n2)->prefix)))
3875                 {
3876                     skip = 1;
3877                     break;
3878                 }
3879             }
3880         }
3881         if (skip)
3882             continue;
3883
3884         /*
3885          * grow the nodeTab if needed
3886          */
3887         if (val1->nodeMax == 0) {
3888             val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3889                                                     sizeof(xmlNodePtr));
3890             if (val1->nodeTab == NULL) {
3891                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3892                 return(NULL);
3893             }
3894             memset(val1->nodeTab, 0 ,
3895                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3896             val1->nodeMax = XML_NODESET_DEFAULT;
3897         } else if (val1->nodeNr == val1->nodeMax) {
3898             xmlNodePtr *temp;
3899
3900             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3901                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3902                 return(NULL);
3903             }
3904             temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3905                                              sizeof(xmlNodePtr));
3906             if (temp == NULL) {
3907                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3908                 return(NULL);
3909             }
3910             val1->nodeTab = temp;
3911             val1->nodeMax *= 2;
3912         }
3913         if (n2->type == XML_NAMESPACE_DECL) {
3914             xmlNsPtr ns = (xmlNsPtr) n2;
3915
3916             val1->nodeTab[val1->nodeNr++] =
3917                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3918         } else
3919             val1->nodeTab[val1->nodeNr++] = n2;
3920     }
3921
3922     return(val1);
3923 }
3924
3925
3926 /**
3927  * xmlXPathNodeSetMergeAndClear:
3928  * @set1:  the first NodeSet or NULL
3929  * @set2:  the second NodeSet
3930  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3931  *
3932  * Merges two nodesets, all nodes from @set2 are added to @set1
3933  * if @set1 is NULL, a new set is created and copied from @set2.
3934  * Checks for duplicate nodes. Clears set2.
3935  *
3936  * Returns @set1 once extended or NULL in case of error.
3937  */
3938 static xmlNodeSetPtr
3939 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3940                              int hasNullEntries)
3941 {
3942     if ((set1 == NULL) && (hasNullEntries == 0)) {
3943         /*
3944         * Note that doing a memcpy of the list, namespace nodes are
3945         * just assigned to set1, since set2 is cleared anyway.
3946         */
3947         set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3948         if (set1 == NULL)
3949             return(NULL);
3950         if (set2->nodeNr != 0) {
3951             memcpy(set1->nodeTab, set2->nodeTab,
3952                 set2->nodeNr * sizeof(xmlNodePtr));
3953             set1->nodeNr = set2->nodeNr;
3954         }
3955     } else {
3956         int i, j, initNbSet1;
3957         xmlNodePtr n1, n2;
3958
3959         if (set1 == NULL)
3960             set1 = xmlXPathNodeSetCreate(NULL);
3961         if (set1 == NULL)
3962             return (NULL);
3963
3964         initNbSet1 = set1->nodeNr;
3965         for (i = 0;i < set2->nodeNr;i++) {
3966             n2 = set2->nodeTab[i];
3967             /*
3968             * Skip NULLed entries.
3969             */
3970             if (n2 == NULL)
3971                 continue;
3972             /*
3973             * Skip duplicates.
3974             */
3975             for (j = 0; j < initNbSet1; j++) {
3976                 n1 = set1->nodeTab[j];
3977                 if (n1 == n2) {
3978                     goto skip_node;
3979                 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3980                     (n2->type == XML_NAMESPACE_DECL))
3981                 {
3982                     if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3983                         (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3984                         ((xmlNsPtr) n2)->prefix)))
3985                     {
3986                         /*
3987                         * Free the namespace node.
3988                         */
3989                         set2->nodeTab[i] = NULL;
3990                         xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3991                         goto skip_node;
3992                     }
3993                 }
3994             }
3995             /*
3996             * grow the nodeTab if needed
3997             */
3998             if (set1->nodeMax == 0) {
3999                 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4000                     XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4001                 if (set1->nodeTab == NULL) {
4002                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4003                     return(NULL);
4004                 }
4005                 memset(set1->nodeTab, 0,
4006                     XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4007                 set1->nodeMax = XML_NODESET_DEFAULT;
4008             } else if (set1->nodeNr >= set1->nodeMax) {
4009                 xmlNodePtr *temp;
4010
4011                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4012                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4013                     return(NULL);
4014                 }
4015                 temp = (xmlNodePtr *) xmlRealloc(
4016                     set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4017                 if (temp == NULL) {
4018                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4019                     return(NULL);
4020                 }
4021                 set1->nodeTab = temp;
4022                 set1->nodeMax *= 2;
4023             }
4024             if (n2->type == XML_NAMESPACE_DECL) {
4025                 xmlNsPtr ns = (xmlNsPtr) n2;
4026
4027                 set1->nodeTab[set1->nodeNr++] =
4028                     xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
4029             } else
4030                 set1->nodeTab[set1->nodeNr++] = n2;
4031 skip_node:
4032             {}
4033         }
4034     }
4035     set2->nodeNr = 0;
4036     return(set1);
4037 }
4038
4039 /**
4040  * xmlXPathNodeSetMergeAndClearNoDupls:
4041  * @set1:  the first NodeSet or NULL
4042  * @set2:  the second NodeSet
4043  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4044  *
4045  * Merges two nodesets, all nodes from @set2 are added to @set1
4046  * if @set1 is NULL, a new set is created and copied from @set2.
4047  * Doesn't chack for duplicate nodes. Clears set2.
4048  *
4049  * Returns @set1 once extended or NULL in case of error.
4050  */
4051 static xmlNodeSetPtr
4052 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4053                                     int hasNullEntries)
4054 {
4055     if (set2 == NULL)
4056         return(set1);
4057     if ((set1 == NULL) && (hasNullEntries == 0)) {
4058         /*
4059         * Note that doing a memcpy of the list, namespace nodes are
4060         * just assigned to set1, since set2 is cleared anyway.
4061         */
4062         set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4063         if (set1 == NULL)
4064             return(NULL);
4065         if (set2->nodeNr != 0) {
4066             memcpy(set1->nodeTab, set2->nodeTab,
4067                 set2->nodeNr * sizeof(xmlNodePtr));
4068             set1->nodeNr = set2->nodeNr;
4069         }
4070     } else {
4071         int i;
4072         xmlNodePtr n2;
4073
4074         if (set1 == NULL)
4075             set1 = xmlXPathNodeSetCreate(NULL);
4076         if (set1 == NULL)
4077             return (NULL);
4078
4079         for (i = 0;i < set2->nodeNr;i++) {
4080             n2 = set2->nodeTab[i];
4081             /*
4082             * Skip NULLed entries.
4083             */
4084             if (n2 == NULL)
4085                 continue;
4086             if (set1->nodeMax == 0) {
4087                 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4088                     XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4089                 if (set1->nodeTab == NULL) {
4090                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4091                     return(NULL);
4092                 }
4093                 memset(set1->nodeTab, 0,
4094                     XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4095                 set1->nodeMax = XML_NODESET_DEFAULT;
4096             } else if (set1->nodeNr >= set1->nodeMax) {
4097                 xmlNodePtr *temp;
4098
4099                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4100                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4101                     return(NULL);
4102                 }
4103                 temp = (xmlNodePtr *) xmlRealloc(
4104                     set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4105                 if (temp == NULL) {
4106                     xmlXPathErrMemory(NULL, "merging nodeset\n");
4107                     return(NULL);
4108                 }
4109                 set1->nodeTab = temp;
4110                 set1->nodeMax *= 2;
4111             }
4112             set1->nodeTab[set1->nodeNr++] = n2;
4113         }
4114     }
4115     set2->nodeNr = 0;
4116     return(set1);
4117 }
4118
4119 /**
4120  * xmlXPathNodeSetDel:
4121  * @cur:  the initial node set
4122  * @val:  an xmlNodePtr
4123  *
4124  * Removes an xmlNodePtr from an existing NodeSet
4125  */
4126 void
4127 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4128     int i;
4129
4130     if (cur == NULL) return;
4131     if (val == NULL) return;
4132
4133     /*
4134      * find node in nodeTab
4135      */
4136     for (i = 0;i < cur->nodeNr;i++)
4137         if (cur->nodeTab[i] == val) break;
4138
4139     if (i >= cur->nodeNr) {     /* not found */
4140 #ifdef DEBUG
4141         xmlGenericError(xmlGenericErrorContext,
4142                 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4143                 val->name);
4144 #endif
4145         return;
4146     }
4147     if ((cur->nodeTab[i] != NULL) &&
4148         (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4149         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4150     cur->nodeNr--;
4151     for (;i < cur->nodeNr;i++)
4152         cur->nodeTab[i] = cur->nodeTab[i + 1];
4153     cur->nodeTab[cur->nodeNr] = NULL;
4154 }
4155
4156 /**
4157  * xmlXPathNodeSetRemove:
4158  * @cur:  the initial node set
4159  * @val:  the index to remove
4160  *
4161  * Removes an entry from an existing NodeSet list.
4162  */
4163 void
4164 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4165     if (cur == NULL) return;
4166     if (val >= cur->nodeNr) return;
4167     if ((cur->nodeTab[val] != NULL) &&
4168         (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4169         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4170     cur->nodeNr--;
4171     for (;val < cur->nodeNr;val++)
4172         cur->nodeTab[val] = cur->nodeTab[val + 1];
4173     cur->nodeTab[cur->nodeNr] = NULL;
4174 }
4175
4176 /**
4177  * xmlXPathFreeNodeSet:
4178  * @obj:  the xmlNodeSetPtr to free
4179  *
4180  * Free the NodeSet compound (not the actual nodes !).
4181  */
4182 void
4183 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4184     if (obj == NULL) return;
4185     if (obj->nodeTab != NULL) {
4186         int i;
4187
4188         /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4189         for (i = 0;i < obj->nodeNr;i++)
4190             if ((obj->nodeTab[i] != NULL) &&
4191                 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4192                 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4193         xmlFree(obj->nodeTab);
4194     }
4195     xmlFree(obj);
4196 }
4197
4198 /**
4199  * xmlXPathNodeSetClear:
4200  * @set:  the node set to clear
4201  *
4202  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4203  * are feed), but does *not* free the list itself. Sets the length of the
4204  * list to 0.
4205  */
4206 static void
4207 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4208 {
4209     if ((set == NULL) || (set->nodeNr <= 0))
4210         return;
4211     else if (hasNsNodes) {
4212         int i;
4213         xmlNodePtr node;
4214
4215         for (i = 0; i < set->nodeNr; i++) {
4216             node = set->nodeTab[i];
4217             if ((node != NULL) &&
4218                 (node->type == XML_NAMESPACE_DECL))
4219                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4220         }
4221     }
4222     set->nodeNr = 0;
4223 }
4224
4225 /**
4226  * xmlXPathNodeSetClearFromPos:
4227  * @set: the node set to be cleared
4228  * @pos: the start position to clear from
4229  *
4230  * Clears the list from temporary XPath objects (e.g. namespace nodes
4231  * are feed) starting with the entry at @pos, but does *not* free the list
4232  * itself. Sets the length of the list to @pos.
4233  */
4234 static void
4235 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4236 {
4237     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4238         return;
4239     else if ((hasNsNodes)) {
4240         int i;
4241         xmlNodePtr node;
4242
4243         for (i = pos; i < set->nodeNr; i++) {
4244             node = set->nodeTab[i];
4245             if ((node != NULL) &&
4246                 (node->type == XML_NAMESPACE_DECL))
4247                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4248         }
4249     }
4250     set->nodeNr = pos;
4251 }
4252
4253 /**
4254  * xmlXPathFreeValueTree:
4255  * @obj:  the xmlNodeSetPtr to free
4256  *
4257  * Free the NodeSet compound and the actual tree, this is different
4258  * from xmlXPathFreeNodeSet()
4259  */
4260 static void
4261 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4262     int i;
4263
4264     if (obj == NULL) return;
4265
4266     if (obj->nodeTab != NULL) {
4267         for (i = 0;i < obj->nodeNr;i++) {
4268             if (obj->nodeTab[i] != NULL) {
4269                 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4270                     xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4271                 } else {
4272                     xmlFreeNodeList(obj->nodeTab[i]);
4273                 }
4274             }
4275         }
4276         xmlFree(obj->nodeTab);
4277     }
4278     xmlFree(obj);
4279 }
4280
4281 #if defined(DEBUG) || defined(DEBUG_STEP)
4282 /**
4283  * xmlGenericErrorContextNodeSet:
4284  * @output:  a FILE * for the output
4285  * @obj:  the xmlNodeSetPtr to display
4286  *
4287  * Quick display of a NodeSet
4288  */
4289 void
4290 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4291     int i;
4292
4293     if (output == NULL) output = xmlGenericErrorContext;
4294     if (obj == NULL)  {
4295         fprintf(output, "NodeSet == NULL !\n");
4296         return;
4297     }
4298     if (obj->nodeNr == 0) {
4299         fprintf(output, "NodeSet is empty\n");
4300         return;
4301     }
4302     if (obj->nodeTab == NULL) {
4303         fprintf(output, " nodeTab == NULL !\n");
4304         return;
4305     }
4306     for (i = 0; i < obj->nodeNr; i++) {
4307         if (obj->nodeTab[i] == NULL) {
4308             fprintf(output, " NULL !\n");
4309             return;
4310         }
4311         if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4312             (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4313             fprintf(output, " /");
4314         else if (obj->nodeTab[i]->name == NULL)
4315             fprintf(output, " noname!");
4316         else fprintf(output, " %s", obj->nodeTab[i]->name);
4317     }
4318     fprintf(output, "\n");
4319 }
4320 #endif
4321
4322 /**
4323  * xmlXPathNewNodeSet:
4324  * @val:  the NodePtr value
4325  *
4326  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4327  * it with the single Node @val
4328  *
4329  * Returns the newly created object.
4330  */
4331 xmlXPathObjectPtr
4332 xmlXPathNewNodeSet(xmlNodePtr val) {
4333     xmlXPathObjectPtr ret;
4334
4335     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4336     if (ret == NULL) {
4337         xmlXPathErrMemory(NULL, "creating nodeset\n");
4338         return(NULL);
4339     }
4340     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4341     ret->type = XPATH_NODESET;
4342     ret->boolval = 0;
4343     ret->nodesetval = xmlXPathNodeSetCreate(val);
4344     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4345 #ifdef XP_DEBUG_OBJ_USAGE
4346     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4347 #endif
4348     return(ret);
4349 }
4350
4351 /**
4352  * xmlXPathNewValueTree:
4353  * @val:  the NodePtr value
4354  *
4355  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4356  * it with the tree root @val
4357  *
4358  * Returns the newly created object.
4359  */
4360 xmlXPathObjectPtr
4361 xmlXPathNewValueTree(xmlNodePtr val) {
4362     xmlXPathObjectPtr ret;
4363
4364     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4365     if (ret == NULL) {
4366         xmlXPathErrMemory(NULL, "creating result value tree\n");
4367         return(NULL);
4368     }
4369     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4370     ret->type = XPATH_XSLT_TREE;
4371     ret->boolval = 1;
4372     ret->user = (void *) val;
4373     ret->nodesetval = xmlXPathNodeSetCreate(val);
4374 #ifdef XP_DEBUG_OBJ_USAGE
4375     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4376 #endif
4377     return(ret);
4378 }
4379
4380 /**
4381  * xmlXPathNewNodeSetList:
4382  * @val:  an existing NodeSet
4383  *
4384  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4385  * it with the Nodeset @val
4386  *
4387  * Returns the newly created object.
4388  */
4389 xmlXPathObjectPtr
4390 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4391 {
4392     xmlXPathObjectPtr ret;
4393     int i;
4394
4395     if (val == NULL)
4396         ret = NULL;
4397     else if (val->nodeTab == NULL)
4398         ret = xmlXPathNewNodeSet(NULL);
4399     else {
4400         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4401         if (ret) {
4402             for (i = 1; i < val->nodeNr; ++i) {
4403                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4404                     < 0) break;
4405             }
4406         }
4407     }
4408
4409     return (ret);
4410 }
4411
4412 /**
4413  * xmlXPathWrapNodeSet:
4414  * @val:  the NodePtr value
4415  *
4416  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4417  *
4418  * Returns the newly created object.
4419  */
4420 xmlXPathObjectPtr
4421 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4422     xmlXPathObjectPtr ret;
4423
4424     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4425     if (ret == NULL) {
4426         xmlXPathErrMemory(NULL, "creating node set object\n");
4427         return(NULL);
4428     }
4429     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4430     ret->type = XPATH_NODESET;
4431     ret->nodesetval = val;
4432 #ifdef XP_DEBUG_OBJ_USAGE
4433     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4434 #endif
4435     return(ret);
4436 }
4437
4438 /**
4439  * xmlXPathFreeNodeSetList:
4440  * @obj:  an existing NodeSetList object
4441  *
4442  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4443  * the list contrary to xmlXPathFreeObject().
4444  */
4445 void
4446 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4447     if (obj == NULL) return;
4448 #ifdef XP_DEBUG_OBJ_USAGE
4449     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4450 #endif
4451     xmlFree(obj);
4452 }
4453
4454 /**
4455  * xmlXPathDifference:
4456  * @nodes1:  a node-set
4457  * @nodes2:  a node-set
4458  *
4459  * Implements the EXSLT - Sets difference() function:
4460  *    node-set set:difference (node-set, node-set)
4461  *
4462  * Returns the difference between the two node sets, or nodes1 if
4463  *         nodes2 is empty
4464  */
4465 xmlNodeSetPtr
4466 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4467     xmlNodeSetPtr ret;
4468     int i, l1;
4469     xmlNodePtr cur;
4470
4471     if (xmlXPathNodeSetIsEmpty(nodes2))
4472         return(nodes1);
4473
4474     ret = xmlXPathNodeSetCreate(NULL);
4475     if (xmlXPathNodeSetIsEmpty(nodes1))
4476         return(ret);
4477
4478     l1 = xmlXPathNodeSetGetLength(nodes1);
4479
4480     for (i = 0; i < l1; i++) {
4481         cur = xmlXPathNodeSetItem(nodes1, i);
4482         if (!xmlXPathNodeSetContains(nodes2, cur)) {
4483             if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4484                 break;
4485         }
4486     }
4487     return(ret);
4488 }
4489
4490 /**
4491  * xmlXPathIntersection:
4492  * @nodes1:  a node-set
4493  * @nodes2:  a node-set
4494  *
4495  * Implements the EXSLT - Sets intersection() function:
4496  *    node-set set:intersection (node-set, node-set)
4497  *
4498  * Returns a node set comprising the nodes that are within both the
4499  *         node sets passed as arguments
4500  */
4501 xmlNodeSetPtr
4502 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4503     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4504     int i, l1;
4505     xmlNodePtr cur;
4506
4507     if (ret == NULL)
4508         return(ret);
4509     if (xmlXPathNodeSetIsEmpty(nodes1))
4510         return(ret);
4511     if (xmlXPathNodeSetIsEmpty(nodes2))
4512         return(ret);
4513
4514     l1 = xmlXPathNodeSetGetLength(nodes1);
4515
4516     for (i = 0; i < l1; i++) {
4517         cur = xmlXPathNodeSetItem(nodes1, i);
4518         if (xmlXPathNodeSetContains(nodes2, cur)) {
4519             if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4520                 break;
4521         }
4522     }
4523     return(ret);
4524 }
4525
4526 /**
4527  * xmlXPathDistinctSorted:
4528  * @nodes:  a node-set, sorted by document order
4529  *
4530  * Implements the EXSLT - Sets distinct() function:
4531  *    node-set set:distinct (node-set)
4532  *
4533  * Returns a subset of the nodes contained in @nodes, or @nodes if
4534  *         it is empty
4535  */
4536 xmlNodeSetPtr
4537 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4538     xmlNodeSetPtr ret;
4539     xmlHashTablePtr hash;
4540     int i, l;
4541     xmlChar * strval;
4542     xmlNodePtr cur;
4543
4544     if (xmlXPathNodeSetIsEmpty(nodes))
4545         return(nodes);
4546
4547     ret = xmlXPathNodeSetCreate(NULL);
4548     if (ret == NULL)
4549         return(ret);
4550     l = xmlXPathNodeSetGetLength(nodes);
4551     hash = xmlHashCreate (l);
4552     for (i = 0; i < l; i++) {
4553         cur = xmlXPathNodeSetItem(nodes, i);
4554         strval = xmlXPathCastNodeToString(cur);
4555         if (xmlHashLookup(hash, strval) == NULL) {
4556             xmlHashAddEntry(hash, strval, strval);
4557             if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4558                 break;
4559         } else {
4560             xmlFree(strval);
4561         }
4562     }
4563     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4564     return(ret);
4565 }
4566
4567 /**
4568  * xmlXPathDistinct:
4569  * @nodes:  a node-set
4570  *
4571  * Implements the EXSLT - Sets distinct() function:
4572  *    node-set set:distinct (node-set)
4573  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4574  * is called with the sorted node-set
4575  *
4576  * Returns a subset of the nodes contained in @nodes, or @nodes if
4577  *         it is empty
4578  */
4579 xmlNodeSetPtr
4580 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4581     if (xmlXPathNodeSetIsEmpty(nodes))
4582         return(nodes);
4583
4584     xmlXPathNodeSetSort(nodes);
4585     return(xmlXPathDistinctSorted(nodes));
4586 }
4587
4588 /**
4589  * xmlXPathHasSameNodes:
4590  * @nodes1:  a node-set
4591  * @nodes2:  a node-set
4592  *
4593  * Implements the EXSLT - Sets has-same-nodes function:
4594  *    boolean set:has-same-node(node-set, node-set)
4595  *
4596  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4597  *         otherwise
4598  */
4599 int
4600 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4601     int i, l;
4602     xmlNodePtr cur;
4603
4604     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4605         xmlXPathNodeSetIsEmpty(nodes2))
4606         return(0);
4607
4608     l = xmlXPathNodeSetGetLength(nodes1);
4609     for (i = 0; i < l; i++) {
4610         cur = xmlXPathNodeSetItem(nodes1, i);
4611         if (xmlXPathNodeSetContains(nodes2, cur))
4612             return(1);
4613     }
4614     return(0);
4615 }
4616
4617 /**
4618  * xmlXPathNodeLeadingSorted:
4619  * @nodes: a node-set, sorted by document order
4620  * @node: a node
4621  *
4622  * Implements the EXSLT - Sets leading() function:
4623  *    node-set set:leading (node-set, node-set)
4624  *
4625  * Returns the nodes in @nodes that precede @node in document order,
4626  *         @nodes if @node is NULL or an empty node-set if @nodes
4627  *         doesn't contain @node
4628  */
4629 xmlNodeSetPtr
4630 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4631     int i, l;
4632     xmlNodePtr cur;
4633     xmlNodeSetPtr ret;
4634
4635     if (node == NULL)
4636         return(nodes);
4637
4638     ret = xmlXPathNodeSetCreate(NULL);
4639     if (ret == NULL)
4640         return(ret);
4641     if (xmlXPathNodeSetIsEmpty(nodes) ||
4642         (!xmlXPathNodeSetContains(nodes, node)))
4643         return(ret);
4644
4645     l = xmlXPathNodeSetGetLength(nodes);
4646     for (i = 0; i < l; i++) {
4647         cur = xmlXPathNodeSetItem(nodes, i);
4648         if (cur == node)
4649             break;
4650         if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4651             break;
4652     }
4653     return(ret);
4654 }
4655
4656 /**
4657  * xmlXPathNodeLeading:
4658  * @nodes:  a node-set
4659  * @node:  a node
4660  *
4661  * Implements the EXSLT - Sets leading() function:
4662  *    node-set set:leading (node-set, node-set)
4663  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4664  * is called.
4665  *
4666  * Returns the nodes in @nodes that precede @node in document order,
4667  *         @nodes if @node is NULL or an empty node-set if @nodes
4668  *         doesn't contain @node
4669  */
4670 xmlNodeSetPtr
4671 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4672     xmlXPathNodeSetSort(nodes);
4673     return(xmlXPathNodeLeadingSorted(nodes, node));
4674 }
4675
4676 /**
4677  * xmlXPathLeadingSorted:
4678  * @nodes1:  a node-set, sorted by document order
4679  * @nodes2:  a node-set, sorted by document order
4680  *
4681  * Implements the EXSLT - Sets leading() function:
4682  *    node-set set:leading (node-set, node-set)
4683  *
4684  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4685  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4686  *         an empty node-set if @nodes1 doesn't contain @nodes2
4687  */
4688 xmlNodeSetPtr
4689 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4690     if (xmlXPathNodeSetIsEmpty(nodes2))
4691         return(nodes1);
4692     return(xmlXPathNodeLeadingSorted(nodes1,
4693                                      xmlXPathNodeSetItem(nodes2, 1)));
4694 }
4695
4696 /**
4697  * xmlXPathLeading:
4698  * @nodes1:  a node-set
4699  * @nodes2:  a node-set
4700  *
4701  * Implements the EXSLT - Sets leading() function:
4702  *    node-set set:leading (node-set, node-set)
4703  * @nodes1 and @nodes2 are sorted by document order, then
4704  * #exslSetsLeadingSorted is called.
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 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4712     if (xmlXPathNodeSetIsEmpty(nodes2))
4713         return(nodes1);
4714     if (xmlXPathNodeSetIsEmpty(nodes1))
4715         return(xmlXPathNodeSetCreate(NULL));
4716     xmlXPathNodeSetSort(nodes1);
4717     xmlXPathNodeSetSort(nodes2);
4718     return(xmlXPathNodeLeadingSorted(nodes1,
4719                                      xmlXPathNodeSetItem(nodes2, 1)));
4720 }
4721
4722 /**
4723  * xmlXPathNodeTrailingSorted:
4724  * @nodes: a node-set, sorted by document order
4725  * @node: a node
4726  *
4727  * Implements the EXSLT - Sets trailing() function:
4728  *    node-set set:trailing (node-set, node-set)
4729  *
4730  * Returns the nodes in @nodes that follow @node in document order,
4731  *         @nodes if @node is NULL or an empty node-set if @nodes
4732  *         doesn't contain @node
4733  */
4734 xmlNodeSetPtr
4735 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4736     int i, l;
4737     xmlNodePtr cur;
4738     xmlNodeSetPtr ret;
4739
4740     if (node == NULL)
4741         return(nodes);
4742
4743     ret = xmlXPathNodeSetCreate(NULL);
4744     if (ret == NULL)
4745         return(ret);
4746     if (xmlXPathNodeSetIsEmpty(nodes) ||
4747         (!xmlXPathNodeSetContains(nodes, node)))
4748         return(ret);
4749
4750     l = xmlXPathNodeSetGetLength(nodes);
4751     for (i = l - 1; i >= 0; i--) {
4752         cur = xmlXPathNodeSetItem(nodes, i);
4753         if (cur == node)
4754             break;
4755         if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4756             break;
4757     }
4758     xmlXPathNodeSetSort(ret);   /* bug 413451 */
4759     return(ret);
4760 }
4761
4762 /**
4763  * xmlXPathNodeTrailing:
4764  * @nodes:  a node-set
4765  * @node:  a node
4766  *
4767  * Implements the EXSLT - Sets trailing() function:
4768  *    node-set set:trailing (node-set, node-set)
4769  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4770  * is called.
4771  *
4772  * Returns the nodes in @nodes that follow @node in document order,
4773  *         @nodes if @node is NULL or an empty node-set if @nodes
4774  *         doesn't contain @node
4775  */
4776 xmlNodeSetPtr
4777 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4778     xmlXPathNodeSetSort(nodes);
4779     return(xmlXPathNodeTrailingSorted(nodes, node));
4780 }
4781
4782 /**
4783  * xmlXPathTrailingSorted:
4784  * @nodes1:  a node-set, sorted by document order
4785  * @nodes2:  a node-set, sorted by document order
4786  *
4787  * Implements the EXSLT - Sets trailing() function:
4788  *    node-set set:trailing (node-set, node-set)
4789  *
4790  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4791  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4792  *         an empty node-set if @nodes1 doesn't contain @nodes2
4793  */
4794 xmlNodeSetPtr
4795 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4796     if (xmlXPathNodeSetIsEmpty(nodes2))
4797         return(nodes1);
4798     return(xmlXPathNodeTrailingSorted(nodes1,
4799                                       xmlXPathNodeSetItem(nodes2, 0)));
4800 }
4801
4802 /**
4803  * xmlXPathTrailing:
4804  * @nodes1:  a node-set
4805  * @nodes2:  a node-set
4806  *
4807  * Implements the EXSLT - Sets trailing() function:
4808  *    node-set set:trailing (node-set, node-set)
4809  * @nodes1 and @nodes2 are sorted by document order, then
4810  * #xmlXPathTrailingSorted is called.
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 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4818     if (xmlXPathNodeSetIsEmpty(nodes2))
4819         return(nodes1);
4820     if (xmlXPathNodeSetIsEmpty(nodes1))
4821         return(xmlXPathNodeSetCreate(NULL));
4822     xmlXPathNodeSetSort(nodes1);
4823     xmlXPathNodeSetSort(nodes2);
4824     return(xmlXPathNodeTrailingSorted(nodes1,
4825                                       xmlXPathNodeSetItem(nodes2, 0)));
4826 }
4827
4828 /************************************************************************
4829  *                                                                      *
4830  *              Routines to handle extra functions                      *
4831  *                                                                      *
4832  ************************************************************************/
4833
4834 /**
4835  * xmlXPathRegisterFunc:
4836  * @ctxt:  the XPath context
4837  * @name:  the function name
4838  * @f:  the function implementation or NULL
4839  *
4840  * Register a new function. If @f is NULL it unregisters the function
4841  *
4842  * Returns 0 in case of success, -1 in case of error
4843  */
4844 int
4845 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4846                      xmlXPathFunction f) {
4847     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4848 }
4849
4850 /**
4851  * xmlXPathRegisterFuncNS:
4852  * @ctxt:  the XPath context
4853  * @name:  the function name
4854  * @ns_uri:  the function namespace URI
4855  * @f:  the function implementation or NULL
4856  *
4857  * Register a new function. If @f is NULL it unregisters the function
4858  *
4859  * Returns 0 in case of success, -1 in case of error
4860  */
4861 int
4862 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4863                        const xmlChar *ns_uri, xmlXPathFunction f) {
4864     if (ctxt == NULL)
4865         return(-1);
4866     if (name == NULL)
4867         return(-1);
4868
4869     if (ctxt->funcHash == NULL)
4870         ctxt->funcHash = xmlHashCreate(0);
4871     if (ctxt->funcHash == NULL)
4872         return(-1);
4873     if (f == NULL)
4874         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4875     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4876 }
4877
4878 /**
4879  * xmlXPathRegisterFuncLookup:
4880  * @ctxt:  the XPath context
4881  * @f:  the lookup function
4882  * @funcCtxt:  the lookup data
4883  *
4884  * Registers an external mechanism to do function lookup.
4885  */
4886 void
4887 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4888                             xmlXPathFuncLookupFunc f,
4889                             void *funcCtxt) {
4890     if (ctxt == NULL)
4891         return;
4892     ctxt->funcLookupFunc = f;
4893     ctxt->funcLookupData = funcCtxt;
4894 }
4895
4896 /**
4897  * xmlXPathFunctionLookup:
4898  * @ctxt:  the XPath context
4899  * @name:  the function name
4900  *
4901  * Search in the Function array of the context for the given
4902  * function.
4903  *
4904  * Returns the xmlXPathFunction or NULL if not found
4905  */
4906 xmlXPathFunction
4907 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4908     if (ctxt == NULL)
4909         return (NULL);
4910
4911     if (ctxt->funcLookupFunc != NULL) {
4912         xmlXPathFunction ret;
4913         xmlXPathFuncLookupFunc f;
4914
4915         f = ctxt->funcLookupFunc;
4916         ret = f(ctxt->funcLookupData, name, NULL);
4917         if (ret != NULL)
4918             return(ret);
4919     }
4920     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4921 }
4922
4923 /**
4924  * xmlXPathFunctionLookupNS:
4925  * @ctxt:  the XPath context
4926  * @name:  the function name
4927  * @ns_uri:  the function namespace URI
4928  *
4929  * Search in the Function array of the context for the given
4930  * function.
4931  *
4932  * Returns the xmlXPathFunction or NULL if not found
4933  */
4934 xmlXPathFunction
4935 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4936                          const xmlChar *ns_uri) {
4937     xmlXPathFunction ret;
4938
4939     if (ctxt == NULL)
4940         return(NULL);
4941     if (name == NULL)
4942         return(NULL);
4943
4944     if (ctxt->funcLookupFunc != NULL) {
4945         xmlXPathFuncLookupFunc f;
4946
4947         f = ctxt->funcLookupFunc;
4948         ret = f(ctxt->funcLookupData, name, ns_uri);
4949         if (ret != NULL)
4950             return(ret);
4951     }
4952
4953     if (ctxt->funcHash == NULL)
4954         return(NULL);
4955
4956     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4957     return(ret);
4958 }
4959
4960 /**
4961  * xmlXPathRegisteredFuncsCleanup:
4962  * @ctxt:  the XPath context
4963  *
4964  * Cleanup the XPath context data associated to registered functions
4965  */
4966 void
4967 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4968     if (ctxt == NULL)
4969         return;
4970
4971     xmlHashFree(ctxt->funcHash, NULL);
4972     ctxt->funcHash = NULL;
4973 }
4974
4975 /************************************************************************
4976  *                                                                      *
4977  *                      Routines to handle Variables                    *
4978  *                                                                      *
4979  ************************************************************************/
4980
4981 /**
4982  * xmlXPathRegisterVariable:
4983  * @ctxt:  the XPath context
4984  * @name:  the variable name
4985  * @value:  the variable value or NULL
4986  *
4987  * Register a new variable value. If @value is NULL it unregisters
4988  * the variable
4989  *
4990  * Returns 0 in case of success, -1 in case of error
4991  */
4992 int
4993 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4994                          xmlXPathObjectPtr value) {
4995     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4996 }
4997
4998 /**
4999  * xmlXPathRegisterVariableNS:
5000  * @ctxt:  the XPath context
5001  * @name:  the variable name
5002  * @ns_uri:  the variable namespace URI
5003  * @value:  the variable value or NULL
5004  *
5005  * Register a new variable value. If @value is NULL it unregisters
5006  * the variable
5007  *
5008  * Returns 0 in case of success, -1 in case of error
5009  */
5010 int
5011 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5012                            const xmlChar *ns_uri,
5013                            xmlXPathObjectPtr value) {
5014     if (ctxt == NULL)
5015         return(-1);
5016     if (name == NULL)
5017         return(-1);
5018
5019     if (ctxt->varHash == NULL)
5020         ctxt->varHash = xmlHashCreate(0);
5021     if (ctxt->varHash == NULL)
5022         return(-1);
5023     if (value == NULL)
5024         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5025                                    (xmlHashDeallocator)xmlXPathFreeObject));
5026     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5027                                (void *) value,
5028                                (xmlHashDeallocator)xmlXPathFreeObject));
5029 }
5030
5031 /**
5032  * xmlXPathRegisterVariableLookup:
5033  * @ctxt:  the XPath context
5034  * @f:  the lookup function
5035  * @data:  the lookup data
5036  *
5037  * register an external mechanism to do variable lookup
5038  */
5039 void
5040 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5041          xmlXPathVariableLookupFunc f, void *data) {
5042     if (ctxt == NULL)
5043         return;
5044     ctxt->varLookupFunc = f;
5045     ctxt->varLookupData = data;
5046 }
5047
5048 /**
5049  * xmlXPathVariableLookup:
5050  * @ctxt:  the XPath context
5051  * @name:  the variable name
5052  *
5053  * Search in the Variable array of the context for the given
5054  * variable value.
5055  *
5056  * Returns a copy of the value or NULL if not found
5057  */
5058 xmlXPathObjectPtr
5059 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5060     if (ctxt == NULL)
5061         return(NULL);
5062
5063     if (ctxt->varLookupFunc != NULL) {
5064         xmlXPathObjectPtr ret;
5065
5066         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5067                 (ctxt->varLookupData, name, NULL);
5068         return(ret);
5069     }
5070     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5071 }
5072
5073 /**
5074  * xmlXPathVariableLookupNS:
5075  * @ctxt:  the XPath context
5076  * @name:  the variable name
5077  * @ns_uri:  the variable namespace URI
5078  *
5079  * Search in the Variable array of the context for the given
5080  * variable value.
5081  *
5082  * Returns the a copy of the value or NULL if not found
5083  */
5084 xmlXPathObjectPtr
5085 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5086                          const xmlChar *ns_uri) {
5087     if (ctxt == NULL)
5088         return(NULL);
5089
5090     if (ctxt->varLookupFunc != NULL) {
5091         xmlXPathObjectPtr ret;
5092
5093         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5094                 (ctxt->varLookupData, name, ns_uri);
5095         if (ret != NULL) return(ret);
5096     }
5097
5098     if (ctxt->varHash == NULL)
5099         return(NULL);
5100     if (name == NULL)
5101         return(NULL);
5102
5103     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5104                 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5105 }
5106
5107 /**
5108  * xmlXPathRegisteredVariablesCleanup:
5109  * @ctxt:  the XPath context
5110  *
5111  * Cleanup the XPath context data associated to registered variables
5112  */
5113 void
5114 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5115     if (ctxt == NULL)
5116         return;
5117
5118     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5119     ctxt->varHash = NULL;
5120 }
5121
5122 /**
5123  * xmlXPathRegisterNs:
5124  * @ctxt:  the XPath context
5125  * @prefix:  the namespace prefix cannot be NULL or empty string
5126  * @ns_uri:  the namespace name
5127  *
5128  * Register a new namespace. If @ns_uri is NULL it unregisters
5129  * the namespace
5130  *
5131  * Returns 0 in case of success, -1 in case of error
5132  */
5133 int
5134 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5135                            const xmlChar *ns_uri) {
5136     if (ctxt == NULL)
5137         return(-1);
5138     if (prefix == NULL)
5139         return(-1);
5140     if (prefix[0] == 0)
5141         return(-1);
5142
5143     if (ctxt->nsHash == NULL)
5144         ctxt->nsHash = xmlHashCreate(10);
5145     if (ctxt->nsHash == NULL)
5146         return(-1);
5147     if (ns_uri == NULL)
5148         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5149                                   (xmlHashDeallocator)xmlFree));
5150     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5151                               (xmlHashDeallocator)xmlFree));
5152 }
5153
5154 /**
5155  * xmlXPathNsLookup:
5156  * @ctxt:  the XPath context
5157  * @prefix:  the namespace prefix value
5158  *
5159  * Search in the namespace declaration array of the context for the given
5160  * namespace name associated to the given prefix
5161  *
5162  * Returns the value or NULL if not found
5163  */
5164 const xmlChar *
5165 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5166     if (ctxt == NULL)
5167         return(NULL);
5168     if (prefix == NULL)
5169         return(NULL);
5170
5171 #ifdef XML_XML_NAMESPACE
5172     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5173         return(XML_XML_NAMESPACE);
5174 #endif
5175
5176     if (ctxt->namespaces != NULL) {
5177         int i;
5178
5179         for (i = 0;i < ctxt->nsNr;i++) {
5180             if ((ctxt->namespaces[i] != NULL) &&
5181                 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5182                 return(ctxt->namespaces[i]->href);
5183         }
5184     }
5185
5186     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5187 }
5188
5189 /**
5190  * xmlXPathRegisteredNsCleanup:
5191  * @ctxt:  the XPath context
5192  *
5193  * Cleanup the XPath context data associated to registered variables
5194  */
5195 void
5196 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5197     if (ctxt == NULL)
5198         return;
5199
5200     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5201     ctxt->nsHash = NULL;
5202 }
5203
5204 /************************************************************************
5205  *                                                                      *
5206  *                      Routines to handle Values                       *
5207  *                                                                      *
5208  ************************************************************************/
5209
5210 /* Allocations are terrible, one needs to optimize all this !!! */
5211
5212 /**
5213  * xmlXPathNewFloat:
5214  * @val:  the double value
5215  *
5216  * Create a new xmlXPathObjectPtr of type double and of value @val
5217  *
5218  * Returns the newly created object.
5219  */
5220 xmlXPathObjectPtr
5221 xmlXPathNewFloat(double val) {
5222     xmlXPathObjectPtr ret;
5223
5224     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5225     if (ret == NULL) {
5226         xmlXPathErrMemory(NULL, "creating float object\n");
5227         return(NULL);
5228     }
5229     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5230     ret->type = XPATH_NUMBER;
5231     ret->floatval = val;
5232 #ifdef XP_DEBUG_OBJ_USAGE
5233     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5234 #endif
5235     return(ret);
5236 }
5237
5238 /**
5239  * xmlXPathNewBoolean:
5240  * @val:  the boolean value
5241  *
5242  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5243  *
5244  * Returns the newly created object.
5245  */
5246 xmlXPathObjectPtr
5247 xmlXPathNewBoolean(int val) {
5248     xmlXPathObjectPtr ret;
5249
5250     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5251     if (ret == NULL) {
5252         xmlXPathErrMemory(NULL, "creating boolean object\n");
5253         return(NULL);
5254     }
5255     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5256     ret->type = XPATH_BOOLEAN;
5257     ret->boolval = (val != 0);
5258 #ifdef XP_DEBUG_OBJ_USAGE
5259     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5260 #endif
5261     return(ret);
5262 }
5263
5264 /**
5265  * xmlXPathNewString:
5266  * @val:  the xmlChar * value
5267  *
5268  * Create a new xmlXPathObjectPtr of type string and of value @val
5269  *
5270  * Returns the newly created object.
5271  */
5272 xmlXPathObjectPtr
5273 xmlXPathNewString(const xmlChar *val) {
5274     xmlXPathObjectPtr ret;
5275
5276     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5277     if (ret == NULL) {
5278         xmlXPathErrMemory(NULL, "creating string object\n");
5279         return(NULL);
5280     }
5281     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5282     ret->type = XPATH_STRING;
5283     if (val != NULL)
5284         ret->stringval = xmlStrdup(val);
5285     else
5286         ret->stringval = xmlStrdup((const xmlChar *)"");
5287 #ifdef XP_DEBUG_OBJ_USAGE
5288     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5289 #endif
5290     return(ret);
5291 }
5292
5293 /**
5294  * xmlXPathWrapString:
5295  * @val:  the xmlChar * value
5296  *
5297  * Wraps the @val string into an XPath object.
5298  *
5299  * Returns the newly created object.
5300  */
5301 xmlXPathObjectPtr
5302 xmlXPathWrapString (xmlChar *val) {
5303     xmlXPathObjectPtr ret;
5304
5305     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5306     if (ret == NULL) {
5307         xmlXPathErrMemory(NULL, "creating string object\n");
5308         return(NULL);
5309     }
5310     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5311     ret->type = XPATH_STRING;
5312     ret->stringval = val;
5313 #ifdef XP_DEBUG_OBJ_USAGE
5314     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5315 #endif
5316     return(ret);
5317 }
5318
5319 /**
5320  * xmlXPathNewCString:
5321  * @val:  the char * value
5322  *
5323  * Create a new xmlXPathObjectPtr of type string and of value @val
5324  *
5325  * Returns the newly created object.
5326  */
5327 xmlXPathObjectPtr
5328 xmlXPathNewCString(const char *val) {
5329     xmlXPathObjectPtr ret;
5330
5331     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5332     if (ret == NULL) {
5333         xmlXPathErrMemory(NULL, "creating string object\n");
5334         return(NULL);
5335     }
5336     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5337     ret->type = XPATH_STRING;
5338     ret->stringval = xmlStrdup(BAD_CAST val);
5339 #ifdef XP_DEBUG_OBJ_USAGE
5340     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5341 #endif
5342     return(ret);
5343 }
5344
5345 /**
5346  * xmlXPathWrapCString:
5347  * @val:  the char * value
5348  *
5349  * Wraps a string into an XPath object.
5350  *
5351  * Returns the newly created object.
5352  */
5353 xmlXPathObjectPtr
5354 xmlXPathWrapCString (char * val) {
5355     return(xmlXPathWrapString((xmlChar *)(val)));
5356 }
5357
5358 /**
5359  * xmlXPathWrapExternal:
5360  * @val:  the user data
5361  *
5362  * Wraps the @val data into an XPath object.
5363  *
5364  * Returns the newly created object.
5365  */
5366 xmlXPathObjectPtr
5367 xmlXPathWrapExternal (void *val) {
5368     xmlXPathObjectPtr ret;
5369
5370     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5371     if (ret == NULL) {
5372         xmlXPathErrMemory(NULL, "creating user object\n");
5373         return(NULL);
5374     }
5375     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5376     ret->type = XPATH_USERS;
5377     ret->user = val;
5378 #ifdef XP_DEBUG_OBJ_USAGE
5379     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5380 #endif
5381     return(ret);
5382 }
5383
5384 /**
5385  * xmlXPathObjectCopy:
5386  * @val:  the original object
5387  *
5388  * allocate a new copy of a given object
5389  *
5390  * Returns the newly created object.
5391  */
5392 xmlXPathObjectPtr
5393 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5394     xmlXPathObjectPtr ret;
5395
5396     if (val == NULL)
5397         return(NULL);
5398
5399     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5400     if (ret == NULL) {
5401         xmlXPathErrMemory(NULL, "copying object\n");
5402         return(NULL);
5403     }
5404     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5405 #ifdef XP_DEBUG_OBJ_USAGE
5406     xmlXPathDebugObjUsageRequested(NULL, val->type);
5407 #endif
5408     switch (val->type) {
5409         case XPATH_BOOLEAN:
5410         case XPATH_NUMBER:
5411         case XPATH_POINT:
5412         case XPATH_RANGE:
5413             break;
5414         case XPATH_STRING:
5415             ret->stringval = xmlStrdup(val->stringval);
5416             break;
5417         case XPATH_XSLT_TREE:
5418 #if 0
5419 /*
5420   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5421   this previous handling is no longer correct, and can cause some serious
5422   problems (ref. bug 145547)
5423 */
5424             if ((val->nodesetval != NULL) &&
5425                 (val->nodesetval->nodeTab != NULL)) {
5426                 xmlNodePtr cur, tmp;
5427                 xmlDocPtr top;
5428
5429                 ret->boolval = 1;
5430                 top =  xmlNewDoc(NULL);
5431                 top->name = (char *)
5432                     xmlStrdup(val->nodesetval->nodeTab[0]->name);
5433                 ret->user = top;
5434                 if (top != NULL) {
5435                     top->doc = top;
5436                     cur = val->nodesetval->nodeTab[0]->children;
5437                     while (cur != NULL) {
5438                         tmp = xmlDocCopyNode(cur, top, 1);
5439                         xmlAddChild((xmlNodePtr) top, tmp);
5440                         cur = cur->next;
5441                     }
5442                 }
5443
5444                 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5445             } else
5446                 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5447             /* Deallocate the copied tree value */
5448             break;
5449 #endif
5450         case XPATH_NODESET:
5451             ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5452             /* Do not deallocate the copied tree value */
5453             ret->boolval = 0;
5454             break;
5455         case XPATH_LOCATIONSET:
5456 #ifdef LIBXML_XPTR_ENABLED
5457         {
5458             xmlLocationSetPtr loc = val->user;
5459             ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5460             break;
5461         }
5462 #endif
5463         case XPATH_USERS:
5464             ret->user = val->user;
5465             break;
5466         case XPATH_UNDEFINED:
5467             xmlGenericError(xmlGenericErrorContext,
5468                     "xmlXPathObjectCopy: unsupported type %d\n",
5469                     val->type);
5470             break;
5471     }
5472     return(ret);
5473 }
5474
5475 /**
5476  * xmlXPathFreeObject:
5477  * @obj:  the object to free
5478  *
5479  * Free up an xmlXPathObjectPtr object.
5480  */
5481 void
5482 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5483     if (obj == NULL) return;
5484     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5485         if (obj->boolval) {
5486 #if 0
5487             if (obj->user != NULL) {
5488                 xmlXPathFreeNodeSet(obj->nodesetval);
5489                 xmlFreeNodeList((xmlNodePtr) obj->user);
5490             } else
5491 #endif
5492             obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5493             if (obj->nodesetval != NULL)
5494                 xmlXPathFreeValueTree(obj->nodesetval);
5495         } else {
5496             if (obj->nodesetval != NULL)
5497                 xmlXPathFreeNodeSet(obj->nodesetval);
5498         }
5499 #ifdef LIBXML_XPTR_ENABLED
5500     } else if (obj->type == XPATH_LOCATIONSET) {
5501         if (obj->user != NULL)
5502             xmlXPtrFreeLocationSet(obj->user);
5503 #endif
5504     } else if (obj->type == XPATH_STRING) {
5505         if (obj->stringval != NULL)
5506             xmlFree(obj->stringval);
5507     }
5508 #ifdef XP_DEBUG_OBJ_USAGE
5509     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5510 #endif
5511     xmlFree(obj);
5512 }
5513
5514 /**
5515  * xmlXPathReleaseObject:
5516  * @obj:  the xmlXPathObjectPtr to free or to cache
5517  *
5518  * Depending on the state of the cache this frees the given
5519  * XPath object or stores it in the cache.
5520  */
5521 static void
5522 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5523 {
5524 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5525         sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5526     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5527
5528 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5529
5530     if (obj == NULL)
5531         return;
5532     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5533          xmlXPathFreeObject(obj);
5534     } else {
5535         xmlXPathContextCachePtr cache =
5536             (xmlXPathContextCachePtr) ctxt->cache;
5537
5538         switch (obj->type) {
5539             case XPATH_NODESET:
5540             case XPATH_XSLT_TREE:
5541                 if (obj->nodesetval != NULL) {
5542                     if (obj->boolval) {
5543                         /*
5544                         * It looks like the @boolval is used for
5545                         * evaluation if this an XSLT Result Tree Fragment.
5546                         * TODO: Check if this assumption is correct.
5547                         */
5548                         obj->type = XPATH_XSLT_TREE; /* just for debugging */
5549                         xmlXPathFreeValueTree(obj->nodesetval);
5550                         obj->nodesetval = NULL;
5551                     } else if ((obj->nodesetval->nodeMax <= 40) &&
5552                         (XP_CACHE_WANTS(cache->nodesetObjs,
5553                                         cache->maxNodeset)))
5554                     {
5555                         XP_CACHE_ADD(cache->nodesetObjs, obj);
5556                         goto obj_cached;
5557                     } else {
5558                         xmlXPathFreeNodeSet(obj->nodesetval);
5559                         obj->nodesetval = NULL;
5560                     }
5561                 }
5562                 break;
5563             case XPATH_STRING:
5564                 if (obj->stringval != NULL)
5565                     xmlFree(obj->stringval);
5566
5567                 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5568                     XP_CACHE_ADD(cache->stringObjs, obj);
5569                     goto obj_cached;
5570                 }
5571                 break;
5572             case XPATH_BOOLEAN:
5573                 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5574                     XP_CACHE_ADD(cache->booleanObjs, obj);
5575                     goto obj_cached;
5576                 }
5577                 break;
5578             case XPATH_NUMBER:
5579                 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5580                     XP_CACHE_ADD(cache->numberObjs, obj);
5581                     goto obj_cached;
5582                 }
5583                 break;
5584 #ifdef LIBXML_XPTR_ENABLED
5585             case XPATH_LOCATIONSET:
5586                 if (obj->user != NULL) {
5587                     xmlXPtrFreeLocationSet(obj->user);
5588                 }
5589                 goto free_obj;
5590 #endif
5591             default:
5592                 goto free_obj;
5593         }
5594
5595         /*
5596         * Fallback to adding to the misc-objects slot.
5597         */
5598         if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5599             XP_CACHE_ADD(cache->miscObjs, obj);
5600         } else
5601             goto free_obj;
5602
5603 obj_cached:
5604
5605 #ifdef XP_DEBUG_OBJ_USAGE
5606         xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5607 #endif
5608
5609         if (obj->nodesetval != NULL) {
5610             xmlNodeSetPtr tmpset = obj->nodesetval;
5611
5612             /*
5613             * TODO: Due to those nasty ns-nodes, we need to traverse
5614             *  the list and free the ns-nodes.
5615             * URGENT TODO: Check if it's actually slowing things down.
5616             *  Maybe we shouldn't try to preserve the list.
5617             */
5618             if (tmpset->nodeNr > 1) {
5619                 int i;
5620                 xmlNodePtr node;
5621
5622                 for (i = 0; i < tmpset->nodeNr; i++) {
5623                     node = tmpset->nodeTab[i];
5624                     if ((node != NULL) &&
5625                         (node->type == XML_NAMESPACE_DECL))
5626                     {
5627                         xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5628                     }
5629                 }
5630             } else if (tmpset->nodeNr == 1) {
5631                 if ((tmpset->nodeTab[0] != NULL) &&
5632                     (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5633                     xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5634             }
5635             tmpset->nodeNr = 0;
5636             memset(obj, 0, sizeof(xmlXPathObject));
5637             obj->nodesetval = tmpset;
5638         } else
5639             memset(obj, 0, sizeof(xmlXPathObject));
5640
5641         return;
5642
5643 free_obj:
5644         /*
5645         * Cache is full; free the object.
5646         */
5647         if (obj->nodesetval != NULL)
5648             xmlXPathFreeNodeSet(obj->nodesetval);
5649 #ifdef XP_DEBUG_OBJ_USAGE
5650         xmlXPathDebugObjUsageReleased(NULL, obj->type);
5651 #endif
5652         xmlFree(obj);
5653     }
5654     return;
5655 }
5656
5657
5658 /************************************************************************
5659  *                                                                      *
5660  *                      Type Casting Routines                           *
5661  *                                                                      *
5662  ************************************************************************/
5663
5664 /**
5665  * xmlXPathCastBooleanToString:
5666  * @val:  a boolean
5667  *
5668  * Converts a boolean to its string value.
5669  *
5670  * Returns a newly allocated string.
5671  */
5672 xmlChar *
5673 xmlXPathCastBooleanToString (int val) {
5674     xmlChar *ret;
5675     if (val)
5676         ret = xmlStrdup((const xmlChar *) "true");
5677     else
5678         ret = xmlStrdup((const xmlChar *) "false");
5679     return(ret);
5680 }
5681
5682 /**
5683  * xmlXPathCastNumberToString:
5684  * @val:  a number
5685  *
5686  * Converts a number to its string value.
5687  *
5688  * Returns a newly allocated string.
5689  */
5690 xmlChar *
5691 xmlXPathCastNumberToString (double val) {
5692     xmlChar *ret;
5693     switch (xmlXPathIsInf(val)) {
5694     case 1:
5695         ret = xmlStrdup((const xmlChar *) "Infinity");
5696         break;
5697     case -1:
5698         ret = xmlStrdup((const xmlChar *) "-Infinity");
5699         break;
5700     default:
5701         if (xmlXPathIsNaN(val)) {
5702             ret = xmlStrdup((const xmlChar *) "NaN");
5703         } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5704             ret = xmlStrdup((const xmlChar *) "0");
5705         } else {
5706             /* could be improved */
5707             char buf[100];
5708             xmlXPathFormatNumber(val, buf, 99);
5709             buf[99] = 0;
5710             ret = xmlStrdup((const xmlChar *) buf);
5711         }
5712     }
5713     return(ret);
5714 }
5715
5716 /**
5717  * xmlXPathCastNodeToString:
5718  * @node:  a node
5719  *
5720  * Converts a node to its string value.
5721  *
5722  * Returns a newly allocated string.
5723  */
5724 xmlChar *
5725 xmlXPathCastNodeToString (xmlNodePtr node) {
5726 xmlChar *ret;
5727     if ((ret = xmlNodeGetContent(node)) == NULL)
5728         ret = xmlStrdup((const xmlChar *) "");
5729     return(ret);
5730 }
5731
5732 /**
5733  * xmlXPathCastNodeSetToString:
5734  * @ns:  a node-set
5735  *
5736  * Converts a node-set to its string value.
5737  *
5738  * Returns a newly allocated string.
5739  */
5740 xmlChar *
5741 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5742     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5743         return(xmlStrdup((const xmlChar *) ""));
5744
5745     if (ns->nodeNr > 1)
5746         xmlXPathNodeSetSort(ns);
5747     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5748 }
5749
5750 /**
5751  * xmlXPathCastToString:
5752  * @val:  an XPath object
5753  *
5754  * Converts an existing object to its string() equivalent
5755  *
5756  * Returns the allocated string value of the object, NULL in case of error.
5757  *         It's up to the caller to free the string memory with xmlFree().
5758  */
5759 xmlChar *
5760 xmlXPathCastToString(xmlXPathObjectPtr val) {
5761     xmlChar *ret = NULL;
5762
5763     if (val == NULL)
5764         return(xmlStrdup((const xmlChar *) ""));
5765     switch (val->type) {
5766         case XPATH_UNDEFINED:
5767 #ifdef DEBUG_EXPR
5768             xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5769 #endif
5770             ret = xmlStrdup((const xmlChar *) "");
5771             break;
5772         case XPATH_NODESET:
5773         case XPATH_XSLT_TREE:
5774             ret = xmlXPathCastNodeSetToString(val->nodesetval);
5775             break;
5776         case XPATH_STRING:
5777             return(xmlStrdup(val->stringval));
5778         case XPATH_BOOLEAN:
5779             ret = xmlXPathCastBooleanToString(val->boolval);
5780             break;
5781         case XPATH_NUMBER: {
5782             ret = xmlXPathCastNumberToString(val->floatval);
5783             break;
5784         }
5785         case XPATH_USERS:
5786         case XPATH_POINT:
5787         case XPATH_RANGE:
5788         case XPATH_LOCATIONSET:
5789             TODO
5790             ret = xmlStrdup((const xmlChar *) "");
5791             break;
5792     }
5793     return(ret);
5794 }
5795
5796 /**
5797  * xmlXPathConvertString:
5798  * @val:  an XPath object
5799  *
5800  * Converts an existing object to its string() equivalent
5801  *
5802  * Returns the new object, the old one is freed (or the operation
5803  *         is done directly on @val)
5804  */
5805 xmlXPathObjectPtr
5806 xmlXPathConvertString(xmlXPathObjectPtr val) {
5807     xmlChar *res = NULL;
5808
5809     if (val == NULL)
5810         return(xmlXPathNewCString(""));
5811
5812     switch (val->type) {
5813     case XPATH_UNDEFINED:
5814 #ifdef DEBUG_EXPR
5815         xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5816 #endif
5817         break;
5818     case XPATH_NODESET:
5819     case XPATH_XSLT_TREE:
5820         res = xmlXPathCastNodeSetToString(val->nodesetval);
5821         break;
5822     case XPATH_STRING:
5823         return(val);
5824     case XPATH_BOOLEAN:
5825         res = xmlXPathCastBooleanToString(val->boolval);
5826         break;
5827     case XPATH_NUMBER:
5828         res = xmlXPathCastNumberToString(val->floatval);
5829         break;
5830     case XPATH_USERS:
5831     case XPATH_POINT:
5832     case XPATH_RANGE:
5833     case XPATH_LOCATIONSET:
5834         TODO;
5835         break;
5836     }
5837     xmlXPathFreeObject(val);
5838     if (res == NULL)
5839         return(xmlXPathNewCString(""));
5840     return(xmlXPathWrapString(res));
5841 }
5842
5843 /**
5844  * xmlXPathCastBooleanToNumber:
5845  * @val:  a boolean
5846  *
5847  * Converts a boolean to its number value
5848  *
5849  * Returns the number value
5850  */
5851 double
5852 xmlXPathCastBooleanToNumber(int val) {
5853     if (val)
5854         return(1.0);
5855     return(0.0);
5856 }
5857
5858 /**
5859  * xmlXPathCastStringToNumber:
5860  * @val:  a string
5861  *
5862  * Converts a string to its number value
5863  *
5864  * Returns the number value
5865  */
5866 double
5867 xmlXPathCastStringToNumber(const xmlChar * val) {
5868     return(xmlXPathStringEvalNumber(val));
5869 }
5870
5871 /**
5872  * xmlXPathCastNodeToNumber:
5873  * @node:  a node
5874  *
5875  * Converts a node to its number value
5876  *
5877  * Returns the number value
5878  */
5879 double
5880 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5881     xmlChar *strval;
5882     double ret;
5883
5884     if (node == NULL)
5885         return(xmlXPathNAN);
5886     strval = xmlXPathCastNodeToString(node);
5887     if (strval == NULL)
5888         return(xmlXPathNAN);
5889     ret = xmlXPathCastStringToNumber(strval);
5890     xmlFree(strval);
5891
5892     return(ret);
5893 }
5894
5895 /**
5896  * xmlXPathCastNodeSetToNumber:
5897  * @ns:  a node-set
5898  *
5899  * Converts a node-set to its number value
5900  *
5901  * Returns the number value
5902  */
5903 double
5904 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5905     xmlChar *str;
5906     double ret;
5907
5908     if (ns == NULL)
5909         return(xmlXPathNAN);
5910     str = xmlXPathCastNodeSetToString(ns);
5911     ret = xmlXPathCastStringToNumber(str);
5912     xmlFree(str);
5913     return(ret);
5914 }
5915
5916 /**
5917  * xmlXPathCastToNumber:
5918  * @val:  an XPath object
5919  *
5920  * Converts an XPath object to its number value
5921  *
5922  * Returns the number value
5923  */
5924 double
5925 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5926     double ret = 0.0;
5927
5928     if (val == NULL)
5929         return(xmlXPathNAN);
5930     switch (val->type) {
5931     case XPATH_UNDEFINED:
5932 #ifdef DEGUB_EXPR
5933         xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5934 #endif
5935         ret = xmlXPathNAN;
5936         break;
5937     case XPATH_NODESET:
5938     case XPATH_XSLT_TREE:
5939         ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5940         break;
5941     case XPATH_STRING:
5942         ret = xmlXPathCastStringToNumber(val->stringval);
5943         break;
5944     case XPATH_NUMBER:
5945         ret = val->floatval;
5946         break;
5947     case XPATH_BOOLEAN:
5948         ret = xmlXPathCastBooleanToNumber(val->boolval);
5949         break;
5950     case XPATH_USERS:
5951     case XPATH_POINT:
5952     case XPATH_RANGE:
5953     case XPATH_LOCATIONSET:
5954         TODO;
5955         ret = xmlXPathNAN;
5956         break;
5957     }
5958     return(ret);
5959 }
5960
5961 /**
5962  * xmlXPathConvertNumber:
5963  * @val:  an XPath object
5964  *
5965  * Converts an existing object to its number() equivalent
5966  *
5967  * Returns the new object, the old one is freed (or the operation
5968  *         is done directly on @val)
5969  */
5970 xmlXPathObjectPtr
5971 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5972     xmlXPathObjectPtr ret;
5973
5974     if (val == NULL)
5975         return(xmlXPathNewFloat(0.0));
5976     if (val->type == XPATH_NUMBER)
5977         return(val);
5978     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5979     xmlXPathFreeObject(val);
5980     return(ret);
5981 }
5982
5983 /**
5984  * xmlXPathCastNumberToBoolean:
5985  * @val:  a number
5986  *
5987  * Converts a number to its boolean value
5988  *
5989  * Returns the boolean value
5990  */
5991 int
5992 xmlXPathCastNumberToBoolean (double val) {
5993      if (xmlXPathIsNaN(val) || (val == 0.0))
5994          return(0);
5995      return(1);
5996 }
5997
5998 /**
5999  * xmlXPathCastStringToBoolean:
6000  * @val:  a string
6001  *
6002  * Converts a string to its boolean value
6003  *
6004  * Returns the boolean value
6005  */
6006 int
6007 xmlXPathCastStringToBoolean (const xmlChar *val) {
6008     if ((val == NULL) || (xmlStrlen(val) == 0))
6009         return(0);
6010     return(1);
6011 }
6012
6013 /**
6014  * xmlXPathCastNodeSetToBoolean:
6015  * @ns:  a node-set
6016  *
6017  * Converts a node-set to its boolean value
6018  *
6019  * Returns the boolean value
6020  */
6021 int
6022 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6023     if ((ns == NULL) || (ns->nodeNr == 0))
6024         return(0);
6025     return(1);
6026 }
6027
6028 /**
6029  * xmlXPathCastToBoolean:
6030  * @val:  an XPath object
6031  *
6032  * Converts an XPath object to its boolean value
6033  *
6034  * Returns the boolean value
6035  */
6036 int
6037 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6038     int ret = 0;
6039
6040     if (val == NULL)
6041         return(0);
6042     switch (val->type) {
6043     case XPATH_UNDEFINED:
6044 #ifdef DEBUG_EXPR
6045         xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6046 #endif
6047         ret = 0;
6048         break;
6049     case XPATH_NODESET:
6050     case XPATH_XSLT_TREE:
6051         ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6052         break;
6053     case XPATH_STRING:
6054         ret = xmlXPathCastStringToBoolean(val->stringval);
6055         break;
6056     case XPATH_NUMBER:
6057         ret = xmlXPathCastNumberToBoolean(val->floatval);
6058         break;
6059     case XPATH_BOOLEAN:
6060         ret = val->boolval;
6061         break;
6062     case XPATH_USERS:
6063     case XPATH_POINT:
6064     case XPATH_RANGE:
6065     case XPATH_LOCATIONSET:
6066         TODO;
6067         ret = 0;
6068         break;
6069     }
6070     return(ret);
6071 }
6072
6073
6074 /**
6075  * xmlXPathConvertBoolean:
6076  * @val:  an XPath object
6077  *
6078  * Converts an existing object to its boolean() equivalent
6079  *
6080  * Returns the new object, the old one is freed (or the operation
6081  *         is done directly on @val)
6082  */
6083 xmlXPathObjectPtr
6084 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6085     xmlXPathObjectPtr ret;
6086
6087     if (val == NULL)
6088         return(xmlXPathNewBoolean(0));
6089     if (val->type == XPATH_BOOLEAN)
6090         return(val);
6091     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6092     xmlXPathFreeObject(val);
6093     return(ret);
6094 }
6095
6096 /************************************************************************
6097  *                                                                      *
6098  *              Routines to handle XPath contexts                       *
6099  *                                                                      *
6100  ************************************************************************/
6101
6102 /**
6103  * xmlXPathNewContext:
6104  * @doc:  the XML document
6105  *
6106  * Create a new xmlXPathContext
6107  *
6108  * Returns the xmlXPathContext just allocated. The caller will need to free it.
6109  */
6110 xmlXPathContextPtr
6111 xmlXPathNewContext(xmlDocPtr doc) {
6112     xmlXPathContextPtr ret;
6113
6114     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6115     if (ret == NULL) {
6116         xmlXPathErrMemory(NULL, "creating context\n");
6117         return(NULL);
6118     }
6119     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6120     ret->doc = doc;
6121     ret->node = NULL;
6122
6123     ret->varHash = NULL;
6124
6125     ret->nb_types = 0;
6126     ret->max_types = 0;
6127     ret->types = NULL;
6128
6129     ret->funcHash = xmlHashCreate(0);
6130
6131     ret->nb_axis = 0;
6132     ret->max_axis = 0;
6133     ret->axis = NULL;
6134
6135     ret->nsHash = NULL;
6136     ret->user = NULL;
6137
6138     ret->contextSize = -1;
6139     ret->proximityPosition = -1;
6140
6141 #ifdef XP_DEFAULT_CACHE_ON
6142     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6143         xmlXPathFreeContext(ret);
6144         return(NULL);
6145     }
6146 #endif
6147
6148     xmlXPathRegisterAllFunctions(ret);
6149
6150     return(ret);
6151 }
6152
6153 /**
6154  * xmlXPathFreeContext:
6155  * @ctxt:  the context to free
6156  *
6157  * Free up an xmlXPathContext
6158  */
6159 void
6160 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6161     if (ctxt == NULL) return;
6162
6163     if (ctxt->cache != NULL)
6164         xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6165     xmlXPathRegisteredNsCleanup(ctxt);
6166     xmlXPathRegisteredFuncsCleanup(ctxt);
6167     xmlXPathRegisteredVariablesCleanup(ctxt);
6168     xmlResetError(&ctxt->lastError);
6169     xmlFree(ctxt);
6170 }
6171
6172 /************************************************************************
6173  *                                                                      *
6174  *              Routines to handle XPath parser contexts                *
6175  *                                                                      *
6176  ************************************************************************/
6177
6178 #define CHECK_CTXT(ctxt)                                                \
6179     if (ctxt == NULL) {                                         \
6180         __xmlRaiseError(NULL, NULL, NULL,                               \
6181                 NULL, NULL, XML_FROM_XPATH,                             \
6182                 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6183                 __FILE__, __LINE__,                                     \
6184                 NULL, NULL, NULL, 0, 0,                                 \
6185                 "NULL context pointer\n");                              \
6186         return(NULL);                                                   \
6187     }                                                                   \
6188
6189 #define CHECK_CTXT_NEG(ctxt)                                            \
6190     if (ctxt == NULL) {                                         \
6191         __xmlRaiseError(NULL, NULL, NULL,                               \
6192                 NULL, NULL, XML_FROM_XPATH,                             \
6193                 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6194                 __FILE__, __LINE__,                                     \
6195                 NULL, NULL, NULL, 0, 0,                                 \
6196                 "NULL context pointer\n");                              \
6197         return(-1);                                                     \
6198     }                                                                   \
6199
6200
6201 #define CHECK_CONTEXT(ctxt)                                             \
6202     if ((ctxt == NULL) || (ctxt->doc == NULL) ||                        \
6203         (ctxt->doc->children == NULL)) {                                \
6204         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);    \
6205         return(NULL);                                                   \
6206     }
6207
6208
6209 /**
6210  * xmlXPathNewParserContext:
6211  * @str:  the XPath expression
6212  * @ctxt:  the XPath context
6213  *
6214  * Create a new xmlXPathParserContext
6215  *
6216  * Returns the xmlXPathParserContext just allocated.
6217  */
6218 xmlXPathParserContextPtr
6219 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6220     xmlXPathParserContextPtr ret;
6221
6222     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6223     if (ret == NULL) {
6224         xmlXPathErrMemory(ctxt, "creating parser context\n");
6225         return(NULL);
6226     }
6227     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6228     ret->cur = ret->base = str;
6229     ret->context = ctxt;
6230
6231     ret->comp = xmlXPathNewCompExpr();
6232     if (ret->comp == NULL) {
6233         xmlFree(ret->valueTab);
6234         xmlFree(ret);
6235         return(NULL);
6236     }
6237     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6238         ret->comp->dict = ctxt->dict;
6239         xmlDictReference(ret->comp->dict);
6240     }
6241
6242     return(ret);
6243 }
6244
6245 /**
6246  * xmlXPathCompParserContext:
6247  * @comp:  the XPath compiled expression
6248  * @ctxt:  the XPath context
6249  *
6250  * Create a new xmlXPathParserContext when processing a compiled expression
6251  *
6252  * Returns the xmlXPathParserContext just allocated.
6253  */
6254 static xmlXPathParserContextPtr
6255 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6256     xmlXPathParserContextPtr ret;
6257
6258     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6259     if (ret == NULL) {
6260         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6261         return(NULL);
6262     }
6263     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6264
6265     /* Allocate the value stack */
6266     ret->valueTab = (xmlXPathObjectPtr *)
6267                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6268     if (ret->valueTab == NULL) {
6269         xmlFree(ret);
6270         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6271         return(NULL);
6272     }
6273     ret->valueNr = 0;
6274     ret->valueMax = 10;
6275     ret->value = NULL;
6276     ret->valueFrame = 0;
6277
6278     ret->context = ctxt;
6279     ret->comp = comp;
6280
6281     return(ret);
6282 }
6283
6284 /**
6285  * xmlXPathFreeParserContext:
6286  * @ctxt:  the context to free
6287  *
6288  * Free up an xmlXPathParserContext
6289  */
6290 void
6291 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6292     if (ctxt->valueTab != NULL) {
6293         xmlFree(ctxt->valueTab);
6294     }
6295     if (ctxt->comp != NULL) {
6296 #ifdef XPATH_STREAMING
6297         if (ctxt->comp->stream != NULL) {
6298             xmlFreePatternList(ctxt->comp->stream);
6299             ctxt->comp->stream = NULL;
6300         }
6301 #endif
6302         xmlXPathFreeCompExpr(ctxt->comp);
6303     }
6304     xmlFree(ctxt);
6305 }
6306
6307 /************************************************************************
6308  *                                                                      *
6309  *              The implicit core function library                      *
6310  *                                                                      *
6311  ************************************************************************/
6312
6313 /**
6314  * xmlXPathNodeValHash:
6315  * @node:  a node pointer
6316  *
6317  * Function computing the beginning of the string value of the node,
6318  * used to speed up comparisons
6319  *
6320  * Returns an int usable as a hash
6321  */
6322 static unsigned int
6323 xmlXPathNodeValHash(xmlNodePtr node) {
6324     int len = 2;
6325     const xmlChar * string = NULL;
6326     xmlNodePtr tmp = NULL;
6327     unsigned int ret = 0;
6328
6329     if (node == NULL)
6330         return(0);
6331
6332     if (node->type == XML_DOCUMENT_NODE) {
6333         tmp = xmlDocGetRootElement((xmlDocPtr) node);
6334         if (tmp == NULL)
6335             node = node->children;
6336         else
6337             node = tmp;
6338
6339         if (node == NULL)
6340             return(0);
6341     }
6342
6343     switch (node->type) {
6344         case XML_COMMENT_NODE:
6345         case XML_PI_NODE:
6346         case XML_CDATA_SECTION_NODE:
6347         case XML_TEXT_NODE:
6348             string = node->content;
6349             if (string == NULL)
6350                 return(0);
6351             if (string[0] == 0)
6352                 return(0);
6353             return(((unsigned int) string[0]) +
6354                    (((unsigned int) string[1]) << 8));
6355         case XML_NAMESPACE_DECL:
6356             string = ((xmlNsPtr)node)->href;
6357             if (string == NULL)
6358                 return(0);
6359             if (string[0] == 0)
6360                 return(0);
6361             return(((unsigned int) string[0]) +
6362                    (((unsigned int) string[1]) << 8));
6363         case XML_ATTRIBUTE_NODE:
6364             tmp = ((xmlAttrPtr) node)->children;
6365             break;
6366         case XML_ELEMENT_NODE:
6367             tmp = node->children;
6368             break;
6369         default:
6370             return(0);
6371     }
6372     while (tmp != NULL) {
6373         switch (tmp->type) {
6374             case XML_COMMENT_NODE:
6375             case XML_PI_NODE:
6376             case XML_CDATA_SECTION_NODE:
6377             case XML_TEXT_NODE:
6378                 string = tmp->content;
6379                 break;
6380             case XML_NAMESPACE_DECL:
6381                 string = ((xmlNsPtr)tmp)->href;
6382                 break;
6383             default:
6384                 break;
6385         }
6386         if ((string != NULL) && (string[0] != 0)) {
6387             if (len == 1) {
6388                 return(ret + (((unsigned int) string[0]) << 8));
6389             }
6390             if (string[1] == 0) {
6391                 len = 1;
6392                 ret = (unsigned int) string[0];
6393             } else {
6394                 return(((unsigned int) string[0]) +
6395                        (((unsigned int) string[1]) << 8));
6396             }
6397         }
6398         /*
6399          * Skip to next node
6400          */
6401         if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6402             if (tmp->children->type != XML_ENTITY_DECL) {
6403                 tmp = tmp->children;
6404                 continue;
6405             }
6406         }
6407         if (tmp == node)
6408             break;
6409
6410         if (tmp->next != NULL) {
6411             tmp = tmp->next;
6412             continue;
6413         }
6414
6415         do {
6416             tmp = tmp->parent;
6417             if (tmp == NULL)
6418                 break;
6419             if (tmp == node) {
6420                 tmp = NULL;
6421                 break;
6422             }
6423             if (tmp->next != NULL) {
6424                 tmp = tmp->next;
6425                 break;
6426             }
6427         } while (tmp != NULL);
6428     }
6429     return(ret);
6430 }
6431
6432 /**
6433  * xmlXPathStringHash:
6434  * @string:  a string
6435  *
6436  * Function computing the beginning of the string value of the node,
6437  * used to speed up comparisons
6438  *
6439  * Returns an int usable as a hash
6440  */
6441 static unsigned int
6442 xmlXPathStringHash(const xmlChar * string) {
6443     if (string == NULL)
6444         return((unsigned int) 0);
6445     if (string[0] == 0)
6446         return(0);
6447     return(((unsigned int) string[0]) +
6448            (((unsigned int) string[1]) << 8));
6449 }
6450
6451 /**
6452  * xmlXPathCompareNodeSetFloat:
6453  * @ctxt:  the XPath Parser context
6454  * @inf:  less than (1) or greater than (0)
6455  * @strict:  is the comparison strict
6456  * @arg:  the node set
6457  * @f:  the value
6458  *
6459  * Implement the compare operation between a nodeset and a number
6460  *     @ns < @val    (1, 1, ...
6461  *     @ns <= @val   (1, 0, ...
6462  *     @ns > @val    (0, 1, ...
6463  *     @ns >= @val   (0, 0, ...
6464  *
6465  * If one object to be compared is a node-set and the other is a number,
6466  * then the comparison will be true if and only if there is a node in the
6467  * node-set such that the result of performing the comparison on the number
6468  * to be compared and on the result of converting the string-value of that
6469  * node to a number using the number function is true.
6470  *
6471  * Returns 0 or 1 depending on the results of the test.
6472  */
6473 static int
6474 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6475                             xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6476     int i, ret = 0;
6477     xmlNodeSetPtr ns;
6478     xmlChar *str2;
6479
6480     if ((f == NULL) || (arg == NULL) ||
6481         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6482         xmlXPathReleaseObject(ctxt->context, arg);
6483         xmlXPathReleaseObject(ctxt->context, f);
6484         return(0);
6485     }
6486     ns = arg->nodesetval;
6487     if (ns != NULL) {
6488         for (i = 0;i < ns->nodeNr;i++) {
6489              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6490              if (str2 != NULL) {
6491                  valuePush(ctxt,
6492                            xmlXPathCacheNewString(ctxt->context, str2));
6493                  xmlFree(str2);
6494                  xmlXPathNumberFunction(ctxt, 1);
6495                  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6496                  ret = xmlXPathCompareValues(ctxt, inf, strict);
6497                  if (ret)
6498                      break;
6499              }
6500         }
6501     }
6502     xmlXPathReleaseObject(ctxt->context, arg);
6503     xmlXPathReleaseObject(ctxt->context, f);
6504     return(ret);
6505 }
6506
6507 /**
6508  * xmlXPathCompareNodeSetString:
6509  * @ctxt:  the XPath Parser context
6510  * @inf:  less than (1) or greater than (0)
6511  * @strict:  is the comparison strict
6512  * @arg:  the node set
6513  * @s:  the value
6514  *
6515  * Implement the compare operation between a nodeset and a string
6516  *     @ns < @val    (1, 1, ...
6517  *     @ns <= @val   (1, 0, ...
6518  *     @ns > @val    (0, 1, ...
6519  *     @ns >= @val   (0, 0, ...
6520  *
6521  * If one object to be compared is a node-set and the other is a string,
6522  * then the comparison will be true if and only if there is a node in
6523  * the node-set such that the result of performing the comparison on the
6524  * string-value of the node and the other string is true.
6525  *
6526  * Returns 0 or 1 depending on the results of the test.
6527  */
6528 static int
6529 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6530                             xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6531     int i, ret = 0;
6532     xmlNodeSetPtr ns;
6533     xmlChar *str2;
6534
6535     if ((s == NULL) || (arg == NULL) ||
6536         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6537         xmlXPathReleaseObject(ctxt->context, arg);
6538         xmlXPathReleaseObject(ctxt->context, s);
6539         return(0);
6540     }
6541     ns = arg->nodesetval;
6542     if (ns != NULL) {
6543         for (i = 0;i < ns->nodeNr;i++) {
6544              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6545              if (str2 != NULL) {
6546                  valuePush(ctxt,
6547                            xmlXPathCacheNewString(ctxt->context, str2));
6548                  xmlFree(str2);
6549                  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6550                  ret = xmlXPathCompareValues(ctxt, inf, strict);
6551                  if (ret)
6552                      break;
6553              }
6554         }
6555     }
6556     xmlXPathReleaseObject(ctxt->context, arg);
6557     xmlXPathReleaseObject(ctxt->context, s);
6558     return(ret);
6559 }
6560
6561 /**
6562  * xmlXPathCompareNodeSets:
6563  * @inf:  less than (1) or greater than (0)
6564  * @strict:  is the comparison strict
6565  * @arg1:  the first node set object
6566  * @arg2:  the second node set object
6567  *
6568  * Implement the compare operation on nodesets:
6569  *
6570  * If both objects to be compared are node-sets, then the comparison
6571  * will be true if and only if there is a node in the first node-set
6572  * and a node in the second node-set such that the result of performing
6573  * the comparison on the string-values of the two nodes is true.
6574  * ....
6575  * When neither object to be compared is a node-set and the operator
6576  * is <=, <, >= or >, then the objects are compared by converting both
6577  * objects to numbers and comparing the numbers according to IEEE 754.
6578  * ....
6579  * The number function converts its argument to a number as follows:
6580  *  - a string that consists of optional whitespace followed by an
6581  *    optional minus sign followed by a Number followed by whitespace
6582  *    is converted to the IEEE 754 number that is nearest (according
6583  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6584  *    represented by the string; any other string is converted to NaN
6585  *
6586  * Conclusion all nodes need to be converted first to their string value
6587  * and then the comparison must be done when possible
6588  */
6589 static int
6590 xmlXPathCompareNodeSets(int inf, int strict,
6591                         xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6592     int i, j, init = 0;
6593     double val1;
6594     double *values2;
6595     int ret = 0;
6596     xmlNodeSetPtr ns1;
6597     xmlNodeSetPtr ns2;
6598
6599     if ((arg1 == NULL) ||
6600         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6601         xmlXPathFreeObject(arg2);
6602         return(0);
6603     }
6604     if ((arg2 == NULL) ||
6605         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6606         xmlXPathFreeObject(arg1);
6607         xmlXPathFreeObject(arg2);
6608         return(0);
6609     }
6610
6611     ns1 = arg1->nodesetval;
6612     ns2 = arg2->nodesetval;
6613
6614     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6615         xmlXPathFreeObject(arg1);
6616         xmlXPathFreeObject(arg2);
6617         return(0);
6618     }
6619     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6620         xmlXPathFreeObject(arg1);
6621         xmlXPathFreeObject(arg2);
6622         return(0);
6623     }
6624
6625     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6626     if (values2 == NULL) {
6627         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6628         xmlXPathFreeObject(arg1);
6629         xmlXPathFreeObject(arg2);
6630         return(0);
6631     }
6632     for (i = 0;i < ns1->nodeNr;i++) {
6633         val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6634         if (xmlXPathIsNaN(val1))
6635             continue;
6636         for (j = 0;j < ns2->nodeNr;j++) {
6637             if (init == 0) {
6638                 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6639             }
6640             if (xmlXPathIsNaN(values2[j]))
6641                 continue;
6642             if (inf && strict)
6643                 ret = (val1 < values2[j]);
6644             else if (inf && !strict)
6645                 ret = (val1 <= values2[j]);
6646             else if (!inf && strict)
6647                 ret = (val1 > values2[j]);
6648             else if (!inf && !strict)
6649                 ret = (val1 >= values2[j]);
6650             if (ret)
6651                 break;
6652         }
6653         if (ret)
6654             break;
6655         init = 1;
6656     }
6657     xmlFree(values2);
6658     xmlXPathFreeObject(arg1);
6659     xmlXPathFreeObject(arg2);
6660     return(ret);
6661 }
6662
6663 /**
6664  * xmlXPathCompareNodeSetValue:
6665  * @ctxt:  the XPath Parser context
6666  * @inf:  less than (1) or greater than (0)
6667  * @strict:  is the comparison strict
6668  * @arg:  the node set
6669  * @val:  the value
6670  *
6671  * Implement the compare operation between a nodeset and a value
6672  *     @ns < @val    (1, 1, ...
6673  *     @ns <= @val   (1, 0, ...
6674  *     @ns > @val    (0, 1, ...
6675  *     @ns >= @val   (0, 0, ...
6676  *
6677  * If one object to be compared is a node-set and the other is a boolean,
6678  * then the comparison will be true if and only if the result of performing
6679  * the comparison on the boolean and on the result of converting
6680  * the node-set to a boolean using the boolean function is true.
6681  *
6682  * Returns 0 or 1 depending on the results of the test.
6683  */
6684 static int
6685 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6686                             xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6687     if ((val == NULL) || (arg == NULL) ||
6688         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6689         return(0);
6690
6691     switch(val->type) {
6692         case XPATH_NUMBER:
6693             return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6694         case XPATH_NODESET:
6695         case XPATH_XSLT_TREE:
6696             return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6697         case XPATH_STRING:
6698             return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6699         case XPATH_BOOLEAN:
6700             valuePush(ctxt, arg);
6701             xmlXPathBooleanFunction(ctxt, 1);
6702             valuePush(ctxt, val);
6703             return(xmlXPathCompareValues(ctxt, inf, strict));
6704         default:
6705             TODO
6706     }
6707     return(0);
6708 }
6709
6710 /**
6711  * xmlXPathEqualNodeSetString:
6712  * @arg:  the nodeset object argument
6713  * @str:  the string to compare to.
6714  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6715  *
6716  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6717  * If one object to be compared is a node-set and the other is a string,
6718  * then the comparison will be true if and only if there is a node in
6719  * the node-set such that the result of performing the comparison on the
6720  * string-value of the node and the other string is true.
6721  *
6722  * Returns 0 or 1 depending on the results of the test.
6723  */
6724 static int
6725 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6726 {
6727     int i;
6728     xmlNodeSetPtr ns;
6729     xmlChar *str2;
6730     unsigned int hash;
6731
6732     if ((str == NULL) || (arg == NULL) ||
6733         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6734         return (0);
6735     ns = arg->nodesetval;
6736     /*
6737      * A NULL nodeset compared with a string is always false
6738      * (since there is no node equal, and no node not equal)
6739      */
6740     if ((ns == NULL) || (ns->nodeNr <= 0) )
6741         return (0);
6742     hash = xmlXPathStringHash(str);
6743     for (i = 0; i < ns->nodeNr; i++) {
6744         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6745             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6746             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6747                 xmlFree(str2);
6748                 if (neq)
6749                     continue;
6750                 return (1);
6751             } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6752                 if (neq)
6753                     continue;
6754                 return (1);
6755             } else if (neq) {
6756                 if (str2 != NULL)
6757                     xmlFree(str2);
6758                 return (1);
6759             }
6760             if (str2 != NULL)
6761                 xmlFree(str2);
6762         } else if (neq)
6763             return (1);
6764     }
6765     return (0);
6766 }
6767
6768 /**
6769  * xmlXPathEqualNodeSetFloat:
6770  * @arg:  the nodeset object argument
6771  * @f:  the float to compare to
6772  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6773  *
6774  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6775  * If one object to be compared is a node-set and the other is a number,
6776  * then the comparison will be true if and only if there is a node in
6777  * the node-set such that the result of performing the comparison on the
6778  * number to be compared and on the result of converting the string-value
6779  * of that node to a number using the number function is true.
6780  *
6781  * Returns 0 or 1 depending on the results of the test.
6782  */
6783 static int
6784 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6785     xmlXPathObjectPtr arg, double f, int neq) {
6786   int i, ret=0;
6787   xmlNodeSetPtr ns;
6788   xmlChar *str2;
6789   xmlXPathObjectPtr val;
6790   double v;
6791
6792     if ((arg == NULL) ||
6793         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6794         return(0);
6795
6796     ns = arg->nodesetval;
6797     if (ns != NULL) {
6798         for (i=0;i<ns->nodeNr;i++) {
6799             str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6800             if (str2 != NULL) {
6801                 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6802                 xmlFree(str2);
6803                 xmlXPathNumberFunction(ctxt, 1);
6804                 val = valuePop(ctxt);
6805                 v = val->floatval;
6806                 xmlXPathReleaseObject(ctxt->context, val);
6807                 if (!xmlXPathIsNaN(v)) {
6808                     if ((!neq) && (v==f)) {
6809                         ret = 1;
6810                         break;
6811                     } else if ((neq) && (v!=f)) {
6812                         ret = 1;
6813                         break;
6814                     }
6815                 } else {        /* NaN is unequal to any value */
6816                     if (neq)
6817                         ret = 1;
6818                 }
6819             }
6820         }
6821     }
6822
6823     return(ret);
6824 }
6825
6826
6827 /**
6828  * xmlXPathEqualNodeSets:
6829  * @arg1:  first nodeset object argument
6830  * @arg2:  second nodeset object argument
6831  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6832  *
6833  * Implement the equal / not equal operation on XPath nodesets:
6834  * @arg1 == @arg2  or  @arg1 != @arg2
6835  * If both objects to be compared are node-sets, then the comparison
6836  * will be true if and only if there is a node in the first node-set and
6837  * a node in the second node-set such that the result of performing the
6838  * comparison on the string-values of the two nodes is true.
6839  *
6840  * (needless to say, this is a costly operation)
6841  *
6842  * Returns 0 or 1 depending on the results of the test.
6843  */
6844 static int
6845 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6846     int i, j;
6847     unsigned int *hashs1;
6848     unsigned int *hashs2;
6849     xmlChar **values1;
6850     xmlChar **values2;
6851     int ret = 0;
6852     xmlNodeSetPtr ns1;
6853     xmlNodeSetPtr ns2;
6854
6855     if ((arg1 == NULL) ||
6856         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6857         return(0);
6858     if ((arg2 == NULL) ||
6859         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6860         return(0);
6861
6862     ns1 = arg1->nodesetval;
6863     ns2 = arg2->nodesetval;
6864
6865     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6866         return(0);
6867     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6868         return(0);
6869
6870     /*
6871      * for equal, check if there is a node pertaining to both sets
6872      */
6873     if (neq == 0)
6874         for (i = 0;i < ns1->nodeNr;i++)
6875             for (j = 0;j < ns2->nodeNr;j++)
6876                 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6877                     return(1);
6878
6879     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6880     if (values1 == NULL) {
6881         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6882         return(0);
6883     }
6884     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6885     if (hashs1 == NULL) {
6886         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6887         xmlFree(values1);
6888         return(0);
6889     }
6890     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6891     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6892     if (values2 == NULL) {
6893         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6894         xmlFree(hashs1);
6895         xmlFree(values1);
6896         return(0);
6897     }
6898     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6899     if (hashs2 == NULL) {
6900         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6901         xmlFree(hashs1);
6902         xmlFree(values1);
6903         xmlFree(values2);
6904         return(0);
6905     }
6906     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6907     for (i = 0;i < ns1->nodeNr;i++) {
6908         hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6909         for (j = 0;j < ns2->nodeNr;j++) {
6910             if (i == 0)
6911                 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6912             if (hashs1[i] != hashs2[j]) {
6913                 if (neq) {
6914                     ret = 1;
6915                     break;
6916                 }
6917             }
6918             else {
6919                 if (values1[i] == NULL)
6920                     values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6921                 if (values2[j] == NULL)
6922                     values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6923                 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6924                 if (ret)
6925                     break;
6926             }
6927         }
6928         if (ret)
6929             break;
6930     }
6931     for (i = 0;i < ns1->nodeNr;i++)
6932         if (values1[i] != NULL)
6933             xmlFree(values1[i]);
6934     for (j = 0;j < ns2->nodeNr;j++)
6935         if (values2[j] != NULL)
6936             xmlFree(values2[j]);
6937     xmlFree(values1);
6938     xmlFree(values2);
6939     xmlFree(hashs1);
6940     xmlFree(hashs2);
6941     return(ret);
6942 }
6943
6944 static int
6945 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6946   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6947     int ret = 0;
6948     /*
6949      *At this point we are assured neither arg1 nor arg2
6950      *is a nodeset, so we can just pick the appropriate routine.
6951      */
6952     switch (arg1->type) {
6953         case XPATH_UNDEFINED:
6954 #ifdef DEBUG_EXPR
6955             xmlGenericError(xmlGenericErrorContext,
6956                     "Equal: undefined\n");
6957 #endif
6958             break;
6959         case XPATH_BOOLEAN:
6960             switch (arg2->type) {
6961                 case XPATH_UNDEFINED:
6962 #ifdef DEBUG_EXPR
6963                     xmlGenericError(xmlGenericErrorContext,
6964                             "Equal: undefined\n");
6965 #endif
6966                     break;
6967                 case XPATH_BOOLEAN:
6968 #ifdef DEBUG_EXPR
6969                     xmlGenericError(xmlGenericErrorContext,
6970                             "Equal: %d boolean %d \n",
6971                             arg1->boolval, arg2->boolval);
6972 #endif
6973                     ret = (arg1->boolval == arg2->boolval);
6974                     break;
6975                 case XPATH_NUMBER:
6976                     ret = (arg1->boolval ==
6977                            xmlXPathCastNumberToBoolean(arg2->floatval));
6978                     break;
6979                 case XPATH_STRING:
6980                     if ((arg2->stringval == NULL) ||
6981                         (arg2->stringval[0] == 0)) ret = 0;
6982                     else
6983                         ret = 1;
6984                     ret = (arg1->boolval == ret);
6985                     break;
6986                 case XPATH_USERS:
6987                 case XPATH_POINT:
6988                 case XPATH_RANGE:
6989                 case XPATH_LOCATIONSET:
6990                     TODO
6991                     break;
6992                 case XPATH_NODESET:
6993                 case XPATH_XSLT_TREE:
6994                     break;
6995             }
6996             break;
6997         case XPATH_NUMBER:
6998             switch (arg2->type) {
6999                 case XPATH_UNDEFINED:
7000 #ifdef DEBUG_EXPR
7001                     xmlGenericError(xmlGenericErrorContext,
7002                             "Equal: undefined\n");
7003 #endif
7004                     break;
7005                 case XPATH_BOOLEAN:
7006                     ret = (arg2->boolval==
7007                            xmlXPathCastNumberToBoolean(arg1->floatval));
7008                     break;
7009                 case XPATH_STRING:
7010                     valuePush(ctxt, arg2);
7011                     xmlXPathNumberFunction(ctxt, 1);
7012                     arg2 = valuePop(ctxt);
7013                     /* no break on purpose */
7014                 case XPATH_NUMBER:
7015                     /* Hand check NaN and Infinity equalities */
7016                     if (xmlXPathIsNaN(arg1->floatval) ||
7017                             xmlXPathIsNaN(arg2->floatval)) {
7018                         ret = 0;
7019                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7020                         if (xmlXPathIsInf(arg2->floatval) == 1)
7021                             ret = 1;
7022                         else
7023                             ret = 0;
7024                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7025                         if (xmlXPathIsInf(arg2->floatval) == -1)
7026                             ret = 1;
7027                         else
7028                             ret = 0;
7029                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7030                         if (xmlXPathIsInf(arg1->floatval) == 1)
7031                             ret = 1;
7032                         else
7033                             ret = 0;
7034                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7035                         if (xmlXPathIsInf(arg1->floatval) == -1)
7036                             ret = 1;
7037                         else
7038                             ret = 0;
7039                     } else {
7040                         ret = (arg1->floatval == arg2->floatval);
7041                     }
7042                     break;
7043                 case XPATH_USERS:
7044                 case XPATH_POINT:
7045                 case XPATH_RANGE:
7046                 case XPATH_LOCATIONSET:
7047                     TODO
7048                     break;
7049                 case XPATH_NODESET:
7050                 case XPATH_XSLT_TREE:
7051                     break;
7052             }
7053             break;
7054         case XPATH_STRING:
7055             switch (arg2->type) {
7056                 case XPATH_UNDEFINED:
7057 #ifdef DEBUG_EXPR
7058                     xmlGenericError(xmlGenericErrorContext,
7059                             "Equal: undefined\n");
7060 #endif
7061                     break;
7062                 case XPATH_BOOLEAN:
7063                     if ((arg1->stringval == NULL) ||
7064                         (arg1->stringval[0] == 0)) ret = 0;
7065                     else
7066                         ret = 1;
7067                     ret = (arg2->boolval == ret);
7068                     break;
7069                 case XPATH_STRING:
7070                     ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7071                     break;
7072                 case XPATH_NUMBER:
7073                     valuePush(ctxt, arg1);
7074                     xmlXPathNumberFunction(ctxt, 1);
7075                     arg1 = valuePop(ctxt);
7076                     /* Hand check NaN and Infinity equalities */
7077                     if (xmlXPathIsNaN(arg1->floatval) ||
7078                             xmlXPathIsNaN(arg2->floatval)) {
7079                         ret = 0;
7080                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7081                         if (xmlXPathIsInf(arg2->floatval) == 1)
7082                             ret = 1;
7083                         else
7084                             ret = 0;
7085                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7086                         if (xmlXPathIsInf(arg2->floatval) == -1)
7087                             ret = 1;
7088                         else
7089                             ret = 0;
7090                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7091                         if (xmlXPathIsInf(arg1->floatval) == 1)
7092                             ret = 1;
7093                         else
7094                             ret = 0;
7095                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7096                         if (xmlXPathIsInf(arg1->floatval) == -1)
7097                             ret = 1;
7098                         else
7099                             ret = 0;
7100                     } else {
7101                         ret = (arg1->floatval == arg2->floatval);
7102                     }
7103                     break;
7104                 case XPATH_USERS:
7105                 case XPATH_POINT:
7106                 case XPATH_RANGE:
7107                 case XPATH_LOCATIONSET:
7108                     TODO
7109                     break;
7110                 case XPATH_NODESET:
7111                 case XPATH_XSLT_TREE:
7112                     break;
7113             }
7114             break;
7115         case XPATH_USERS:
7116         case XPATH_POINT:
7117         case XPATH_RANGE:
7118         case XPATH_LOCATIONSET:
7119             TODO
7120             break;
7121         case XPATH_NODESET:
7122         case XPATH_XSLT_TREE:
7123             break;
7124     }
7125     xmlXPathReleaseObject(ctxt->context, arg1);
7126     xmlXPathReleaseObject(ctxt->context, arg2);
7127     return(ret);
7128 }
7129
7130 /**
7131  * xmlXPathEqualValues:
7132  * @ctxt:  the XPath Parser context
7133  *
7134  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7135  *
7136  * Returns 0 or 1 depending on the results of the test.
7137  */
7138 int
7139 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7140     xmlXPathObjectPtr arg1, arg2, argtmp;
7141     int ret = 0;
7142
7143     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7144     arg2 = valuePop(ctxt);
7145     arg1 = valuePop(ctxt);
7146     if ((arg1 == NULL) || (arg2 == NULL)) {
7147         if (arg1 != NULL)
7148             xmlXPathReleaseObject(ctxt->context, arg1);
7149         else
7150             xmlXPathReleaseObject(ctxt->context, arg2);
7151         XP_ERROR0(XPATH_INVALID_OPERAND);
7152     }
7153
7154     if (arg1 == arg2) {
7155 #ifdef DEBUG_EXPR
7156         xmlGenericError(xmlGenericErrorContext,
7157                 "Equal: by pointer\n");
7158 #endif
7159         xmlXPathFreeObject(arg1);
7160         return(1);
7161     }
7162
7163     /*
7164      *If either argument is a nodeset, it's a 'special case'
7165      */
7166     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7167       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7168         /*
7169          *Hack it to assure arg1 is the nodeset
7170          */
7171         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7172                 argtmp = arg2;
7173                 arg2 = arg1;
7174                 arg1 = argtmp;
7175         }
7176         switch (arg2->type) {
7177             case XPATH_UNDEFINED:
7178 #ifdef DEBUG_EXPR
7179                 xmlGenericError(xmlGenericErrorContext,
7180                         "Equal: undefined\n");
7181 #endif
7182                 break;
7183             case XPATH_NODESET:
7184             case XPATH_XSLT_TREE:
7185                 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7186                 break;
7187             case XPATH_BOOLEAN:
7188                 if ((arg1->nodesetval == NULL) ||
7189                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
7190                 else
7191                     ret = 1;
7192                 ret = (ret == arg2->boolval);
7193                 break;
7194             case XPATH_NUMBER:
7195                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7196                 break;
7197             case XPATH_STRING:
7198                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7199                 break;
7200             case XPATH_USERS:
7201             case XPATH_POINT:
7202             case XPATH_RANGE:
7203             case XPATH_LOCATIONSET:
7204                 TODO
7205                 break;
7206         }
7207         xmlXPathReleaseObject(ctxt->context, arg1);
7208         xmlXPathReleaseObject(ctxt->context, arg2);
7209         return(ret);
7210     }
7211
7212     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7213 }
7214
7215 /**
7216  * xmlXPathNotEqualValues:
7217  * @ctxt:  the XPath Parser context
7218  *
7219  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7220  *
7221  * Returns 0 or 1 depending on the results of the test.
7222  */
7223 int
7224 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7225     xmlXPathObjectPtr arg1, arg2, argtmp;
7226     int ret = 0;
7227
7228     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7229     arg2 = valuePop(ctxt);
7230     arg1 = valuePop(ctxt);
7231     if ((arg1 == NULL) || (arg2 == NULL)) {
7232         if (arg1 != NULL)
7233             xmlXPathReleaseObject(ctxt->context, arg1);
7234         else
7235             xmlXPathReleaseObject(ctxt->context, arg2);
7236         XP_ERROR0(XPATH_INVALID_OPERAND);
7237     }
7238
7239     if (arg1 == arg2) {
7240 #ifdef DEBUG_EXPR
7241         xmlGenericError(xmlGenericErrorContext,
7242                 "NotEqual: by pointer\n");
7243 #endif
7244         xmlXPathReleaseObject(ctxt->context, arg1);
7245         return(0);
7246     }
7247
7248     /*
7249      *If either argument is a nodeset, it's a 'special case'
7250      */
7251     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7252       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7253         /*
7254          *Hack it to assure arg1 is the nodeset
7255          */
7256         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7257                 argtmp = arg2;
7258                 arg2 = arg1;
7259                 arg1 = argtmp;
7260         }
7261         switch (arg2->type) {
7262             case XPATH_UNDEFINED:
7263 #ifdef DEBUG_EXPR
7264                 xmlGenericError(xmlGenericErrorContext,
7265                         "NotEqual: undefined\n");
7266 #endif
7267                 break;
7268             case XPATH_NODESET:
7269             case XPATH_XSLT_TREE:
7270                 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7271                 break;
7272             case XPATH_BOOLEAN:
7273                 if ((arg1->nodesetval == NULL) ||
7274                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
7275                 else
7276                     ret = 1;
7277                 ret = (ret != arg2->boolval);
7278                 break;
7279             case XPATH_NUMBER:
7280                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7281                 break;
7282             case XPATH_STRING:
7283                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7284                 break;
7285             case XPATH_USERS:
7286             case XPATH_POINT:
7287             case XPATH_RANGE:
7288             case XPATH_LOCATIONSET:
7289                 TODO
7290                 break;
7291         }
7292         xmlXPathReleaseObject(ctxt->context, arg1);
7293         xmlXPathReleaseObject(ctxt->context, arg2);
7294         return(ret);
7295     }
7296
7297     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7298 }
7299
7300 /**
7301  * xmlXPathCompareValues:
7302  * @ctxt:  the XPath Parser context
7303  * @inf:  less than (1) or greater than (0)
7304  * @strict:  is the comparison strict
7305  *
7306  * Implement the compare operation on XPath objects:
7307  *     @arg1 < @arg2    (1, 1, ...
7308  *     @arg1 <= @arg2   (1, 0, ...
7309  *     @arg1 > @arg2    (0, 1, ...
7310  *     @arg1 >= @arg2   (0, 0, ...
7311  *
7312  * When neither object to be compared is a node-set and the operator is
7313  * <=, <, >=, >, then the objects are compared by converted both objects
7314  * to numbers and comparing the numbers according to IEEE 754. The <
7315  * comparison will be true if and only if the first number is less than the
7316  * second number. The <= comparison will be true if and only if the first
7317  * number is less than or equal to the second number. The > comparison
7318  * will be true if and only if the first number is greater than the second
7319  * number. The >= comparison will be true if and only if the first number
7320  * is greater than or equal to the second number.
7321  *
7322  * Returns 1 if the comparison succeeded, 0 if it failed
7323  */
7324 int
7325 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7326     int ret = 0, arg1i = 0, arg2i = 0;
7327     xmlXPathObjectPtr arg1, arg2;
7328
7329     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7330     arg2 = valuePop(ctxt);
7331     arg1 = valuePop(ctxt);
7332     if ((arg1 == NULL) || (arg2 == NULL)) {
7333         if (arg1 != NULL)
7334             xmlXPathReleaseObject(ctxt->context, arg1);
7335         else
7336             xmlXPathReleaseObject(ctxt->context, arg2);
7337         XP_ERROR0(XPATH_INVALID_OPERAND);
7338     }
7339
7340     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7341       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7342         /*
7343          * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7344          * are not freed from within this routine; they will be freed from the
7345          * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7346          */
7347         if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7348           ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7349             ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7350         } else {
7351             if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7352                 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7353                                                   arg1, arg2);
7354             } else {
7355                 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7356                                                   arg2, arg1);
7357             }
7358         }
7359         return(ret);
7360     }
7361
7362     if (arg1->type != XPATH_NUMBER) {
7363         valuePush(ctxt, arg1);
7364         xmlXPathNumberFunction(ctxt, 1);
7365         arg1 = valuePop(ctxt);
7366     }
7367     if (arg1->type != XPATH_NUMBER) {
7368         xmlXPathFreeObject(arg1);
7369         xmlXPathFreeObject(arg2);
7370         XP_ERROR0(XPATH_INVALID_OPERAND);
7371     }
7372     if (arg2->type != XPATH_NUMBER) {
7373         valuePush(ctxt, arg2);
7374         xmlXPathNumberFunction(ctxt, 1);
7375         arg2 = valuePop(ctxt);
7376     }
7377     if (arg2->type != XPATH_NUMBER) {
7378         xmlXPathReleaseObject(ctxt->context, arg1);
7379         xmlXPathReleaseObject(ctxt->context, arg2);
7380         XP_ERROR0(XPATH_INVALID_OPERAND);
7381     }
7382     /*
7383      * Add tests for infinity and nan
7384      * => feedback on 3.4 for Inf and NaN
7385      */
7386     /* Hand check NaN and Infinity comparisons */
7387     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7388         ret=0;
7389     } else {
7390         arg1i=xmlXPathIsInf(arg1->floatval);
7391         arg2i=xmlXPathIsInf(arg2->floatval);
7392         if (inf && strict) {
7393             if ((arg1i == -1 && arg2i != -1) ||
7394                 (arg2i == 1 && arg1i != 1)) {
7395                 ret = 1;
7396             } else if (arg1i == 0 && arg2i == 0) {
7397                 ret = (arg1->floatval < arg2->floatval);
7398             } else {
7399                 ret = 0;
7400             }
7401         }
7402         else if (inf && !strict) {
7403             if (arg1i == -1 || arg2i == 1) {
7404                 ret = 1;
7405             } else if (arg1i == 0 && arg2i == 0) {
7406                 ret = (arg1->floatval <= arg2->floatval);
7407             } else {
7408                 ret = 0;
7409             }
7410         }
7411         else if (!inf && strict) {
7412             if ((arg1i == 1 && arg2i != 1) ||
7413                 (arg2i == -1 && arg1i != -1)) {
7414                 ret = 1;
7415             } else if (arg1i == 0 && arg2i == 0) {
7416                 ret = (arg1->floatval > arg2->floatval);
7417             } else {
7418                 ret = 0;
7419             }
7420         }
7421         else if (!inf && !strict) {
7422             if (arg1i == 1 || arg2i == -1) {
7423                 ret = 1;
7424             } else if (arg1i == 0 && arg2i == 0) {
7425                 ret = (arg1->floatval >= arg2->floatval);
7426             } else {
7427                 ret = 0;
7428             }
7429         }
7430     }
7431     xmlXPathReleaseObject(ctxt->context, arg1);
7432     xmlXPathReleaseObject(ctxt->context, arg2);
7433     return(ret);
7434 }
7435
7436 /**
7437  * xmlXPathValueFlipSign:
7438  * @ctxt:  the XPath Parser context
7439  *
7440  * Implement the unary - operation on an XPath object
7441  * The numeric operators convert their operands to numbers as if
7442  * by calling the number function.
7443  */
7444 void
7445 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7446     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7447     CAST_TO_NUMBER;
7448     CHECK_TYPE(XPATH_NUMBER);
7449     if (xmlXPathIsNaN(ctxt->value->floatval))
7450         ctxt->value->floatval=xmlXPathNAN;
7451     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7452         ctxt->value->floatval=xmlXPathNINF;
7453     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7454         ctxt->value->floatval=xmlXPathPINF;
7455     else if (ctxt->value->floatval == 0) {
7456         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7457             ctxt->value->floatval = xmlXPathNZERO;
7458         else
7459             ctxt->value->floatval = 0;
7460     }
7461     else
7462         ctxt->value->floatval = - ctxt->value->floatval;
7463 }
7464
7465 /**
7466  * xmlXPathAddValues:
7467  * @ctxt:  the XPath Parser context
7468  *
7469  * Implement the add operation on XPath objects:
7470  * The numeric operators convert their operands to numbers as if
7471  * by calling the number function.
7472  */
7473 void
7474 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7475     xmlXPathObjectPtr arg;
7476     double val;
7477
7478     arg = valuePop(ctxt);
7479     if (arg == NULL)
7480         XP_ERROR(XPATH_INVALID_OPERAND);
7481     val = xmlXPathCastToNumber(arg);
7482     xmlXPathReleaseObject(ctxt->context, arg);
7483     CAST_TO_NUMBER;
7484     CHECK_TYPE(XPATH_NUMBER);
7485     ctxt->value->floatval += val;
7486 }
7487
7488 /**
7489  * xmlXPathSubValues:
7490  * @ctxt:  the XPath Parser context
7491  *
7492  * Implement the subtraction operation on XPath objects:
7493  * The numeric operators convert their operands to numbers as if
7494  * by calling the number function.
7495  */
7496 void
7497 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7498     xmlXPathObjectPtr arg;
7499     double val;
7500
7501     arg = valuePop(ctxt);
7502     if (arg == NULL)
7503         XP_ERROR(XPATH_INVALID_OPERAND);
7504     val = xmlXPathCastToNumber(arg);
7505     xmlXPathReleaseObject(ctxt->context, arg);
7506     CAST_TO_NUMBER;
7507     CHECK_TYPE(XPATH_NUMBER);
7508     ctxt->value->floatval -= val;
7509 }
7510
7511 /**
7512  * xmlXPathMultValues:
7513  * @ctxt:  the XPath Parser context
7514  *
7515  * Implement the multiply operation on XPath objects:
7516  * The numeric operators convert their operands to numbers as if
7517  * by calling the number function.
7518  */
7519 void
7520 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7521     xmlXPathObjectPtr arg;
7522     double val;
7523
7524     arg = valuePop(ctxt);
7525     if (arg == NULL)
7526         XP_ERROR(XPATH_INVALID_OPERAND);
7527     val = xmlXPathCastToNumber(arg);
7528     xmlXPathReleaseObject(ctxt->context, arg);
7529     CAST_TO_NUMBER;
7530     CHECK_TYPE(XPATH_NUMBER);
7531     ctxt->value->floatval *= val;
7532 }
7533
7534 /**
7535  * xmlXPathDivValues:
7536  * @ctxt:  the XPath Parser context
7537  *
7538  * Implement the div operation on XPath objects @arg1 / @arg2:
7539  * The numeric operators convert their operands to numbers as if
7540  * by calling the number function.
7541  */
7542 void
7543 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7544     xmlXPathObjectPtr arg;
7545     double val;
7546
7547     arg = valuePop(ctxt);
7548     if (arg == NULL)
7549         XP_ERROR(XPATH_INVALID_OPERAND);
7550     val = xmlXPathCastToNumber(arg);
7551     xmlXPathReleaseObject(ctxt->context, arg);
7552     CAST_TO_NUMBER;
7553     CHECK_TYPE(XPATH_NUMBER);
7554     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7555         ctxt->value->floatval = xmlXPathNAN;
7556     else if (val == 0 && xmlXPathGetSign(val) != 0) {
7557         if (ctxt->value->floatval == 0)
7558             ctxt->value->floatval = xmlXPathNAN;
7559         else if (ctxt->value->floatval > 0)
7560             ctxt->value->floatval = xmlXPathNINF;
7561         else if (ctxt->value->floatval < 0)
7562             ctxt->value->floatval = xmlXPathPINF;
7563     }
7564     else if (val == 0) {
7565         if (ctxt->value->floatval == 0)
7566             ctxt->value->floatval = xmlXPathNAN;
7567         else if (ctxt->value->floatval > 0)
7568             ctxt->value->floatval = xmlXPathPINF;
7569         else if (ctxt->value->floatval < 0)
7570             ctxt->value->floatval = xmlXPathNINF;
7571     } else
7572         ctxt->value->floatval /= val;
7573 }
7574
7575 /**
7576  * xmlXPathModValues:
7577  * @ctxt:  the XPath Parser context
7578  *
7579  * Implement the mod operation on XPath objects: @arg1 / @arg2
7580  * The numeric operators convert their operands to numbers as if
7581  * by calling the number function.
7582  */
7583 void
7584 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7585     xmlXPathObjectPtr arg;
7586     double arg1, arg2;
7587
7588     arg = valuePop(ctxt);
7589     if (arg == NULL)
7590         XP_ERROR(XPATH_INVALID_OPERAND);
7591     arg2 = xmlXPathCastToNumber(arg);
7592     xmlXPathReleaseObject(ctxt->context, arg);
7593     CAST_TO_NUMBER;
7594     CHECK_TYPE(XPATH_NUMBER);
7595     arg1 = ctxt->value->floatval;
7596     if (arg2 == 0)
7597         ctxt->value->floatval = xmlXPathNAN;
7598     else {
7599         ctxt->value->floatval = fmod(arg1, arg2);
7600     }
7601 }
7602
7603 /************************************************************************
7604  *                                                                      *
7605  *              The traversal functions                                 *
7606  *                                                                      *
7607  ************************************************************************/
7608
7609 /*
7610  * A traversal function enumerates nodes along an axis.
7611  * Initially it must be called with NULL, and it indicates
7612  * termination on the axis by returning NULL.
7613  */
7614 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7615                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7616
7617 /*
7618  * xmlXPathTraversalFunctionExt:
7619  * A traversal function enumerates nodes along an axis.
7620  * Initially it must be called with NULL, and it indicates
7621  * termination on the axis by returning NULL.
7622  * The context node of the traversal is specified via @contextNode.
7623  */
7624 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7625                     (xmlNodePtr cur, xmlNodePtr contextNode);
7626
7627 /*
7628  * xmlXPathNodeSetMergeFunction:
7629  * Used for merging node sets in xmlXPathCollectAndTest().
7630  */
7631 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7632                     (xmlNodeSetPtr, xmlNodeSetPtr, int);
7633
7634
7635 /**
7636  * xmlXPathNextSelf:
7637  * @ctxt:  the XPath Parser context
7638  * @cur:  the current node in the traversal
7639  *
7640  * Traversal function for the "self" direction
7641  * The self axis contains just the context node itself
7642  *
7643  * Returns the next element following that axis
7644  */
7645 xmlNodePtr
7646 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7647     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7648     if (cur == NULL)
7649         return(ctxt->context->node);
7650     return(NULL);
7651 }
7652
7653 /**
7654  * xmlXPathNextChild:
7655  * @ctxt:  the XPath Parser context
7656  * @cur:  the current node in the traversal
7657  *
7658  * Traversal function for the "child" direction
7659  * The child axis contains the children of the context node in document order.
7660  *
7661  * Returns the next element following that axis
7662  */
7663 xmlNodePtr
7664 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7665     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7666     if (cur == NULL) {
7667         if (ctxt->context->node == NULL) return(NULL);
7668         switch (ctxt->context->node->type) {
7669             case XML_ELEMENT_NODE:
7670             case XML_TEXT_NODE:
7671             case XML_CDATA_SECTION_NODE:
7672             case XML_ENTITY_REF_NODE:
7673             case XML_ENTITY_NODE:
7674             case XML_PI_NODE:
7675             case XML_COMMENT_NODE:
7676             case XML_NOTATION_NODE:
7677             case XML_DTD_NODE:
7678                 return(ctxt->context->node->children);
7679             case XML_DOCUMENT_NODE:
7680             case XML_DOCUMENT_TYPE_NODE:
7681             case XML_DOCUMENT_FRAG_NODE:
7682             case XML_HTML_DOCUMENT_NODE:
7683 #ifdef LIBXML_DOCB_ENABLED
7684             case XML_DOCB_DOCUMENT_NODE:
7685 #endif
7686                 return(((xmlDocPtr) ctxt->context->node)->children);
7687             case XML_ELEMENT_DECL:
7688             case XML_ATTRIBUTE_DECL:
7689             case XML_ENTITY_DECL:
7690             case XML_ATTRIBUTE_NODE:
7691             case XML_NAMESPACE_DECL:
7692             case XML_XINCLUDE_START:
7693             case XML_XINCLUDE_END:
7694                 return(NULL);
7695         }
7696         return(NULL);
7697     }
7698     if ((cur->type == XML_DOCUMENT_NODE) ||
7699         (cur->type == XML_HTML_DOCUMENT_NODE))
7700         return(NULL);
7701     return(cur->next);
7702 }
7703
7704 /**
7705  * xmlXPathNextChildElement:
7706  * @ctxt:  the XPath Parser context
7707  * @cur:  the current node in the traversal
7708  *
7709  * Traversal function for the "child" direction and nodes of type element.
7710  * The child axis contains the children of the context node in document order.
7711  *
7712  * Returns the next element following that axis
7713  */
7714 static xmlNodePtr
7715 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7716     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7717     if (cur == NULL) {
7718         cur = ctxt->context->node;
7719         if (cur == NULL) return(NULL);
7720         /*
7721         * Get the first element child.
7722         */
7723         switch (cur->type) {
7724             case XML_ELEMENT_NODE:
7725             case XML_DOCUMENT_FRAG_NODE:
7726             case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7727             case XML_ENTITY_NODE:
7728                 cur = cur->children;
7729                 if (cur != NULL) {
7730                     if (cur->type == XML_ELEMENT_NODE)
7731                         return(cur);
7732                     do {
7733                         cur = cur->next;
7734                     } while ((cur != NULL) &&
7735                         (cur->type != XML_ELEMENT_NODE));
7736                     return(cur);
7737                 }
7738                 return(NULL);
7739             case XML_DOCUMENT_NODE:
7740             case XML_HTML_DOCUMENT_NODE:
7741 #ifdef LIBXML_DOCB_ENABLED
7742             case XML_DOCB_DOCUMENT_NODE:
7743 #endif
7744                 return(xmlDocGetRootElement((xmlDocPtr) cur));
7745             default:
7746                 return(NULL);
7747         }
7748         return(NULL);
7749     }
7750     /*
7751     * Get the next sibling element node.
7752     */
7753     switch (cur->type) {
7754         case XML_ELEMENT_NODE:
7755         case XML_TEXT_NODE:
7756         case XML_ENTITY_REF_NODE:
7757         case XML_ENTITY_NODE:
7758         case XML_CDATA_SECTION_NODE:
7759         case XML_PI_NODE:
7760         case XML_COMMENT_NODE:
7761         case XML_XINCLUDE_END:
7762             break;
7763         /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7764         default:
7765             return(NULL);
7766     }
7767     if (cur->next != NULL) {
7768         if (cur->next->type == XML_ELEMENT_NODE)
7769             return(cur->next);
7770         cur = cur->next;
7771         do {
7772             cur = cur->next;
7773         } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7774         return(cur);
7775     }
7776     return(NULL);
7777 }
7778
7779 #if 0
7780 /**
7781  * xmlXPathNextDescendantOrSelfElemParent:
7782  * @ctxt:  the XPath Parser context
7783  * @cur:  the current node in the traversal
7784  *
7785  * Traversal function for the "descendant-or-self" axis.
7786  * Additionally it returns only nodes which can be parents of
7787  * element nodes.
7788  *
7789  *
7790  * Returns the next element following that axis
7791  */
7792 static xmlNodePtr
7793 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7794                                        xmlNodePtr contextNode)
7795 {
7796     if (cur == NULL) {
7797         if (contextNode == NULL)
7798             return(NULL);
7799         switch (contextNode->type) {
7800             case XML_ELEMENT_NODE:
7801             case XML_XINCLUDE_START:
7802             case XML_DOCUMENT_FRAG_NODE:
7803             case XML_DOCUMENT_NODE:
7804 #ifdef LIBXML_DOCB_ENABLED
7805             case XML_DOCB_DOCUMENT_NODE:
7806 #endif
7807             case XML_HTML_DOCUMENT_NODE:
7808                 return(contextNode);
7809             default:
7810                 return(NULL);
7811         }
7812         return(NULL);
7813     } else {
7814         xmlNodePtr start = cur;
7815
7816         while (cur != NULL) {
7817             switch (cur->type) {
7818                 case XML_ELEMENT_NODE:
7819                 /* TODO: OK to have XInclude here? */
7820                 case XML_XINCLUDE_START:
7821                 case XML_DOCUMENT_FRAG_NODE:
7822                     if (cur != start)
7823                         return(cur);
7824                     if (cur->children != NULL) {
7825                         cur = cur->children;
7826                         continue;
7827                     }
7828                     break;
7829                 /* Not sure if we need those here. */
7830                 case XML_DOCUMENT_NODE:
7831 #ifdef LIBXML_DOCB_ENABLED
7832                 case XML_DOCB_DOCUMENT_NODE:
7833 #endif
7834                 case XML_HTML_DOCUMENT_NODE:
7835                     if (cur != start)
7836                         return(cur);
7837                     return(xmlDocGetRootElement((xmlDocPtr) cur));
7838                 default:
7839                     break;
7840             }
7841
7842 next_sibling:
7843             if ((cur == NULL) || (cur == contextNode))
7844                 return(NULL);
7845             if (cur->next != NULL) {
7846                 cur = cur->next;
7847             } else {
7848                 cur = cur->parent;
7849                 goto next_sibling;
7850             }
7851         }
7852     }
7853     return(NULL);
7854 }
7855 #endif
7856
7857 /**
7858  * xmlXPathNextDescendant:
7859  * @ctxt:  the XPath Parser context
7860  * @cur:  the current node in the traversal
7861  *
7862  * Traversal function for the "descendant" direction
7863  * the descendant axis contains the descendants of the context node in document
7864  * order; a descendant is a child or a child of a child and so on.
7865  *
7866  * Returns the next element following that axis
7867  */
7868 xmlNodePtr
7869 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7870     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7871     if (cur == NULL) {
7872         if (ctxt->context->node == NULL)
7873             return(NULL);
7874         if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7875             (ctxt->context->node->type == XML_NAMESPACE_DECL))
7876             return(NULL);
7877
7878         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7879             return(ctxt->context->doc->children);
7880         return(ctxt->context->node->children);
7881     }
7882
7883     if (cur->type == XML_NAMESPACE_DECL)
7884         return(NULL);
7885     if (cur->children != NULL) {
7886         /*
7887          * Do not descend on entities declarations
7888          */
7889         if (cur->children->type != XML_ENTITY_DECL) {
7890             cur = cur->children;
7891             /*
7892              * Skip DTDs
7893              */
7894             if (cur->type != XML_DTD_NODE)
7895                 return(cur);
7896         }
7897     }
7898
7899     if (cur == ctxt->context->node) return(NULL);
7900
7901     while (cur->next != NULL) {
7902         cur = cur->next;
7903         if ((cur->type != XML_ENTITY_DECL) &&
7904             (cur->type != XML_DTD_NODE))
7905             return(cur);
7906     }
7907
7908     do {
7909         cur = cur->parent;
7910         if (cur == NULL) break;
7911         if (cur == ctxt->context->node) return(NULL);
7912         if (cur->next != NULL) {
7913             cur = cur->next;
7914             return(cur);
7915         }
7916     } while (cur != NULL);
7917     return(cur);
7918 }
7919
7920 /**
7921  * xmlXPathNextDescendantOrSelf:
7922  * @ctxt:  the XPath Parser context
7923  * @cur:  the current node in the traversal
7924  *
7925  * Traversal function for the "descendant-or-self" direction
7926  * the descendant-or-self axis contains the context node and the descendants
7927  * of the context node in document order; thus the context node is the first
7928  * node on the axis, and the first child of the context node is the second node
7929  * on the axis
7930  *
7931  * Returns the next element following that axis
7932  */
7933 xmlNodePtr
7934 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7935     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7936     if (cur == NULL)
7937         return(ctxt->context->node);
7938
7939     if (ctxt->context->node == NULL)
7940         return(NULL);
7941     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7942         (ctxt->context->node->type == XML_NAMESPACE_DECL))
7943         return(NULL);
7944
7945     return(xmlXPathNextDescendant(ctxt, cur));
7946 }
7947
7948 /**
7949  * xmlXPathNextParent:
7950  * @ctxt:  the XPath Parser context
7951  * @cur:  the current node in the traversal
7952  *
7953  * Traversal function for the "parent" direction
7954  * The parent axis contains the parent of the context node, if there is one.
7955  *
7956  * Returns the next element following that axis
7957  */
7958 xmlNodePtr
7959 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7960     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7961     /*
7962      * the parent of an attribute or namespace node is the element
7963      * to which the attribute or namespace node is attached
7964      * Namespace handling !!!
7965      */
7966     if (cur == NULL) {
7967         if (ctxt->context->node == NULL) return(NULL);
7968         switch (ctxt->context->node->type) {
7969             case XML_ELEMENT_NODE:
7970             case XML_TEXT_NODE:
7971             case XML_CDATA_SECTION_NODE:
7972             case XML_ENTITY_REF_NODE:
7973             case XML_ENTITY_NODE:
7974             case XML_PI_NODE:
7975             case XML_COMMENT_NODE:
7976             case XML_NOTATION_NODE:
7977             case XML_DTD_NODE:
7978             case XML_ELEMENT_DECL:
7979             case XML_ATTRIBUTE_DECL:
7980             case XML_XINCLUDE_START:
7981             case XML_XINCLUDE_END:
7982             case XML_ENTITY_DECL:
7983                 if (ctxt->context->node->parent == NULL)
7984                     return((xmlNodePtr) ctxt->context->doc);
7985                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7986                     ((ctxt->context->node->parent->name[0] == ' ') ||
7987                      (xmlStrEqual(ctxt->context->node->parent->name,
7988                                  BAD_CAST "fake node libxslt"))))
7989                     return(NULL);
7990                 return(ctxt->context->node->parent);
7991             case XML_ATTRIBUTE_NODE: {
7992                 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7993
7994                 return(att->parent);
7995             }
7996             case XML_DOCUMENT_NODE:
7997             case XML_DOCUMENT_TYPE_NODE:
7998             case XML_DOCUMENT_FRAG_NODE:
7999             case XML_HTML_DOCUMENT_NODE:
8000 #ifdef LIBXML_DOCB_ENABLED
8001             case XML_DOCB_DOCUMENT_NODE:
8002 #endif
8003                 return(NULL);
8004             case XML_NAMESPACE_DECL: {
8005                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8006
8007                 if ((ns->next != NULL) &&
8008                     (ns->next->type != XML_NAMESPACE_DECL))
8009                     return((xmlNodePtr) ns->next);
8010                 return(NULL);
8011             }
8012         }
8013     }
8014     return(NULL);
8015 }
8016
8017 /**
8018  * xmlXPathNextAncestor:
8019  * @ctxt:  the XPath Parser context
8020  * @cur:  the current node in the traversal
8021  *
8022  * Traversal function for the "ancestor" direction
8023  * the ancestor axis contains the ancestors of the context node; the ancestors
8024  * of the context node consist of the parent of context node and the parent's
8025  * parent and so on; the nodes are ordered in reverse document order; thus the
8026  * parent is the first node on the axis, and the parent's parent is the second
8027  * node on the axis
8028  *
8029  * Returns the next element following that axis
8030  */
8031 xmlNodePtr
8032 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8033     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8034     /*
8035      * the parent of an attribute or namespace node is the element
8036      * to which the attribute or namespace node is attached
8037      * !!!!!!!!!!!!!
8038      */
8039     if (cur == NULL) {
8040         if (ctxt->context->node == NULL) return(NULL);
8041         switch (ctxt->context->node->type) {
8042             case XML_ELEMENT_NODE:
8043             case XML_TEXT_NODE:
8044             case XML_CDATA_SECTION_NODE:
8045             case XML_ENTITY_REF_NODE:
8046             case XML_ENTITY_NODE:
8047             case XML_PI_NODE:
8048             case XML_COMMENT_NODE:
8049             case XML_DTD_NODE:
8050             case XML_ELEMENT_DECL:
8051             case XML_ATTRIBUTE_DECL:
8052             case XML_ENTITY_DECL:
8053             case XML_NOTATION_NODE:
8054             case XML_XINCLUDE_START:
8055             case XML_XINCLUDE_END:
8056                 if (ctxt->context->node->parent == NULL)
8057                     return((xmlNodePtr) ctxt->context->doc);
8058                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8059                     ((ctxt->context->node->parent->name[0] == ' ') ||
8060                      (xmlStrEqual(ctxt->context->node->parent->name,
8061                                  BAD_CAST "fake node libxslt"))))
8062                     return(NULL);
8063                 return(ctxt->context->node->parent);
8064             case XML_ATTRIBUTE_NODE: {
8065                 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8066
8067                 return(tmp->parent);
8068             }
8069             case XML_DOCUMENT_NODE:
8070             case XML_DOCUMENT_TYPE_NODE:
8071             case XML_DOCUMENT_FRAG_NODE:
8072             case XML_HTML_DOCUMENT_NODE:
8073 #ifdef LIBXML_DOCB_ENABLED
8074             case XML_DOCB_DOCUMENT_NODE:
8075 #endif
8076                 return(NULL);
8077             case XML_NAMESPACE_DECL: {
8078                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8079
8080                 if ((ns->next != NULL) &&
8081                     (ns->next->type != XML_NAMESPACE_DECL))
8082                     return((xmlNodePtr) ns->next);
8083                 /* Bad, how did that namespace end up here ? */
8084                 return(NULL);
8085             }
8086         }
8087         return(NULL);
8088     }
8089     if (cur == ctxt->context->doc->children)
8090         return((xmlNodePtr) ctxt->context->doc);
8091     if (cur == (xmlNodePtr) ctxt->context->doc)
8092         return(NULL);
8093     switch (cur->type) {
8094         case XML_ELEMENT_NODE:
8095         case XML_TEXT_NODE:
8096         case XML_CDATA_SECTION_NODE:
8097         case XML_ENTITY_REF_NODE:
8098         case XML_ENTITY_NODE:
8099         case XML_PI_NODE:
8100         case XML_COMMENT_NODE:
8101         case XML_NOTATION_NODE:
8102         case XML_DTD_NODE:
8103         case XML_ELEMENT_DECL:
8104         case XML_ATTRIBUTE_DECL:
8105         case XML_ENTITY_DECL:
8106         case XML_XINCLUDE_START:
8107         case XML_XINCLUDE_END:
8108             if (cur->parent == NULL)
8109                 return(NULL);
8110             if ((cur->parent->type == XML_ELEMENT_NODE) &&
8111                 ((cur->parent->name[0] == ' ') ||
8112                  (xmlStrEqual(cur->parent->name,
8113                               BAD_CAST "fake node libxslt"))))
8114                 return(NULL);
8115             return(cur->parent);
8116         case XML_ATTRIBUTE_NODE: {
8117             xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8118
8119             return(att->parent);
8120         }
8121         case XML_NAMESPACE_DECL: {
8122             xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8123
8124             if ((ns->next != NULL) &&
8125                 (ns->next->type != XML_NAMESPACE_DECL))
8126                 return((xmlNodePtr) ns->next);
8127             /* Bad, how did that namespace end up here ? */
8128             return(NULL);
8129         }
8130         case XML_DOCUMENT_NODE:
8131         case XML_DOCUMENT_TYPE_NODE:
8132         case XML_DOCUMENT_FRAG_NODE:
8133         case XML_HTML_DOCUMENT_NODE:
8134 #ifdef LIBXML_DOCB_ENABLED
8135         case XML_DOCB_DOCUMENT_NODE:
8136 #endif
8137             return(NULL);
8138     }
8139     return(NULL);
8140 }
8141
8142 /**
8143  * xmlXPathNextAncestorOrSelf:
8144  * @ctxt:  the XPath Parser context
8145  * @cur:  the current node in the traversal
8146  *
8147  * Traversal function for the "ancestor-or-self" direction
8148  * he ancestor-or-self axis contains the context node and ancestors of
8149  * the context node in reverse document order; thus the context node is
8150  * the first node on the axis, and the context node's parent the second;
8151  * parent here is defined the same as with the parent axis.
8152  *
8153  * Returns the next element following that axis
8154  */
8155 xmlNodePtr
8156 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8157     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8158     if (cur == NULL)
8159         return(ctxt->context->node);
8160     return(xmlXPathNextAncestor(ctxt, cur));
8161 }
8162
8163 /**
8164  * xmlXPathNextFollowingSibling:
8165  * @ctxt:  the XPath Parser context
8166  * @cur:  the current node in the traversal
8167  *
8168  * Traversal function for the "following-sibling" direction
8169  * The following-sibling axis contains the following siblings of the context
8170  * node in document order.
8171  *
8172  * Returns the next element following that axis
8173  */
8174 xmlNodePtr
8175 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8176     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8177     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8178         (ctxt->context->node->type == XML_NAMESPACE_DECL))
8179         return(NULL);
8180     if (cur == (xmlNodePtr) ctxt->context->doc)
8181         return(NULL);
8182     if (cur == NULL)
8183         return(ctxt->context->node->next);
8184     return(cur->next);
8185 }
8186
8187 /**
8188  * xmlXPathNextPrecedingSibling:
8189  * @ctxt:  the XPath Parser context
8190  * @cur:  the current node in the traversal
8191  *
8192  * Traversal function for the "preceding-sibling" direction
8193  * The preceding-sibling axis contains the preceding siblings of the context
8194  * node in reverse document order; the first preceding sibling is first on the
8195  * axis; the sibling preceding that node is the second on the axis and so on.
8196  *
8197  * Returns the next element following that axis
8198  */
8199 xmlNodePtr
8200 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8201     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8202     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8203         (ctxt->context->node->type == XML_NAMESPACE_DECL))
8204         return(NULL);
8205     if (cur == (xmlNodePtr) ctxt->context->doc)
8206         return(NULL);
8207     if (cur == NULL)
8208         return(ctxt->context->node->prev);
8209     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8210         cur = cur->prev;
8211         if (cur == NULL)
8212             return(ctxt->context->node->prev);
8213     }
8214     return(cur->prev);
8215 }
8216
8217 /**
8218  * xmlXPathNextFollowing:
8219  * @ctxt:  the XPath Parser context
8220  * @cur:  the current node in the traversal
8221  *
8222  * Traversal function for the "following" direction
8223  * The following axis contains all nodes in the same document as the context
8224  * node that are after the context node in document order, excluding any
8225  * descendants and excluding attribute nodes and namespace nodes; the nodes
8226  * are ordered in document order
8227  *
8228  * Returns the next element following that axis
8229  */
8230 xmlNodePtr
8231 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8232     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8233     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8234         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8235         return(cur->children);
8236
8237     if (cur == NULL) {
8238         cur = ctxt->context->node;
8239         if (cur->type == XML_NAMESPACE_DECL)
8240             return(NULL);
8241         if (cur->type == XML_ATTRIBUTE_NODE)
8242             cur = cur->parent;
8243     }
8244     if (cur == NULL) return(NULL) ; /* ERROR */
8245     if (cur->next != NULL) return(cur->next) ;
8246     do {
8247         cur = cur->parent;
8248         if (cur == NULL) break;
8249         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8250         if (cur->next != NULL) return(cur->next);
8251     } while (cur != NULL);
8252     return(cur);
8253 }
8254
8255 /*
8256  * xmlXPathIsAncestor:
8257  * @ancestor:  the ancestor node
8258  * @node:  the current node
8259  *
8260  * Check that @ancestor is a @node's ancestor
8261  *
8262  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8263  */
8264 static int
8265 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8266     if ((ancestor == NULL) || (node == NULL)) return(0);
8267     if (node->type == XML_NAMESPACE_DECL)
8268         return(0);
8269     if (ancestor->type == XML_NAMESPACE_DECL)
8270         return(0);
8271     /* nodes need to be in the same document */
8272     if (ancestor->doc != node->doc) return(0);
8273     /* avoid searching if ancestor or node is the root node */
8274     if (ancestor == (xmlNodePtr) node->doc) return(1);
8275     if (node == (xmlNodePtr) ancestor->doc) return(0);
8276     while (node->parent != NULL) {
8277         if (node->parent == ancestor)
8278             return(1);
8279         node = node->parent;
8280     }
8281     return(0);
8282 }
8283
8284 /**
8285  * xmlXPathNextPreceding:
8286  * @ctxt:  the XPath Parser context
8287  * @cur:  the current node in the traversal
8288  *
8289  * Traversal function for the "preceding" direction
8290  * the preceding axis contains all nodes in the same document as the context
8291  * node that are before the context node in document order, excluding any
8292  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8293  * ordered in reverse document order
8294  *
8295  * Returns the next element following that axis
8296  */
8297 xmlNodePtr
8298 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8299 {
8300     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8301     if (cur == NULL) {
8302         cur = ctxt->context->node;
8303         if (cur->type == XML_NAMESPACE_DECL)
8304             return(NULL);
8305         if (cur->type == XML_ATTRIBUTE_NODE)
8306             return(cur->parent);
8307     }
8308     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8309         return (NULL);
8310     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8311         cur = cur->prev;
8312     do {
8313         if (cur->prev != NULL) {
8314             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8315             return (cur);
8316         }
8317
8318         cur = cur->parent;
8319         if (cur == NULL)
8320             return (NULL);
8321         if (cur == ctxt->context->doc->children)
8322             return (NULL);
8323     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8324     return (cur);
8325 }
8326
8327 /**
8328  * xmlXPathNextPrecedingInternal:
8329  * @ctxt:  the XPath Parser context
8330  * @cur:  the current node in the traversal
8331  *
8332  * Traversal function for the "preceding" direction
8333  * the preceding axis contains all nodes in the same document as the context
8334  * node that are before the context node in document order, excluding any
8335  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8336  * ordered in reverse document order
8337  * This is a faster implementation but internal only since it requires a
8338  * state kept in the parser context: ctxt->ancestor.
8339  *
8340  * Returns the next element following that axis
8341  */
8342 static xmlNodePtr
8343 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8344                               xmlNodePtr cur)
8345 {
8346     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8347     if (cur == NULL) {
8348         cur = ctxt->context->node;
8349         if (cur == NULL)
8350             return (NULL);
8351         if (cur->type == XML_NAMESPACE_DECL)
8352             return (NULL);
8353         ctxt->ancestor = cur->parent;
8354     }
8355     if (cur->type == XML_NAMESPACE_DECL)
8356         return(NULL);
8357     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8358         cur = cur->prev;
8359     while (cur->prev == NULL) {
8360         cur = cur->parent;
8361         if (cur == NULL)
8362             return (NULL);
8363         if (cur == ctxt->context->doc->children)
8364             return (NULL);
8365         if (cur != ctxt->ancestor)
8366             return (cur);
8367         ctxt->ancestor = cur->parent;
8368     }
8369     cur = cur->prev;
8370     while (cur->last != NULL)
8371         cur = cur->last;
8372     return (cur);
8373 }
8374
8375 /**
8376  * xmlXPathNextNamespace:
8377  * @ctxt:  the XPath Parser context
8378  * @cur:  the current attribute in the traversal
8379  *
8380  * Traversal function for the "namespace" direction
8381  * the namespace axis contains the namespace nodes of the context node;
8382  * the order of nodes on this axis is implementation-defined; the axis will
8383  * be empty unless the context node is an element
8384  *
8385  * We keep the XML namespace node at the end of the list.
8386  *
8387  * Returns the next element following that axis
8388  */
8389 xmlNodePtr
8390 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8391     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8392     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8393     if (cur == NULL) {
8394         if (ctxt->context->tmpNsList != NULL)
8395             xmlFree(ctxt->context->tmpNsList);
8396         ctxt->context->tmpNsList =
8397             xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8398         ctxt->context->tmpNsNr = 0;
8399         if (ctxt->context->tmpNsList != NULL) {
8400             while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8401                 ctxt->context->tmpNsNr++;
8402             }
8403         }
8404         return((xmlNodePtr) xmlXPathXMLNamespace);
8405     }
8406     if (ctxt->context->tmpNsNr > 0) {
8407         return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8408     } else {
8409         if (ctxt->context->tmpNsList != NULL)
8410             xmlFree(ctxt->context->tmpNsList);
8411         ctxt->context->tmpNsList = NULL;
8412         return(NULL);
8413     }
8414 }
8415
8416 /**
8417  * xmlXPathNextAttribute:
8418  * @ctxt:  the XPath Parser context
8419  * @cur:  the current attribute in the traversal
8420  *
8421  * Traversal function for the "attribute" direction
8422  * TODO: support DTD inherited default attributes
8423  *
8424  * Returns the next element following that axis
8425  */
8426 xmlNodePtr
8427 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8428     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8429     if (ctxt->context->node == NULL)
8430         return(NULL);
8431     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8432         return(NULL);
8433     if (cur == NULL) {
8434         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8435             return(NULL);
8436         return((xmlNodePtr)ctxt->context->node->properties);
8437     }
8438     return((xmlNodePtr)cur->next);
8439 }
8440
8441 /************************************************************************
8442  *                                                                      *
8443  *              NodeTest Functions                                      *
8444  *                                                                      *
8445  ************************************************************************/
8446
8447 #define IS_FUNCTION                     200
8448
8449
8450 /************************************************************************
8451  *                                                                      *
8452  *              Implicit tree core function library                     *
8453  *                                                                      *
8454  ************************************************************************/
8455
8456 /**
8457  * xmlXPathRoot:
8458  * @ctxt:  the XPath Parser context
8459  *
8460  * Initialize the context to the root of the document
8461  */
8462 void
8463 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8464     if ((ctxt == NULL) || (ctxt->context == NULL))
8465         return;
8466     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8467     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8468         ctxt->context->node));
8469 }
8470
8471 /************************************************************************
8472  *                                                                      *
8473  *              The explicit core function library                      *
8474  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8475  *                                                                      *
8476  ************************************************************************/
8477
8478
8479 /**
8480  * xmlXPathLastFunction:
8481  * @ctxt:  the XPath Parser context
8482  * @nargs:  the number of arguments
8483  *
8484  * Implement the last() XPath function
8485  *    number last()
8486  * The last function returns the number of nodes in the context node list.
8487  */
8488 void
8489 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8490     CHECK_ARITY(0);
8491     if (ctxt->context->contextSize >= 0) {
8492         valuePush(ctxt,
8493             xmlXPathCacheNewFloat(ctxt->context,
8494                 (double) ctxt->context->contextSize));
8495 #ifdef DEBUG_EXPR
8496         xmlGenericError(xmlGenericErrorContext,
8497                 "last() : %d\n", ctxt->context->contextSize);
8498 #endif
8499     } else {
8500         XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8501     }
8502 }
8503
8504 /**
8505  * xmlXPathPositionFunction:
8506  * @ctxt:  the XPath Parser context
8507  * @nargs:  the number of arguments
8508  *
8509  * Implement the position() XPath function
8510  *    number position()
8511  * The position function returns the position of the context node in the
8512  * context node list. The first position is 1, and so the last position
8513  * will be equal to last().
8514  */
8515 void
8516 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8517     CHECK_ARITY(0);
8518     if (ctxt->context->proximityPosition >= 0) {
8519         valuePush(ctxt,
8520               xmlXPathCacheNewFloat(ctxt->context,
8521                 (double) ctxt->context->proximityPosition));
8522 #ifdef DEBUG_EXPR
8523         xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8524                 ctxt->context->proximityPosition);
8525 #endif
8526     } else {
8527         XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8528     }
8529 }
8530
8531 /**
8532  * xmlXPathCountFunction:
8533  * @ctxt:  the XPath Parser context
8534  * @nargs:  the number of arguments
8535  *
8536  * Implement the count() XPath function
8537  *    number count(node-set)
8538  */
8539 void
8540 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8541     xmlXPathObjectPtr cur;
8542
8543     CHECK_ARITY(1);
8544     if ((ctxt->value == NULL) ||
8545         ((ctxt->value->type != XPATH_NODESET) &&
8546          (ctxt->value->type != XPATH_XSLT_TREE)))
8547         XP_ERROR(XPATH_INVALID_TYPE);
8548     cur = valuePop(ctxt);
8549
8550     if ((cur == NULL) || (cur->nodesetval == NULL))
8551         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8552     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8553         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8554             (double) cur->nodesetval->nodeNr));
8555     } else {
8556         if ((cur->nodesetval->nodeNr != 1) ||
8557             (cur->nodesetval->nodeTab == NULL)) {
8558             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8559         } else {
8560             xmlNodePtr tmp;
8561             int i = 0;
8562
8563             tmp = cur->nodesetval->nodeTab[0];
8564             if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8565                 tmp = tmp->children;
8566                 while (tmp != NULL) {
8567                     tmp = tmp->next;
8568                     i++;
8569                 }
8570             }
8571             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8572         }
8573     }
8574     xmlXPathReleaseObject(ctxt->context, cur);
8575 }
8576
8577 /**
8578  * xmlXPathGetElementsByIds:
8579  * @doc:  the document
8580  * @ids:  a whitespace separated list of IDs
8581  *
8582  * Selects elements by their unique ID.
8583  *
8584  * Returns a node-set of selected elements.
8585  */
8586 static xmlNodeSetPtr
8587 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8588     xmlNodeSetPtr ret;
8589     const xmlChar *cur = ids;
8590     xmlChar *ID;
8591     xmlAttrPtr attr;
8592     xmlNodePtr elem = NULL;
8593
8594     if (ids == NULL) return(NULL);
8595
8596     ret = xmlXPathNodeSetCreate(NULL);
8597     if (ret == NULL)
8598         return(ret);
8599
8600     while (IS_BLANK_CH(*cur)) cur++;
8601     while (*cur != 0) {
8602         while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8603             cur++;
8604
8605         ID = xmlStrndup(ids, cur - ids);
8606         if (ID != NULL) {
8607             /*
8608              * We used to check the fact that the value passed
8609              * was an NCName, but this generated much troubles for
8610              * me and Aleksey Sanin, people blatantly violated that
8611              * constaint, like Visa3D spec.
8612              * if (xmlValidateNCName(ID, 1) == 0)
8613              */
8614             attr = xmlGetID(doc, ID);
8615             if (attr != NULL) {
8616                 if (attr->type == XML_ATTRIBUTE_NODE)
8617                     elem = attr->parent;
8618                 else if (attr->type == XML_ELEMENT_NODE)
8619                     elem = (xmlNodePtr) attr;
8620                 else
8621                     elem = NULL;
8622                 if (elem != NULL)
8623                     xmlXPathNodeSetAdd(ret, elem);
8624             }
8625             xmlFree(ID);
8626         }
8627
8628         while (IS_BLANK_CH(*cur)) cur++;
8629         ids = cur;
8630     }
8631     return(ret);
8632 }
8633
8634 /**
8635  * xmlXPathIdFunction:
8636  * @ctxt:  the XPath Parser context
8637  * @nargs:  the number of arguments
8638  *
8639  * Implement the id() XPath function
8640  *    node-set id(object)
8641  * The id function selects elements by their unique ID
8642  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8643  * then the result is the union of the result of applying id to the
8644  * string value of each of the nodes in the argument node-set. When the
8645  * argument to id is of any other type, the argument is converted to a
8646  * string as if by a call to the string function; the string is split
8647  * into a whitespace-separated list of tokens (whitespace is any sequence
8648  * of characters matching the production S); the result is a node-set
8649  * containing the elements in the same document as the context node that
8650  * have a unique ID equal to any of the tokens in the list.
8651  */
8652 void
8653 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8654     xmlChar *tokens;
8655     xmlNodeSetPtr ret;
8656     xmlXPathObjectPtr obj;
8657
8658     CHECK_ARITY(1);
8659     obj = valuePop(ctxt);
8660     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8661     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8662         xmlNodeSetPtr ns;
8663         int i;
8664
8665         ret = xmlXPathNodeSetCreate(NULL);
8666         /*
8667          * FIXME -- in an out-of-memory condition this will behave badly.
8668          * The solution is not clear -- we already popped an item from
8669          * ctxt, so the object is in a corrupt state.
8670          */
8671
8672         if (obj->nodesetval != NULL) {
8673             for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8674                 tokens =
8675                     xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8676                 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8677                 ret = xmlXPathNodeSetMerge(ret, ns);
8678                 xmlXPathFreeNodeSet(ns);
8679                 if (tokens != NULL)
8680                     xmlFree(tokens);
8681             }
8682         }
8683         xmlXPathReleaseObject(ctxt->context, obj);
8684         valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8685         return;
8686     }
8687     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8688     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8689     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8690     xmlXPathReleaseObject(ctxt->context, obj);
8691     return;
8692 }
8693
8694 /**
8695  * xmlXPathLocalNameFunction:
8696  * @ctxt:  the XPath Parser context
8697  * @nargs:  the number of arguments
8698  *
8699  * Implement the local-name() XPath function
8700  *    string local-name(node-set?)
8701  * The local-name function returns a string containing the local part
8702  * of the name of the node in the argument node-set that is first in
8703  * document order. If the node-set is empty or the first node has no
8704  * name, an empty string is returned. If the argument is omitted it
8705  * defaults to the context node.
8706  */
8707 void
8708 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8709     xmlXPathObjectPtr cur;
8710
8711     if (ctxt == NULL) return;
8712
8713     if (nargs == 0) {
8714         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8715             ctxt->context->node));
8716         nargs = 1;
8717     }
8718
8719     CHECK_ARITY(1);
8720     if ((ctxt->value == NULL) ||
8721         ((ctxt->value->type != XPATH_NODESET) &&
8722          (ctxt->value->type != XPATH_XSLT_TREE)))
8723         XP_ERROR(XPATH_INVALID_TYPE);
8724     cur = valuePop(ctxt);
8725
8726     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8727         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8728     } else {
8729         int i = 0; /* Should be first in document order !!!!! */
8730         switch (cur->nodesetval->nodeTab[i]->type) {
8731         case XML_ELEMENT_NODE:
8732         case XML_ATTRIBUTE_NODE:
8733         case XML_PI_NODE:
8734             if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8735                 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8736             else
8737                 valuePush(ctxt,
8738                       xmlXPathCacheNewString(ctxt->context,
8739                         cur->nodesetval->nodeTab[i]->name));
8740             break;
8741         case XML_NAMESPACE_DECL:
8742             valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8743                         ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8744             break;
8745         default:
8746             valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8747         }
8748     }
8749     xmlXPathReleaseObject(ctxt->context, cur);
8750 }
8751
8752 /**
8753  * xmlXPathNamespaceURIFunction:
8754  * @ctxt:  the XPath Parser context
8755  * @nargs:  the number of arguments
8756  *
8757  * Implement the namespace-uri() XPath function
8758  *    string namespace-uri(node-set?)
8759  * The namespace-uri function returns a string containing the
8760  * namespace URI of the expanded name of the node in the argument
8761  * node-set that is first in document order. If the node-set is empty,
8762  * the first node has no name, or the expanded name has no namespace
8763  * URI, an empty string is returned. If the argument is omitted it
8764  * defaults to the context node.
8765  */
8766 void
8767 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8768     xmlXPathObjectPtr cur;
8769
8770     if (ctxt == NULL) return;
8771
8772     if (nargs == 0) {
8773         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8774             ctxt->context->node));
8775         nargs = 1;
8776     }
8777     CHECK_ARITY(1);
8778     if ((ctxt->value == NULL) ||
8779         ((ctxt->value->type != XPATH_NODESET) &&
8780          (ctxt->value->type != XPATH_XSLT_TREE)))
8781         XP_ERROR(XPATH_INVALID_TYPE);
8782     cur = valuePop(ctxt);
8783
8784     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8785         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8786     } else {
8787         int i = 0; /* Should be first in document order !!!!! */
8788         switch (cur->nodesetval->nodeTab[i]->type) {
8789         case XML_ELEMENT_NODE:
8790         case XML_ATTRIBUTE_NODE:
8791             if (cur->nodesetval->nodeTab[i]->ns == NULL)
8792                 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8793             else
8794                 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8795                           cur->nodesetval->nodeTab[i]->ns->href));
8796             break;
8797         default:
8798             valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8799         }
8800     }
8801     xmlXPathReleaseObject(ctxt->context, cur);
8802 }
8803
8804 /**
8805  * xmlXPathNameFunction:
8806  * @ctxt:  the XPath Parser context
8807  * @nargs:  the number of arguments
8808  *
8809  * Implement the name() XPath function
8810  *    string name(node-set?)
8811  * The name function returns a string containing a QName representing
8812  * the name of the node in the argument node-set that is first in document
8813  * order. The QName must represent the name with respect to the namespace
8814  * declarations in effect on the node whose name is being represented.
8815  * Typically, this will be the form in which the name occurred in the XML
8816  * source. This need not be the case if there are namespace declarations
8817  * in effect on the node that associate multiple prefixes with the same
8818  * namespace. However, an implementation may include information about
8819  * the original prefix in its representation of nodes; in this case, an
8820  * implementation can ensure that the returned string is always the same
8821  * as the QName used in the XML source. If the argument it omitted it
8822  * defaults to the context node.
8823  * Libxml keep the original prefix so the "real qualified name" used is
8824  * returned.
8825  */
8826 static void
8827 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8828 {
8829     xmlXPathObjectPtr cur;
8830
8831     if (nargs == 0) {
8832         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8833             ctxt->context->node));
8834         nargs = 1;
8835     }
8836
8837     CHECK_ARITY(1);
8838     if ((ctxt->value == NULL) ||
8839         ((ctxt->value->type != XPATH_NODESET) &&
8840          (ctxt->value->type != XPATH_XSLT_TREE)))
8841         XP_ERROR(XPATH_INVALID_TYPE);
8842     cur = valuePop(ctxt);
8843
8844     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8845         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8846     } else {
8847         int i = 0;              /* Should be first in document order !!!!! */
8848
8849         switch (cur->nodesetval->nodeTab[i]->type) {
8850             case XML_ELEMENT_NODE:
8851             case XML_ATTRIBUTE_NODE:
8852                 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8853                     valuePush(ctxt,
8854                         xmlXPathCacheNewCString(ctxt->context, ""));
8855                 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8856                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8857                     valuePush(ctxt,
8858                         xmlXPathCacheNewString(ctxt->context,
8859                             cur->nodesetval->nodeTab[i]->name));
8860                 } else {
8861                     xmlChar *fullname;
8862
8863                     fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8864                                      cur->nodesetval->nodeTab[i]->ns->prefix,
8865                                      NULL, 0);
8866                     if (fullname == cur->nodesetval->nodeTab[i]->name)
8867                         fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8868                     if (fullname == NULL) {
8869                         XP_ERROR(XPATH_MEMORY_ERROR);
8870                     }
8871                     valuePush(ctxt, xmlXPathCacheWrapString(
8872                         ctxt->context, fullname));
8873                 }
8874                 break;
8875             default:
8876                 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8877                     cur->nodesetval->nodeTab[i]));
8878                 xmlXPathLocalNameFunction(ctxt, 1);
8879         }
8880     }
8881     xmlXPathReleaseObject(ctxt->context, cur);
8882 }
8883
8884
8885 /**
8886  * xmlXPathStringFunction:
8887  * @ctxt:  the XPath Parser context
8888  * @nargs:  the number of arguments
8889  *
8890  * Implement the string() XPath function
8891  *    string string(object?)
8892  * The string function converts an object to a string as follows:
8893  *    - A node-set is converted to a string by returning the value of
8894  *      the node in the node-set that is first in document order.
8895  *      If the node-set is empty, an empty string is returned.
8896  *    - A number is converted to a string as follows
8897  *      + NaN is converted to the string NaN
8898  *      + positive zero is converted to the string 0
8899  *      + negative zero is converted to the string 0
8900  *      + positive infinity is converted to the string Infinity
8901  *      + negative infinity is converted to the string -Infinity
8902  *      + if the number is an integer, the number is represented in
8903  *        decimal form as a Number with no decimal point and no leading
8904  *        zeros, preceded by a minus sign (-) if the number is negative
8905  *      + otherwise, the number is represented in decimal form as a
8906  *        Number including a decimal point with at least one digit
8907  *        before the decimal point and at least one digit after the
8908  *        decimal point, preceded by a minus sign (-) if the number
8909  *        is negative; there must be no leading zeros before the decimal
8910  *        point apart possibly from the one required digit immediately
8911  *        before the decimal point; beyond the one required digit
8912  *        after the decimal point there must be as many, but only as
8913  *        many, more digits as are needed to uniquely distinguish the
8914  *        number from all other IEEE 754 numeric values.
8915  *    - The boolean false value is converted to the string false.
8916  *      The boolean true value is converted to the string true.
8917  *
8918  * If the argument is omitted, it defaults to a node-set with the
8919  * context node as its only member.
8920  */
8921 void
8922 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8923     xmlXPathObjectPtr cur;
8924
8925     if (ctxt == NULL) return;
8926     if (nargs == 0) {
8927     valuePush(ctxt,
8928         xmlXPathCacheWrapString(ctxt->context,
8929             xmlXPathCastNodeToString(ctxt->context->node)));
8930         return;
8931     }
8932
8933     CHECK_ARITY(1);
8934     cur = valuePop(ctxt);
8935     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8936     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8937 }
8938
8939 /**
8940  * xmlXPathStringLengthFunction:
8941  * @ctxt:  the XPath Parser context
8942  * @nargs:  the number of arguments
8943  *
8944  * Implement the string-length() XPath function
8945  *    number string-length(string?)
8946  * The string-length returns the number of characters in the string
8947  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8948  * the context node converted to a string, in other words the value
8949  * of the context node.
8950  */
8951 void
8952 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8953     xmlXPathObjectPtr cur;
8954
8955     if (nargs == 0) {
8956         if ((ctxt == NULL) || (ctxt->context == NULL))
8957             return;
8958         if (ctxt->context->node == NULL) {
8959             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8960         } else {
8961             xmlChar *content;
8962
8963             content = xmlXPathCastNodeToString(ctxt->context->node);
8964             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8965                 xmlUTF8Strlen(content)));
8966             xmlFree(content);
8967         }
8968         return;
8969     }
8970     CHECK_ARITY(1);
8971     CAST_TO_STRING;
8972     CHECK_TYPE(XPATH_STRING);
8973     cur = valuePop(ctxt);
8974     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8975         xmlUTF8Strlen(cur->stringval)));
8976     xmlXPathReleaseObject(ctxt->context, cur);
8977 }
8978
8979 /**
8980  * xmlXPathConcatFunction:
8981  * @ctxt:  the XPath Parser context
8982  * @nargs:  the number of arguments
8983  *
8984  * Implement the concat() XPath function
8985  *    string concat(string, string, string*)
8986  * The concat function returns the concatenation of its arguments.
8987  */
8988 void
8989 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8990     xmlXPathObjectPtr cur, newobj;
8991     xmlChar *tmp;
8992
8993     if (ctxt == NULL) return;
8994     if (nargs < 2) {
8995         CHECK_ARITY(2);
8996     }
8997
8998     CAST_TO_STRING;
8999     cur = valuePop(ctxt);
9000     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9001         xmlXPathReleaseObject(ctxt->context, cur);
9002         return;
9003     }
9004     nargs--;
9005
9006     while (nargs > 0) {
9007         CAST_TO_STRING;
9008         newobj = valuePop(ctxt);
9009         if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9010             xmlXPathReleaseObject(ctxt->context, newobj);
9011             xmlXPathReleaseObject(ctxt->context, cur);
9012             XP_ERROR(XPATH_INVALID_TYPE);
9013         }
9014         tmp = xmlStrcat(newobj->stringval, cur->stringval);
9015         newobj->stringval = cur->stringval;
9016         cur->stringval = tmp;
9017         xmlXPathReleaseObject(ctxt->context, newobj);
9018         nargs--;
9019     }
9020     valuePush(ctxt, cur);
9021 }
9022
9023 /**
9024  * xmlXPathContainsFunction:
9025  * @ctxt:  the XPath Parser context
9026  * @nargs:  the number of arguments
9027  *
9028  * Implement the contains() XPath function
9029  *    boolean contains(string, string)
9030  * The contains function returns true if the first argument string
9031  * contains the second argument string, and otherwise returns false.
9032  */
9033 void
9034 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9035     xmlXPathObjectPtr hay, needle;
9036
9037     CHECK_ARITY(2);
9038     CAST_TO_STRING;
9039     CHECK_TYPE(XPATH_STRING);
9040     needle = valuePop(ctxt);
9041     CAST_TO_STRING;
9042     hay = valuePop(ctxt);
9043
9044     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9045         xmlXPathReleaseObject(ctxt->context, hay);
9046         xmlXPathReleaseObject(ctxt->context, needle);
9047         XP_ERROR(XPATH_INVALID_TYPE);
9048     }
9049     if (xmlStrstr(hay->stringval, needle->stringval))
9050         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9051     else
9052         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9053     xmlXPathReleaseObject(ctxt->context, hay);
9054     xmlXPathReleaseObject(ctxt->context, needle);
9055 }
9056
9057 /**
9058  * xmlXPathStartsWithFunction:
9059  * @ctxt:  the XPath Parser context
9060  * @nargs:  the number of arguments
9061  *
9062  * Implement the starts-with() XPath function
9063  *    boolean starts-with(string, string)
9064  * The starts-with function returns true if the first argument string
9065  * starts with the second argument string, and otherwise returns false.
9066  */
9067 void
9068 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9069     xmlXPathObjectPtr hay, needle;
9070     int n;
9071
9072     CHECK_ARITY(2);
9073     CAST_TO_STRING;
9074     CHECK_TYPE(XPATH_STRING);
9075     needle = valuePop(ctxt);
9076     CAST_TO_STRING;
9077     hay = valuePop(ctxt);
9078
9079     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9080         xmlXPathReleaseObject(ctxt->context, hay);
9081         xmlXPathReleaseObject(ctxt->context, needle);
9082         XP_ERROR(XPATH_INVALID_TYPE);
9083     }
9084     n = xmlStrlen(needle->stringval);
9085     if (xmlStrncmp(hay->stringval, needle->stringval, n))
9086         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9087     else
9088         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9089     xmlXPathReleaseObject(ctxt->context, hay);
9090     xmlXPathReleaseObject(ctxt->context, needle);
9091 }
9092
9093 /**
9094  * xmlXPathSubstringFunction:
9095  * @ctxt:  the XPath Parser context
9096  * @nargs:  the number of arguments
9097  *
9098  * Implement the substring() XPath function
9099  *    string substring(string, number, number?)
9100  * The substring function returns the substring of the first argument
9101  * starting at the position specified in the second argument with
9102  * length specified in the third argument. For example,
9103  * substring("12345",2,3) returns "234". If the third argument is not
9104  * specified, it returns the substring starting at the position specified
9105  * in the second argument and continuing to the end of the string. For
9106  * example, substring("12345",2) returns "2345".  More precisely, each
9107  * character in the string (see [3.6 Strings]) is considered to have a
9108  * numeric position: the position of the first character is 1, the position
9109  * of the second character is 2 and so on. The returned substring contains
9110  * those characters for which the position of the character is greater than
9111  * or equal to the second argument and, if the third argument is specified,
9112  * less than the sum of the second and third arguments; the comparisons
9113  * and addition used for the above follow the standard IEEE 754 rules. Thus:
9114  *  - substring("12345", 1.5, 2.6) returns "234"
9115  *  - substring("12345", 0, 3) returns "12"
9116  *  - substring("12345", 0 div 0, 3) returns ""
9117  *  - substring("12345", 1, 0 div 0) returns ""
9118  *  - substring("12345", -42, 1 div 0) returns "12345"
9119  *  - substring("12345", -1 div 0, 1 div 0) returns ""
9120  */
9121 void
9122 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9123     xmlXPathObjectPtr str, start, len;
9124     double le=0, in;
9125     int i, l, m;
9126     xmlChar *ret;
9127
9128     if (nargs < 2) {
9129         CHECK_ARITY(2);
9130     }
9131     if (nargs > 3) {
9132         CHECK_ARITY(3);
9133     }
9134     /*
9135      * take care of possible last (position) argument
9136     */
9137     if (nargs == 3) {
9138         CAST_TO_NUMBER;
9139         CHECK_TYPE(XPATH_NUMBER);
9140         len = valuePop(ctxt);
9141         le = len->floatval;
9142         xmlXPathReleaseObject(ctxt->context, len);
9143     }
9144
9145     CAST_TO_NUMBER;
9146     CHECK_TYPE(XPATH_NUMBER);
9147     start = valuePop(ctxt);
9148     in = start->floatval;
9149     xmlXPathReleaseObject(ctxt->context, start);
9150     CAST_TO_STRING;
9151     CHECK_TYPE(XPATH_STRING);
9152     str = valuePop(ctxt);
9153     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9154
9155     /*
9156      * If last pos not present, calculate last position
9157     */
9158     if (nargs != 3) {
9159         le = (double)m;
9160         if (in < 1.0)
9161             in = 1.0;
9162     }
9163
9164     /* Need to check for the special cases where either
9165      * the index is NaN, the length is NaN, or both
9166      * arguments are infinity (relying on Inf + -Inf = NaN)
9167      */
9168     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9169         /*
9170          * To meet the requirements of the spec, the arguments
9171          * must be converted to integer format before
9172          * initial index calculations are done
9173          *
9174          * First we go to integer form, rounding up
9175          * and checking for special cases
9176          */
9177         i = (int) in;
9178         if (((double)i)+0.5 <= in) i++;
9179
9180         if (xmlXPathIsInf(le) == 1) {
9181             l = m;
9182             if (i < 1)
9183                 i = 1;
9184         }
9185         else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9186             l = 0;
9187         else {
9188             l = (int) le;
9189             if (((double)l)+0.5 <= le) l++;
9190         }
9191
9192         /* Now we normalize inidices */
9193         i -= 1;
9194         l += i;
9195         if (i < 0)
9196             i = 0;
9197         if (l > m)
9198             l = m;
9199
9200         /* number of chars to copy */
9201         l -= i;
9202
9203         ret = xmlUTF8Strsub(str->stringval, i, l);
9204     }
9205     else {
9206         ret = NULL;
9207     }
9208     if (ret == NULL)
9209         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9210     else {
9211         valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9212         xmlFree(ret);
9213     }
9214     xmlXPathReleaseObject(ctxt->context, str);
9215 }
9216
9217 /**
9218  * xmlXPathSubstringBeforeFunction:
9219  * @ctxt:  the XPath Parser context
9220  * @nargs:  the number of arguments
9221  *
9222  * Implement the substring-before() XPath function
9223  *    string substring-before(string, string)
9224  * The substring-before function returns the substring of the first
9225  * argument string that precedes the first occurrence of the second
9226  * argument string in the first argument string, or the empty string
9227  * if the first argument string does not contain the second argument
9228  * string. For example, substring-before("1999/04/01","/") returns 1999.
9229  */
9230 void
9231 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9232   xmlXPathObjectPtr str;
9233   xmlXPathObjectPtr find;
9234   xmlBufPtr target;
9235   const xmlChar *point;
9236   int offset;
9237
9238   CHECK_ARITY(2);
9239   CAST_TO_STRING;
9240   find = valuePop(ctxt);
9241   CAST_TO_STRING;
9242   str = valuePop(ctxt);
9243
9244   target = xmlBufCreate();
9245   if (target) {
9246     point = xmlStrstr(str->stringval, find->stringval);
9247     if (point) {
9248       offset = (int)(point - str->stringval);
9249       xmlBufAdd(target, str->stringval, offset);
9250     }
9251     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9252         xmlBufContent(target)));
9253     xmlBufFree(target);
9254   }
9255   xmlXPathReleaseObject(ctxt->context, str);
9256   xmlXPathReleaseObject(ctxt->context, find);
9257 }
9258
9259 /**
9260  * xmlXPathSubstringAfterFunction:
9261  * @ctxt:  the XPath Parser context
9262  * @nargs:  the number of arguments
9263  *
9264  * Implement the substring-after() XPath function
9265  *    string substring-after(string, string)
9266  * The substring-after function returns the substring of the first
9267  * argument string that follows the first occurrence of the second
9268  * argument string in the first argument string, or the empty stringi
9269  * if the first argument string does not contain the second argument
9270  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9271  * and substring-after("1999/04/01","19") returns 99/04/01.
9272  */
9273 void
9274 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9275   xmlXPathObjectPtr str;
9276   xmlXPathObjectPtr find;
9277   xmlBufPtr target;
9278   const xmlChar *point;
9279   int offset;
9280
9281   CHECK_ARITY(2);
9282   CAST_TO_STRING;
9283   find = valuePop(ctxt);
9284   CAST_TO_STRING;
9285   str = valuePop(ctxt);
9286
9287   target = xmlBufCreate();
9288   if (target) {
9289     point = xmlStrstr(str->stringval, find->stringval);
9290     if (point) {
9291       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9292       xmlBufAdd(target, &str->stringval[offset],
9293                    xmlStrlen(str->stringval) - offset);
9294     }
9295     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9296         xmlBufContent(target)));
9297     xmlBufFree(target);
9298   }
9299   xmlXPathReleaseObject(ctxt->context, str);
9300   xmlXPathReleaseObject(ctxt->context, find);
9301 }
9302
9303 /**
9304  * xmlXPathNormalizeFunction:
9305  * @ctxt:  the XPath Parser context
9306  * @nargs:  the number of arguments
9307  *
9308  * Implement the normalize-space() XPath function
9309  *    string normalize-space(string?)
9310  * The normalize-space function returns the argument string with white
9311  * space normalized by stripping leading and trailing whitespace
9312  * and replacing sequences of whitespace characters by a single
9313  * space. Whitespace characters are the same allowed by the S production
9314  * in XML. If the argument is omitted, it defaults to the context
9315  * node converted to a string, in other words the value of the context node.
9316  */
9317 void
9318 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9319   xmlXPathObjectPtr obj = NULL;
9320   xmlChar *source = NULL;
9321   xmlBufPtr target;
9322   xmlChar blank;
9323
9324   if (ctxt == NULL) return;
9325   if (nargs == 0) {
9326     /* Use current context node */
9327       valuePush(ctxt,
9328           xmlXPathCacheWrapString(ctxt->context,
9329             xmlXPathCastNodeToString(ctxt->context->node)));
9330     nargs = 1;
9331   }
9332
9333   CHECK_ARITY(1);
9334   CAST_TO_STRING;
9335   CHECK_TYPE(XPATH_STRING);
9336   obj = valuePop(ctxt);
9337   source = obj->stringval;
9338
9339   target = xmlBufCreate();
9340   if (target && source) {
9341
9342     /* Skip leading whitespaces */
9343     while (IS_BLANK_CH(*source))
9344       source++;
9345
9346     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9347     blank = 0;
9348     while (*source) {
9349       if (IS_BLANK_CH(*source)) {
9350         blank = 0x20;
9351       } else {
9352         if (blank) {
9353           xmlBufAdd(target, &blank, 1);
9354           blank = 0;
9355         }
9356         xmlBufAdd(target, source, 1);
9357       }
9358       source++;
9359     }
9360     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9361         xmlBufContent(target)));
9362     xmlBufFree(target);
9363   }
9364   xmlXPathReleaseObject(ctxt->context, obj);
9365 }
9366
9367 /**
9368  * xmlXPathTranslateFunction:
9369  * @ctxt:  the XPath Parser context
9370  * @nargs:  the number of arguments
9371  *
9372  * Implement the translate() XPath function
9373  *    string translate(string, string, string)
9374  * The translate function returns the first argument string with
9375  * occurrences of characters in the second argument string replaced
9376  * by the character at the corresponding position in the third argument
9377  * string. For example, translate("bar","abc","ABC") returns the string
9378  * BAr. If there is a character in the second argument string with no
9379  * character at a corresponding position in the third argument string
9380  * (because the second argument string is longer than the third argument
9381  * string), then occurrences of that character in the first argument
9382  * string are removed. For example, translate("--aaa--","abc-","ABC")
9383  * returns "AAA". If a character occurs more than once in second
9384  * argument string, then the first occurrence determines the replacement
9385  * character. If the third argument string is longer than the second
9386  * argument string, then excess characters are ignored.
9387  */
9388 void
9389 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9390     xmlXPathObjectPtr str;
9391     xmlXPathObjectPtr from;
9392     xmlXPathObjectPtr to;
9393     xmlBufPtr target;
9394     int offset, max;
9395     xmlChar ch;
9396     const xmlChar *point;
9397     xmlChar *cptr;
9398
9399     CHECK_ARITY(3);
9400
9401     CAST_TO_STRING;
9402     to = valuePop(ctxt);
9403     CAST_TO_STRING;
9404     from = valuePop(ctxt);
9405     CAST_TO_STRING;
9406     str = valuePop(ctxt);
9407
9408     target = xmlBufCreate();
9409     if (target) {
9410         max = xmlUTF8Strlen(to->stringval);
9411         for (cptr = str->stringval; (ch=*cptr); ) {
9412             offset = xmlUTF8Strloc(from->stringval, cptr);
9413             if (offset >= 0) {
9414                 if (offset < max) {
9415                     point = xmlUTF8Strpos(to->stringval, offset);
9416                     if (point)
9417                         xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9418                 }
9419             } else
9420                 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9421
9422             /* Step to next character in input */
9423             cptr++;
9424             if ( ch & 0x80 ) {
9425                 /* if not simple ascii, verify proper format */
9426                 if ( (ch & 0xc0) != 0xc0 ) {
9427                     xmlGenericError(xmlGenericErrorContext,
9428                         "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9429                     /* not asserting an XPath error is probably better */
9430                     break;
9431                 }
9432                 /* then skip over remaining bytes for this char */
9433                 while ( (ch <<= 1) & 0x80 )
9434                     if ( (*cptr++ & 0xc0) != 0x80 ) {
9435                         xmlGenericError(xmlGenericErrorContext,
9436                             "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9437                         /* not asserting an XPath error is probably better */
9438                         break;
9439                     }
9440                 if (ch & 0x80) /* must have had error encountered */
9441                     break;
9442             }
9443         }
9444     }
9445     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9446         xmlBufContent(target)));
9447     xmlBufFree(target);
9448     xmlXPathReleaseObject(ctxt->context, str);
9449     xmlXPathReleaseObject(ctxt->context, from);
9450     xmlXPathReleaseObject(ctxt->context, to);
9451 }
9452
9453 /**
9454  * xmlXPathBooleanFunction:
9455  * @ctxt:  the XPath Parser context
9456  * @nargs:  the number of arguments
9457  *
9458  * Implement the boolean() XPath function
9459  *    boolean boolean(object)
9460  * The boolean function converts its argument to a boolean as follows:
9461  *    - a number is true if and only if it is neither positive or
9462  *      negative zero nor NaN
9463  *    - a node-set is true if and only if it is non-empty
9464  *    - a string is true if and only if its length is non-zero
9465  */
9466 void
9467 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9468     xmlXPathObjectPtr cur;
9469
9470     CHECK_ARITY(1);
9471     cur = valuePop(ctxt);
9472     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9473     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9474     valuePush(ctxt, cur);
9475 }
9476
9477 /**
9478  * xmlXPathNotFunction:
9479  * @ctxt:  the XPath Parser context
9480  * @nargs:  the number of arguments
9481  *
9482  * Implement the not() XPath function
9483  *    boolean not(boolean)
9484  * The not function returns true if its argument is false,
9485  * and false otherwise.
9486  */
9487 void
9488 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9489     CHECK_ARITY(1);
9490     CAST_TO_BOOLEAN;
9491     CHECK_TYPE(XPATH_BOOLEAN);
9492     ctxt->value->boolval = ! ctxt->value->boolval;
9493 }
9494
9495 /**
9496  * xmlXPathTrueFunction:
9497  * @ctxt:  the XPath Parser context
9498  * @nargs:  the number of arguments
9499  *
9500  * Implement the true() XPath function
9501  *    boolean true()
9502  */
9503 void
9504 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9505     CHECK_ARITY(0);
9506     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9507 }
9508
9509 /**
9510  * xmlXPathFalseFunction:
9511  * @ctxt:  the XPath Parser context
9512  * @nargs:  the number of arguments
9513  *
9514  * Implement the false() XPath function
9515  *    boolean false()
9516  */
9517 void
9518 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9519     CHECK_ARITY(0);
9520     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9521 }
9522
9523 /**
9524  * xmlXPathLangFunction:
9525  * @ctxt:  the XPath Parser context
9526  * @nargs:  the number of arguments
9527  *
9528  * Implement the lang() XPath function
9529  *    boolean lang(string)
9530  * The lang function returns true or false depending on whether the
9531  * language of the context node as specified by xml:lang attributes
9532  * is the same as or is a sublanguage of the language specified by
9533  * the argument string. The language of the context node is determined
9534  * by the value of the xml:lang attribute on the context node, or, if
9535  * the context node has no xml:lang attribute, by the value of the
9536  * xml:lang attribute on the nearest ancestor of the context node that
9537  * has an xml:lang attribute. If there is no such attribute, then lang
9538  * returns false. If there is such an attribute, then lang returns
9539  * true if the attribute value is equal to the argument ignoring case,
9540  * or if there is some suffix starting with - such that the attribute
9541  * value is equal to the argument ignoring that suffix of the attribute
9542  * value and ignoring case.
9543  */
9544 void
9545 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9546     xmlXPathObjectPtr val = NULL;
9547     const xmlChar *theLang = NULL;
9548     const xmlChar *lang;
9549     int ret = 0;
9550     int i;
9551
9552     CHECK_ARITY(1);
9553     CAST_TO_STRING;
9554     CHECK_TYPE(XPATH_STRING);
9555     val = valuePop(ctxt);
9556     lang = val->stringval;
9557     theLang = xmlNodeGetLang(ctxt->context->node);
9558     if ((theLang != NULL) && (lang != NULL)) {
9559         for (i = 0;lang[i] != 0;i++)
9560             if (toupper(lang[i]) != toupper(theLang[i]))
9561                 goto not_equal;
9562         if ((theLang[i] == 0) || (theLang[i] == '-'))
9563             ret = 1;
9564     }
9565 not_equal:
9566     if (theLang != NULL)
9567         xmlFree((void *)theLang);
9568
9569     xmlXPathReleaseObject(ctxt->context, val);
9570     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9571 }
9572
9573 /**
9574  * xmlXPathNumberFunction:
9575  * @ctxt:  the XPath Parser context
9576  * @nargs:  the number of arguments
9577  *
9578  * Implement the number() XPath function
9579  *    number number(object?)
9580  */
9581 void
9582 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9583     xmlXPathObjectPtr cur;
9584     double res;
9585
9586     if (ctxt == NULL) return;
9587     if (nargs == 0) {
9588         if (ctxt->context->node == NULL) {
9589             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9590         } else {
9591             xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9592
9593             res = xmlXPathStringEvalNumber(content);
9594             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9595             xmlFree(content);
9596         }
9597         return;
9598     }
9599
9600     CHECK_ARITY(1);
9601     cur = valuePop(ctxt);
9602     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9603 }
9604
9605 /**
9606  * xmlXPathSumFunction:
9607  * @ctxt:  the XPath Parser context
9608  * @nargs:  the number of arguments
9609  *
9610  * Implement the sum() XPath function
9611  *    number sum(node-set)
9612  * The sum function returns the sum of the values of the nodes in
9613  * the argument node-set.
9614  */
9615 void
9616 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9617     xmlXPathObjectPtr cur;
9618     int i;
9619     double res = 0.0;
9620
9621     CHECK_ARITY(1);
9622     if ((ctxt->value == NULL) ||
9623         ((ctxt->value->type != XPATH_NODESET) &&
9624          (ctxt->value->type != XPATH_XSLT_TREE)))
9625         XP_ERROR(XPATH_INVALID_TYPE);
9626     cur = valuePop(ctxt);
9627
9628     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9629         for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9630             res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9631         }
9632     }
9633     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9634     xmlXPathReleaseObject(ctxt->context, cur);
9635 }
9636
9637 /*
9638  * To assure working code on multiple platforms, we want to only depend
9639  * upon the characteristic truncation of converting a floating point value
9640  * to an integer.  Unfortunately, because of the different storage sizes
9641  * of our internal floating point value (double) and integer (int), we
9642  * can't directly convert (see bug 301162).  This macro is a messy
9643  * 'workaround'
9644  */
9645 #define XTRUNC(f, v)            \
9646     f = fmod((v), INT_MAX);     \
9647     f = (v) - (f) + (double)((int)(f));
9648
9649 /**
9650  * xmlXPathFloorFunction:
9651  * @ctxt:  the XPath Parser context
9652  * @nargs:  the number of arguments
9653  *
9654  * Implement the floor() XPath function
9655  *    number floor(number)
9656  * The floor function returns the largest (closest to positive infinity)
9657  * number that is not greater than the argument and that is an integer.
9658  */
9659 void
9660 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9661     double f;
9662
9663     CHECK_ARITY(1);
9664     CAST_TO_NUMBER;
9665     CHECK_TYPE(XPATH_NUMBER);
9666
9667     XTRUNC(f, ctxt->value->floatval);
9668     if (f != ctxt->value->floatval) {
9669         if (ctxt->value->floatval > 0)
9670             ctxt->value->floatval = f;
9671         else
9672             ctxt->value->floatval = f - 1;
9673     }
9674 }
9675
9676 /**
9677  * xmlXPathCeilingFunction:
9678  * @ctxt:  the XPath Parser context
9679  * @nargs:  the number of arguments
9680  *
9681  * Implement the ceiling() XPath function
9682  *    number ceiling(number)
9683  * The ceiling function returns the smallest (closest to negative infinity)
9684  * number that is not less than the argument and that is an integer.
9685  */
9686 void
9687 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9688     double f;
9689
9690     CHECK_ARITY(1);
9691     CAST_TO_NUMBER;
9692     CHECK_TYPE(XPATH_NUMBER);
9693
9694 #if 0
9695     ctxt->value->floatval = ceil(ctxt->value->floatval);
9696 #else
9697     XTRUNC(f, ctxt->value->floatval);
9698     if (f != ctxt->value->floatval) {
9699         if (ctxt->value->floatval > 0)
9700             ctxt->value->floatval = f + 1;
9701         else {
9702             if (ctxt->value->floatval < 0 && f == 0)
9703                 ctxt->value->floatval = xmlXPathNZERO;
9704             else
9705                 ctxt->value->floatval = f;
9706         }
9707
9708     }
9709 #endif
9710 }
9711
9712 /**
9713  * xmlXPathRoundFunction:
9714  * @ctxt:  the XPath Parser context
9715  * @nargs:  the number of arguments
9716  *
9717  * Implement the round() XPath function
9718  *    number round(number)
9719  * The round function returns the number that is closest to the
9720  * argument and that is an integer. If there are two such numbers,
9721  * then the one that is even is returned.
9722  */
9723 void
9724 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9725     double f;
9726
9727     CHECK_ARITY(1);
9728     CAST_TO_NUMBER;
9729     CHECK_TYPE(XPATH_NUMBER);
9730
9731     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9732         (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9733         (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9734         (ctxt->value->floatval == 0.0))
9735         return;
9736
9737     XTRUNC(f, ctxt->value->floatval);
9738     if (ctxt->value->floatval < 0) {
9739         if (ctxt->value->floatval < f - 0.5)
9740             ctxt->value->floatval = f - 1;
9741         else
9742             ctxt->value->floatval = f;
9743         if (ctxt->value->floatval == 0)
9744             ctxt->value->floatval = xmlXPathNZERO;
9745     } else {
9746         if (ctxt->value->floatval < f + 0.5)
9747             ctxt->value->floatval = f;
9748         else
9749             ctxt->value->floatval = f + 1;
9750     }
9751 }
9752
9753 /************************************************************************
9754  *                                                                      *
9755  *                      The Parser                                      *
9756  *                                                                      *
9757  ************************************************************************/
9758
9759 /*
9760  * a few forward declarations since we use a recursive call based
9761  * implementation.
9762  */
9763 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9764 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9765 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9766 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9767 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9768                                           int qualified);
9769
9770 /**
9771  * xmlXPathCurrentChar:
9772  * @ctxt:  the XPath parser context
9773  * @cur:  pointer to the beginning of the char
9774  * @len:  pointer to the length of the char read
9775  *
9776  * The current char value, if using UTF-8 this may actually span multiple
9777  * bytes in the input buffer.
9778  *
9779  * Returns the current char value and its length
9780  */
9781
9782 static int
9783 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9784     unsigned char c;
9785     unsigned int val;
9786     const xmlChar *cur;
9787
9788     if (ctxt == NULL)
9789         return(0);
9790     cur = ctxt->cur;
9791
9792     /*
9793      * We are supposed to handle UTF8, check it's valid
9794      * From rfc2044: encoding of the Unicode values on UTF-8:
9795      *
9796      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9797      * 0000 0000-0000 007F   0xxxxxxx
9798      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9799      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9800      *
9801      * Check for the 0x110000 limit too
9802      */
9803     c = *cur;
9804     if (c & 0x80) {
9805         if ((cur[1] & 0xc0) != 0x80)
9806             goto encoding_error;
9807         if ((c & 0xe0) == 0xe0) {
9808
9809             if ((cur[2] & 0xc0) != 0x80)
9810                 goto encoding_error;
9811             if ((c & 0xf0) == 0xf0) {
9812                 if (((c & 0xf8) != 0xf0) ||
9813                     ((cur[3] & 0xc0) != 0x80))
9814                     goto encoding_error;
9815                 /* 4-byte code */
9816                 *len = 4;
9817                 val = (cur[0] & 0x7) << 18;
9818                 val |= (cur[1] & 0x3f) << 12;
9819                 val |= (cur[2] & 0x3f) << 6;
9820                 val |= cur[3] & 0x3f;
9821             } else {
9822               /* 3-byte code */
9823                 *len = 3;
9824                 val = (cur[0] & 0xf) << 12;
9825                 val |= (cur[1] & 0x3f) << 6;
9826                 val |= cur[2] & 0x3f;
9827             }
9828         } else {
9829           /* 2-byte code */
9830             *len = 2;
9831             val = (cur[0] & 0x1f) << 6;
9832             val |= cur[1] & 0x3f;
9833         }
9834         if (!IS_CHAR(val)) {
9835             XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9836         }
9837         return(val);
9838     } else {
9839         /* 1-byte code */
9840         *len = 1;
9841         return((int) *cur);
9842     }
9843 encoding_error:
9844     /*
9845      * If we detect an UTF8 error that probably means that the
9846      * input encoding didn't get properly advertised in the
9847      * declaration header. Report the error and switch the encoding
9848      * to ISO-Latin-1 (if you don't like this policy, just declare the
9849      * encoding !)
9850      */
9851     *len = 0;
9852     XP_ERROR0(XPATH_ENCODING_ERROR);
9853 }
9854
9855 /**
9856  * xmlXPathParseNCName:
9857  * @ctxt:  the XPath Parser context
9858  *
9859  * parse an XML namespace non qualified name.
9860  *
9861  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9862  *
9863  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9864  *                       CombiningChar | Extender
9865  *
9866  * Returns the namespace name or NULL
9867  */
9868
9869 xmlChar *
9870 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9871     const xmlChar *in;
9872     xmlChar *ret;
9873     int count = 0;
9874
9875     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9876     /*
9877      * Accelerator for simple ASCII names
9878      */
9879     in = ctxt->cur;
9880     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9881         ((*in >= 0x41) && (*in <= 0x5A)) ||
9882         (*in == '_')) {
9883         in++;
9884         while (((*in >= 0x61) && (*in <= 0x7A)) ||
9885                ((*in >= 0x41) && (*in <= 0x5A)) ||
9886                ((*in >= 0x30) && (*in <= 0x39)) ||
9887                (*in == '_') || (*in == '.') ||
9888                (*in == '-'))
9889             in++;
9890         if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9891             (*in == '[') || (*in == ']') || (*in == ':') ||
9892             (*in == '@') || (*in == '*')) {
9893             count = in - ctxt->cur;
9894             if (count == 0)
9895                 return(NULL);
9896             ret = xmlStrndup(ctxt->cur, count);
9897             ctxt->cur = in;
9898             return(ret);
9899         }
9900     }
9901     return(xmlXPathParseNameComplex(ctxt, 0));
9902 }
9903
9904
9905 /**
9906  * xmlXPathParseQName:
9907  * @ctxt:  the XPath Parser context
9908  * @prefix:  a xmlChar **
9909  *
9910  * parse an XML qualified name
9911  *
9912  * [NS 5] QName ::= (Prefix ':')? LocalPart
9913  *
9914  * [NS 6] Prefix ::= NCName
9915  *
9916  * [NS 7] LocalPart ::= NCName
9917  *
9918  * Returns the function returns the local part, and prefix is updated
9919  *   to get the Prefix if any.
9920  */
9921
9922 static xmlChar *
9923 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9924     xmlChar *ret = NULL;
9925
9926     *prefix = NULL;
9927     ret = xmlXPathParseNCName(ctxt);
9928     if (ret && CUR == ':') {
9929         *prefix = ret;
9930         NEXT;
9931         ret = xmlXPathParseNCName(ctxt);
9932     }
9933     return(ret);
9934 }
9935
9936 /**
9937  * xmlXPathParseName:
9938  * @ctxt:  the XPath Parser context
9939  *
9940  * parse an XML name
9941  *
9942  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9943  *                  CombiningChar | Extender
9944  *
9945  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9946  *
9947  * Returns the namespace name or NULL
9948  */
9949
9950 xmlChar *
9951 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9952     const xmlChar *in;
9953     xmlChar *ret;
9954     size_t count = 0;
9955
9956     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9957     /*
9958      * Accelerator for simple ASCII names
9959      */
9960     in = ctxt->cur;
9961     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9962         ((*in >= 0x41) && (*in <= 0x5A)) ||
9963         (*in == '_') || (*in == ':')) {
9964         in++;
9965         while (((*in >= 0x61) && (*in <= 0x7A)) ||
9966                ((*in >= 0x41) && (*in <= 0x5A)) ||
9967                ((*in >= 0x30) && (*in <= 0x39)) ||
9968                (*in == '_') || (*in == '-') ||
9969                (*in == ':') || (*in == '.'))
9970             in++;
9971         if ((*in > 0) && (*in < 0x80)) {
9972             count = in - ctxt->cur;
9973             if (count > XML_MAX_NAME_LENGTH) {
9974                 ctxt->cur = in;
9975                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9976             }
9977             ret = xmlStrndup(ctxt->cur, count);
9978             ctxt->cur = in;
9979             return(ret);
9980         }
9981     }
9982     return(xmlXPathParseNameComplex(ctxt, 1));
9983 }
9984
9985 static xmlChar *
9986 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9987     xmlChar buf[XML_MAX_NAMELEN + 5];
9988     int len = 0, l;
9989     int c;
9990
9991     /*
9992      * Handler for more complex cases
9993      */
9994     c = CUR_CHAR(l);
9995     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9996         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9997         (c == '*') || /* accelerators */
9998         (!IS_LETTER(c) && (c != '_') &&
9999          ((!qualified) || (c != ':')))) {
10000         return(NULL);
10001     }
10002
10003     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10004            ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10005             (c == '.') || (c == '-') ||
10006             (c == '_') || ((qualified) && (c == ':')) ||
10007             (IS_COMBINING(c)) ||
10008             (IS_EXTENDER(c)))) {
10009         COPY_BUF(l,buf,len,c);
10010         NEXTL(l);
10011         c = CUR_CHAR(l);
10012         if (len >= XML_MAX_NAMELEN) {
10013             /*
10014              * Okay someone managed to make a huge name, so he's ready to pay
10015              * for the processing speed.
10016              */
10017             xmlChar *buffer;
10018             int max = len * 2;
10019
10020             if (len > XML_MAX_NAME_LENGTH) {
10021                 XP_ERRORNULL(XPATH_EXPR_ERROR);
10022             }
10023             buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10024             if (buffer == NULL) {
10025                 XP_ERRORNULL(XPATH_MEMORY_ERROR);
10026             }
10027             memcpy(buffer, buf, len);
10028             while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10029                    (c == '.') || (c == '-') ||
10030                    (c == '_') || ((qualified) && (c == ':')) ||
10031                    (IS_COMBINING(c)) ||
10032                    (IS_EXTENDER(c))) {
10033                 if (len + 10 > max) {
10034                     if (max > XML_MAX_NAME_LENGTH) {
10035                         XP_ERRORNULL(XPATH_EXPR_ERROR);
10036                     }
10037                     max *= 2;
10038                     buffer = (xmlChar *) xmlRealloc(buffer,
10039                                                     max * sizeof(xmlChar));
10040                     if (buffer == NULL) {
10041                         XP_ERRORNULL(XPATH_MEMORY_ERROR);
10042                     }
10043                 }
10044                 COPY_BUF(l,buffer,len,c);
10045                 NEXTL(l);
10046                 c = CUR_CHAR(l);
10047             }
10048             buffer[len] = 0;
10049             return(buffer);
10050         }
10051     }
10052     if (len == 0)
10053         return(NULL);
10054     return(xmlStrndup(buf, len));
10055 }
10056
10057 #define MAX_FRAC 20
10058
10059 /*
10060  * These are used as divisors for the fractional part of a number.
10061  * Since the table includes 1.0 (representing '0' fractional digits),
10062  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
10063  */
10064 static double my_pow10[MAX_FRAC+1] = {
10065     1.0, 10.0, 100.0, 1000.0, 10000.0,
10066     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
10067     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
10068     100000000000000.0,
10069     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
10070     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
10071 };
10072
10073 /**
10074  * xmlXPathStringEvalNumber:
10075  * @str:  A string to scan
10076  *
10077  *  [30a]  Float  ::= Number ('e' Digits?)?
10078  *
10079  *  [30]   Number ::=   Digits ('.' Digits?)?
10080  *                    | '.' Digits
10081  *  [31]   Digits ::=   [0-9]+
10082  *
10083  * Compile a Number in the string
10084  * In complement of the Number expression, this function also handles
10085  * negative values : '-' Number.
10086  *
10087  * Returns the double value.
10088  */
10089 double
10090 xmlXPathStringEvalNumber(const xmlChar *str) {
10091     const xmlChar *cur = str;
10092     double ret;
10093     int ok = 0;
10094     int isneg = 0;
10095     int exponent = 0;
10096     int is_exponent_negative = 0;
10097 #ifdef __GNUC__
10098     unsigned long tmp = 0;
10099     double temp;
10100 #endif
10101     if (cur == NULL) return(0);
10102     while (IS_BLANK_CH(*cur)) cur++;
10103     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10104         return(xmlXPathNAN);
10105     }
10106     if (*cur == '-') {
10107         isneg = 1;
10108         cur++;
10109     }
10110
10111 #ifdef __GNUC__
10112     /*
10113      * tmp/temp is a workaround against a gcc compiler bug
10114      * http://veillard.com/gcc.bug
10115      */
10116     ret = 0;
10117     while ((*cur >= '0') && (*cur <= '9')) {
10118         ret = ret * 10;
10119         tmp = (*cur - '0');
10120         ok = 1;
10121         cur++;
10122         temp = (double) tmp;
10123         ret = ret + temp;
10124     }
10125 #else
10126     ret = 0;
10127     while ((*cur >= '0') && (*cur <= '9')) {
10128         ret = ret * 10 + (*cur - '0');
10129         ok = 1;
10130         cur++;
10131     }
10132 #endif
10133
10134     if (*cur == '.') {
10135         int v, frac = 0;
10136         double fraction = 0;
10137
10138         cur++;
10139         if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10140             return(xmlXPathNAN);
10141         }
10142         while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10143             v = (*cur - '0');
10144             fraction = fraction * 10 + v;
10145             frac = frac + 1;
10146             cur++;
10147         }
10148         fraction /= my_pow10[frac];
10149         ret = ret + fraction;
10150         while ((*cur >= '0') && (*cur <= '9'))
10151             cur++;
10152     }
10153     if ((*cur == 'e') || (*cur == 'E')) {
10154       cur++;
10155       if (*cur == '-') {
10156         is_exponent_negative = 1;
10157         cur++;
10158       } else if (*cur == '+') {
10159         cur++;
10160       }
10161       while ((*cur >= '0') && (*cur <= '9')) {
10162         exponent = exponent * 10 + (*cur - '0');
10163         cur++;
10164       }
10165     }
10166     while (IS_BLANK_CH(*cur)) cur++;
10167     if (*cur != 0) return(xmlXPathNAN);
10168     if (isneg) ret = -ret;
10169     if (is_exponent_negative) exponent = -exponent;
10170     ret *= pow(10.0, (double)exponent);
10171     return(ret);
10172 }
10173
10174 /**
10175  * xmlXPathCompNumber:
10176  * @ctxt:  the XPath Parser context
10177  *
10178  *  [30]   Number ::=   Digits ('.' Digits?)?
10179  *                    | '.' Digits
10180  *  [31]   Digits ::=   [0-9]+
10181  *
10182  * Compile a Number, then push it on the stack
10183  *
10184  */
10185 static void
10186 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10187 {
10188     double ret = 0.0;
10189     int ok = 0;
10190     int exponent = 0;
10191     int is_exponent_negative = 0;
10192 #ifdef __GNUC__
10193     unsigned long tmp = 0;
10194     double temp;
10195 #endif
10196
10197     CHECK_ERROR;
10198     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10199         XP_ERROR(XPATH_NUMBER_ERROR);
10200     }
10201 #ifdef __GNUC__
10202     /*
10203      * tmp/temp is a workaround against a gcc compiler bug
10204      * http://veillard.com/gcc.bug
10205      */
10206     ret = 0;
10207     while ((CUR >= '0') && (CUR <= '9')) {
10208         ret = ret * 10;
10209         tmp = (CUR - '0');
10210         ok = 1;
10211         NEXT;
10212         temp = (double) tmp;
10213         ret = ret + temp;
10214     }
10215 #else
10216     ret = 0;
10217     while ((CUR >= '0') && (CUR <= '9')) {
10218         ret = ret * 10 + (CUR - '0');
10219         ok = 1;
10220         NEXT;
10221     }
10222 #endif
10223     if (CUR == '.') {
10224         int v, frac = 0;
10225         double fraction = 0;
10226
10227         NEXT;
10228         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10229             XP_ERROR(XPATH_NUMBER_ERROR);
10230         }
10231         while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10232             v = (CUR - '0');
10233             fraction = fraction * 10 + v;
10234             frac = frac + 1;
10235             NEXT;
10236         }
10237         fraction /= my_pow10[frac];
10238         ret = ret + fraction;
10239         while ((CUR >= '0') && (CUR <= '9'))
10240             NEXT;
10241     }
10242     if ((CUR == 'e') || (CUR == 'E')) {
10243         NEXT;
10244         if (CUR == '-') {
10245             is_exponent_negative = 1;
10246             NEXT;
10247         } else if (CUR == '+') {
10248             NEXT;
10249         }
10250         while ((CUR >= '0') && (CUR <= '9')) {
10251             exponent = exponent * 10 + (CUR - '0');
10252             NEXT;
10253         }
10254         if (is_exponent_negative)
10255             exponent = -exponent;
10256         ret *= pow(10.0, (double) exponent);
10257     }
10258     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10259                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10260 }
10261
10262 /**
10263  * xmlXPathParseLiteral:
10264  * @ctxt:  the XPath Parser context
10265  *
10266  * Parse a Literal
10267  *
10268  *  [29]   Literal ::=   '"' [^"]* '"'
10269  *                    | "'" [^']* "'"
10270  *
10271  * Returns the value found or NULL in case of error
10272  */
10273 static xmlChar *
10274 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10275     const xmlChar *q;
10276     xmlChar *ret = NULL;
10277
10278     if (CUR == '"') {
10279         NEXT;
10280         q = CUR_PTR;
10281         while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10282             NEXT;
10283         if (!IS_CHAR_CH(CUR)) {
10284             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10285         } else {
10286             ret = xmlStrndup(q, CUR_PTR - q);
10287             NEXT;
10288         }
10289     } else if (CUR == '\'') {
10290         NEXT;
10291         q = CUR_PTR;
10292         while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10293             NEXT;
10294         if (!IS_CHAR_CH(CUR)) {
10295             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10296         } else {
10297             ret = xmlStrndup(q, CUR_PTR - q);
10298             NEXT;
10299         }
10300     } else {
10301         XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10302     }
10303     return(ret);
10304 }
10305
10306 /**
10307  * xmlXPathCompLiteral:
10308  * @ctxt:  the XPath Parser context
10309  *
10310  * Parse a Literal and push it on the stack.
10311  *
10312  *  [29]   Literal ::=   '"' [^"]* '"'
10313  *                    | "'" [^']* "'"
10314  *
10315  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10316  */
10317 static void
10318 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10319     const xmlChar *q;
10320     xmlChar *ret = NULL;
10321
10322     if (CUR == '"') {
10323         NEXT;
10324         q = CUR_PTR;
10325         while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10326             NEXT;
10327         if (!IS_CHAR_CH(CUR)) {
10328             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10329         } else {
10330             ret = xmlStrndup(q, CUR_PTR - q);
10331             NEXT;
10332         }
10333     } else if (CUR == '\'') {
10334         NEXT;
10335         q = CUR_PTR;
10336         while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10337             NEXT;
10338         if (!IS_CHAR_CH(CUR)) {
10339             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10340         } else {
10341             ret = xmlStrndup(q, CUR_PTR - q);
10342             NEXT;
10343         }
10344     } else {
10345         XP_ERROR(XPATH_START_LITERAL_ERROR);
10346     }
10347     if (ret == NULL) return;
10348     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10349                    xmlXPathCacheNewString(ctxt->context, ret), NULL);
10350     xmlFree(ret);
10351 }
10352
10353 /**
10354  * xmlXPathCompVariableReference:
10355  * @ctxt:  the XPath Parser context
10356  *
10357  * Parse a VariableReference, evaluate it and push it on the stack.
10358  *
10359  * The variable bindings consist of a mapping from variable names
10360  * to variable values. The value of a variable is an object, which can be
10361  * of any of the types that are possible for the value of an expression,
10362  * and may also be of additional types not specified here.
10363  *
10364  * Early evaluation is possible since:
10365  * The variable bindings [...] used to evaluate a subexpression are
10366  * always the same as those used to evaluate the containing expression.
10367  *
10368  *  [36]   VariableReference ::=   '$' QName
10369  */
10370 static void
10371 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10372     xmlChar *name;
10373     xmlChar *prefix;
10374
10375     SKIP_BLANKS;
10376     if (CUR != '$') {
10377         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10378     }
10379     NEXT;
10380     name = xmlXPathParseQName(ctxt, &prefix);
10381     if (name == NULL) {
10382         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10383     }
10384     ctxt->comp->last = -1;
10385     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10386                    name, prefix);
10387     SKIP_BLANKS;
10388     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10389         XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10390     }
10391 }
10392
10393 /**
10394  * xmlXPathIsNodeType:
10395  * @name:  a name string
10396  *
10397  * Is the name given a NodeType one.
10398  *
10399  *  [38]   NodeType ::=   'comment'
10400  *                    | 'text'
10401  *                    | 'processing-instruction'
10402  *                    | 'node'
10403  *
10404  * Returns 1 if true 0 otherwise
10405  */
10406 int
10407 xmlXPathIsNodeType(const xmlChar *name) {
10408     if (name == NULL)
10409         return(0);
10410
10411     if (xmlStrEqual(name, BAD_CAST "node"))
10412         return(1);
10413     if (xmlStrEqual(name, BAD_CAST "text"))
10414         return(1);
10415     if (xmlStrEqual(name, BAD_CAST "comment"))
10416         return(1);
10417     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10418         return(1);
10419     return(0);
10420 }
10421
10422 /**
10423  * xmlXPathCompFunctionCall:
10424  * @ctxt:  the XPath Parser context
10425  *
10426  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10427  *  [17]   Argument ::=   Expr
10428  *
10429  * Compile a function call, the evaluation of all arguments are
10430  * pushed on the stack
10431  */
10432 static void
10433 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10434     xmlChar *name;
10435     xmlChar *prefix;
10436     int nbargs = 0;
10437     int sort = 1;
10438
10439     name = xmlXPathParseQName(ctxt, &prefix);
10440     if (name == NULL) {
10441         xmlFree(prefix);
10442         XP_ERROR(XPATH_EXPR_ERROR);
10443     }
10444     SKIP_BLANKS;
10445 #ifdef DEBUG_EXPR
10446     if (prefix == NULL)
10447         xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10448                         name);
10449     else
10450         xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10451                         prefix, name);
10452 #endif
10453
10454     if (CUR != '(') {
10455         XP_ERROR(XPATH_EXPR_ERROR);
10456     }
10457     NEXT;
10458     SKIP_BLANKS;
10459
10460     /*
10461     * Optimization for count(): we don't need the node-set to be sorted.
10462     */
10463     if ((prefix == NULL) && (name[0] == 'c') &&
10464         xmlStrEqual(name, BAD_CAST "count"))
10465     {
10466         sort = 0;
10467     }
10468     ctxt->comp->last = -1;
10469     if (CUR != ')') {
10470         while (CUR != 0) {
10471             int op1 = ctxt->comp->last;
10472             ctxt->comp->last = -1;
10473             xmlXPathCompileExpr(ctxt, sort);
10474             if (ctxt->error != XPATH_EXPRESSION_OK) {
10475                 xmlFree(name);
10476                 xmlFree(prefix);
10477                 return;
10478             }
10479             PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10480             nbargs++;
10481             if (CUR == ')') break;
10482             if (CUR != ',') {
10483                 XP_ERROR(XPATH_EXPR_ERROR);
10484             }
10485             NEXT;
10486             SKIP_BLANKS;
10487         }
10488     }
10489     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10490                    name, prefix);
10491     NEXT;
10492     SKIP_BLANKS;
10493 }
10494
10495 /**
10496  * xmlXPathCompPrimaryExpr:
10497  * @ctxt:  the XPath Parser context
10498  *
10499  *  [15]   PrimaryExpr ::=   VariableReference
10500  *                | '(' Expr ')'
10501  *                | Literal
10502  *                | Number
10503  *                | FunctionCall
10504  *
10505  * Compile a primary expression.
10506  */
10507 static void
10508 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10509     SKIP_BLANKS;
10510     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10511     else if (CUR == '(') {
10512         NEXT;
10513         SKIP_BLANKS;
10514         xmlXPathCompileExpr(ctxt, 1);
10515         CHECK_ERROR;
10516         if (CUR != ')') {
10517             XP_ERROR(XPATH_EXPR_ERROR);
10518         }
10519         NEXT;
10520         SKIP_BLANKS;
10521     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10522         xmlXPathCompNumber(ctxt);
10523     } else if ((CUR == '\'') || (CUR == '"')) {
10524         xmlXPathCompLiteral(ctxt);
10525     } else {
10526         xmlXPathCompFunctionCall(ctxt);
10527     }
10528     SKIP_BLANKS;
10529 }
10530
10531 /**
10532  * xmlXPathCompFilterExpr:
10533  * @ctxt:  the XPath Parser context
10534  *
10535  *  [20]   FilterExpr ::=   PrimaryExpr
10536  *               | FilterExpr Predicate
10537  *
10538  * Compile a filter expression.
10539  * Square brackets are used to filter expressions in the same way that
10540  * they are used in location paths. It is an error if the expression to
10541  * be filtered does not evaluate to a node-set. The context node list
10542  * used for evaluating the expression in square brackets is the node-set
10543  * to be filtered listed in document order.
10544  */
10545
10546 static void
10547 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10548     xmlXPathCompPrimaryExpr(ctxt);
10549     CHECK_ERROR;
10550     SKIP_BLANKS;
10551
10552     while (CUR == '[') {
10553         xmlXPathCompPredicate(ctxt, 1);
10554         SKIP_BLANKS;
10555     }
10556
10557
10558 }
10559
10560 /**
10561  * xmlXPathScanName:
10562  * @ctxt:  the XPath Parser context
10563  *
10564  * Trickery: parse an XML name but without consuming the input flow
10565  * Needed to avoid insanity in the parser state.
10566  *
10567  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10568  *                  CombiningChar | Extender
10569  *
10570  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10571  *
10572  * [6] Names ::= Name (S Name)*
10573  *
10574  * Returns the Name parsed or NULL
10575  */
10576
10577 static xmlChar *
10578 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10579     int len = 0, l;
10580     int c;
10581     const xmlChar *cur;
10582     xmlChar *ret;
10583
10584     cur = ctxt->cur;
10585
10586     c = CUR_CHAR(l);
10587     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10588         (!IS_LETTER(c) && (c != '_') &&
10589          (c != ':'))) {
10590         return(NULL);
10591     }
10592
10593     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10594            ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10595             (c == '.') || (c == '-') ||
10596             (c == '_') || (c == ':') ||
10597             (IS_COMBINING(c)) ||
10598             (IS_EXTENDER(c)))) {
10599         len += l;
10600         NEXTL(l);
10601         c = CUR_CHAR(l);
10602     }
10603     ret = xmlStrndup(cur, ctxt->cur - cur);
10604     ctxt->cur = cur;
10605     return(ret);
10606 }
10607
10608 /**
10609  * xmlXPathCompPathExpr:
10610  * @ctxt:  the XPath Parser context
10611  *
10612  *  [19]   PathExpr ::=   LocationPath
10613  *               | FilterExpr
10614  *               | FilterExpr '/' RelativeLocationPath
10615  *               | FilterExpr '//' RelativeLocationPath
10616  *
10617  * Compile a path expression.
10618  * The / operator and // operators combine an arbitrary expression
10619  * and a relative location path. It is an error if the expression
10620  * does not evaluate to a node-set.
10621  * The / operator does composition in the same way as when / is
10622  * used in a location path. As in location paths, // is short for
10623  * /descendant-or-self::node()/.
10624  */
10625
10626 static void
10627 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10628     int lc = 1;           /* Should we branch to LocationPath ?         */
10629     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10630
10631     SKIP_BLANKS;
10632     if ((CUR == '$') || (CUR == '(') ||
10633         (IS_ASCII_DIGIT(CUR)) ||
10634         (CUR == '\'') || (CUR == '"') ||
10635         (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10636         lc = 0;
10637     } else if (CUR == '*') {
10638         /* relative or absolute location path */
10639         lc = 1;
10640     } else if (CUR == '/') {
10641         /* relative or absolute location path */
10642         lc = 1;
10643     } else if (CUR == '@') {
10644         /* relative abbreviated attribute location path */
10645         lc = 1;
10646     } else if (CUR == '.') {
10647         /* relative abbreviated attribute location path */
10648         lc = 1;
10649     } else {
10650         /*
10651          * Problem is finding if we have a name here whether it's:
10652          *   - a nodetype
10653          *   - a function call in which case it's followed by '('
10654          *   - an axis in which case it's followed by ':'
10655          *   - a element name
10656          * We do an a priori analysis here rather than having to
10657          * maintain parsed token content through the recursive function
10658          * calls. This looks uglier but makes the code easier to
10659          * read/write/debug.
10660          */
10661         SKIP_BLANKS;
10662         name = xmlXPathScanName(ctxt);
10663         if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10664 #ifdef DEBUG_STEP
10665             xmlGenericError(xmlGenericErrorContext,
10666                     "PathExpr: Axis\n");
10667 #endif
10668             lc = 1;
10669             xmlFree(name);
10670         } else if (name != NULL) {
10671             int len =xmlStrlen(name);
10672
10673
10674             while (NXT(len) != 0) {
10675                 if (NXT(len) == '/') {
10676                     /* element name */
10677 #ifdef DEBUG_STEP
10678                     xmlGenericError(xmlGenericErrorContext,
10679                             "PathExpr: AbbrRelLocation\n");
10680 #endif
10681                     lc = 1;
10682                     break;
10683                 } else if (IS_BLANK_CH(NXT(len))) {
10684                     /* ignore blanks */
10685                     ;
10686                 } else if (NXT(len) == ':') {
10687 #ifdef DEBUG_STEP
10688                     xmlGenericError(xmlGenericErrorContext,
10689                             "PathExpr: AbbrRelLocation\n");
10690 #endif
10691                     lc = 1;
10692                     break;
10693                 } else if ((NXT(len) == '(')) {
10694                     /* Note Type or Function */
10695                     if (xmlXPathIsNodeType(name)) {
10696 #ifdef DEBUG_STEP
10697                         xmlGenericError(xmlGenericErrorContext,
10698                                 "PathExpr: Type search\n");
10699 #endif
10700                         lc = 1;
10701                     } else {
10702 #ifdef DEBUG_STEP
10703                         xmlGenericError(xmlGenericErrorContext,
10704                                 "PathExpr: function call\n");
10705 #endif
10706                         lc = 0;
10707                     }
10708                     break;
10709                 } else if ((NXT(len) == '[')) {
10710                     /* element name */
10711 #ifdef DEBUG_STEP
10712                     xmlGenericError(xmlGenericErrorContext,
10713                             "PathExpr: AbbrRelLocation\n");
10714 #endif
10715                     lc = 1;
10716                     break;
10717                 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10718                            (NXT(len) == '=')) {
10719                     lc = 1;
10720                     break;
10721                 } else {
10722                     lc = 1;
10723                     break;
10724                 }
10725                 len++;
10726             }
10727             if (NXT(len) == 0) {
10728 #ifdef DEBUG_STEP
10729                 xmlGenericError(xmlGenericErrorContext,
10730                         "PathExpr: AbbrRelLocation\n");
10731 #endif
10732                 /* element name */
10733                 lc = 1;
10734             }
10735             xmlFree(name);
10736         } else {
10737             /* make sure all cases are covered explicitly */
10738             XP_ERROR(XPATH_EXPR_ERROR);
10739         }
10740     }
10741
10742     if (lc) {
10743         if (CUR == '/') {
10744             PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10745         } else {
10746             PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10747         }
10748         xmlXPathCompLocationPath(ctxt);
10749     } else {
10750         xmlXPathCompFilterExpr(ctxt);
10751         CHECK_ERROR;
10752         if ((CUR == '/') && (NXT(1) == '/')) {
10753             SKIP(2);
10754             SKIP_BLANKS;
10755
10756             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10757                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10758             PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10759
10760             xmlXPathCompRelativeLocationPath(ctxt);
10761         } else if (CUR == '/') {
10762             xmlXPathCompRelativeLocationPath(ctxt);
10763         }
10764     }
10765     SKIP_BLANKS;
10766 }
10767
10768 /**
10769  * xmlXPathCompUnionExpr:
10770  * @ctxt:  the XPath Parser context
10771  *
10772  *  [18]   UnionExpr ::=   PathExpr
10773  *               | UnionExpr '|' PathExpr
10774  *
10775  * Compile an union expression.
10776  */
10777
10778 static void
10779 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10780     xmlXPathCompPathExpr(ctxt);
10781     CHECK_ERROR;
10782     SKIP_BLANKS;
10783     while (CUR == '|') {
10784         int op1 = ctxt->comp->last;
10785         PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10786
10787         NEXT;
10788         SKIP_BLANKS;
10789         xmlXPathCompPathExpr(ctxt);
10790
10791         PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10792
10793         SKIP_BLANKS;
10794     }
10795 }
10796
10797 /**
10798  * xmlXPathCompUnaryExpr:
10799  * @ctxt:  the XPath Parser context
10800  *
10801  *  [27]   UnaryExpr ::=   UnionExpr
10802  *                   | '-' UnaryExpr
10803  *
10804  * Compile an unary expression.
10805  */
10806
10807 static void
10808 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10809     int minus = 0;
10810     int found = 0;
10811
10812     SKIP_BLANKS;
10813     while (CUR == '-') {
10814         minus = 1 - minus;
10815         found = 1;
10816         NEXT;
10817         SKIP_BLANKS;
10818     }
10819
10820     xmlXPathCompUnionExpr(ctxt);
10821     CHECK_ERROR;
10822     if (found) {
10823         if (minus)
10824             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10825         else
10826             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10827     }
10828 }
10829
10830 /**
10831  * xmlXPathCompMultiplicativeExpr:
10832  * @ctxt:  the XPath Parser context
10833  *
10834  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10835  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10836  *                   | MultiplicativeExpr 'div' UnaryExpr
10837  *                   | MultiplicativeExpr 'mod' UnaryExpr
10838  *  [34]   MultiplyOperator ::=   '*'
10839  *
10840  * Compile an Additive expression.
10841  */
10842
10843 static void
10844 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10845     xmlXPathCompUnaryExpr(ctxt);
10846     CHECK_ERROR;
10847     SKIP_BLANKS;
10848     while ((CUR == '*') ||
10849            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10850            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10851         int op = -1;
10852         int op1 = ctxt->comp->last;
10853
10854         if (CUR == '*') {
10855             op = 0;
10856             NEXT;
10857         } else if (CUR == 'd') {
10858             op = 1;
10859             SKIP(3);
10860         } else if (CUR == 'm') {
10861             op = 2;
10862             SKIP(3);
10863         }
10864         SKIP_BLANKS;
10865         xmlXPathCompUnaryExpr(ctxt);
10866         CHECK_ERROR;
10867         PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10868         SKIP_BLANKS;
10869     }
10870 }
10871
10872 /**
10873  * xmlXPathCompAdditiveExpr:
10874  * @ctxt:  the XPath Parser context
10875  *
10876  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10877  *                   | AdditiveExpr '+' MultiplicativeExpr
10878  *                   | AdditiveExpr '-' MultiplicativeExpr
10879  *
10880  * Compile an Additive expression.
10881  */
10882
10883 static void
10884 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10885
10886     xmlXPathCompMultiplicativeExpr(ctxt);
10887     CHECK_ERROR;
10888     SKIP_BLANKS;
10889     while ((CUR == '+') || (CUR == '-')) {
10890         int plus;
10891         int op1 = ctxt->comp->last;
10892
10893         if (CUR == '+') plus = 1;
10894         else plus = 0;
10895         NEXT;
10896         SKIP_BLANKS;
10897         xmlXPathCompMultiplicativeExpr(ctxt);
10898         CHECK_ERROR;
10899         PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10900         SKIP_BLANKS;
10901     }
10902 }
10903
10904 /**
10905  * xmlXPathCompRelationalExpr:
10906  * @ctxt:  the XPath Parser context
10907  *
10908  *  [24]   RelationalExpr ::=   AdditiveExpr
10909  *                 | RelationalExpr '<' AdditiveExpr
10910  *                 | RelationalExpr '>' AdditiveExpr
10911  *                 | RelationalExpr '<=' AdditiveExpr
10912  *                 | RelationalExpr '>=' AdditiveExpr
10913  *
10914  *  A <= B > C is allowed ? Answer from James, yes with
10915  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10916  *  which is basically what got implemented.
10917  *
10918  * Compile a Relational expression, then push the result
10919  * on the stack
10920  */
10921
10922 static void
10923 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10924     xmlXPathCompAdditiveExpr(ctxt);
10925     CHECK_ERROR;
10926     SKIP_BLANKS;
10927     while ((CUR == '<') ||
10928            (CUR == '>') ||
10929            ((CUR == '<') && (NXT(1) == '=')) ||
10930            ((CUR == '>') && (NXT(1) == '='))) {
10931         int inf, strict;
10932         int op1 = ctxt->comp->last;
10933
10934         if (CUR == '<') inf = 1;
10935         else inf = 0;
10936         if (NXT(1) == '=') strict = 0;
10937         else strict = 1;
10938         NEXT;
10939         if (!strict) NEXT;
10940         SKIP_BLANKS;
10941         xmlXPathCompAdditiveExpr(ctxt);
10942         CHECK_ERROR;
10943         PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10944         SKIP_BLANKS;
10945     }
10946 }
10947
10948 /**
10949  * xmlXPathCompEqualityExpr:
10950  * @ctxt:  the XPath Parser context
10951  *
10952  *  [23]   EqualityExpr ::=   RelationalExpr
10953  *                 | EqualityExpr '=' RelationalExpr
10954  *                 | EqualityExpr '!=' RelationalExpr
10955  *
10956  *  A != B != C is allowed ? Answer from James, yes with
10957  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10958  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10959  *  which is basically what got implemented.
10960  *
10961  * Compile an Equality expression.
10962  *
10963  */
10964 static void
10965 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10966     xmlXPathCompRelationalExpr(ctxt);
10967     CHECK_ERROR;
10968     SKIP_BLANKS;
10969     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10970         int eq;
10971         int op1 = ctxt->comp->last;
10972
10973         if (CUR == '=') eq = 1;
10974         else eq = 0;
10975         NEXT;
10976         if (!eq) NEXT;
10977         SKIP_BLANKS;
10978         xmlXPathCompRelationalExpr(ctxt);
10979         CHECK_ERROR;
10980         PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10981         SKIP_BLANKS;
10982     }
10983 }
10984
10985 /**
10986  * xmlXPathCompAndExpr:
10987  * @ctxt:  the XPath Parser context
10988  *
10989  *  [22]   AndExpr ::=   EqualityExpr
10990  *                 | AndExpr 'and' EqualityExpr
10991  *
10992  * Compile an AND expression.
10993  *
10994  */
10995 static void
10996 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10997     xmlXPathCompEqualityExpr(ctxt);
10998     CHECK_ERROR;
10999     SKIP_BLANKS;
11000     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
11001         int op1 = ctxt->comp->last;
11002         SKIP(3);
11003         SKIP_BLANKS;
11004         xmlXPathCompEqualityExpr(ctxt);
11005         CHECK_ERROR;
11006         PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11007         SKIP_BLANKS;
11008     }
11009 }
11010
11011 /**
11012  * xmlXPathCompileExpr:
11013  * @ctxt:  the XPath Parser context
11014  *
11015  *  [14]   Expr ::=   OrExpr
11016  *  [21]   OrExpr ::=   AndExpr
11017  *                 | OrExpr 'or' AndExpr
11018  *
11019  * Parse and compile an expression
11020  */
11021 static void
11022 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11023     xmlXPathCompAndExpr(ctxt);
11024     CHECK_ERROR;
11025     SKIP_BLANKS;
11026     while ((CUR == 'o') && (NXT(1) == 'r')) {
11027         int op1 = ctxt->comp->last;
11028         SKIP(2);
11029         SKIP_BLANKS;
11030         xmlXPathCompAndExpr(ctxt);
11031         CHECK_ERROR;
11032         PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11033         SKIP_BLANKS;
11034     }
11035     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11036         /* more ops could be optimized too */
11037         /*
11038         * This is the main place to eliminate sorting for
11039         * operations which don't require a sorted node-set.
11040         * E.g. count().
11041         */
11042         PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11043     }
11044 }
11045
11046 /**
11047  * xmlXPathCompPredicate:
11048  * @ctxt:  the XPath Parser context
11049  * @filter:  act as a filter
11050  *
11051  *  [8]   Predicate ::=   '[' PredicateExpr ']'
11052  *  [9]   PredicateExpr ::=   Expr
11053  *
11054  * Compile a predicate expression
11055  */
11056 static void
11057 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11058     int op1 = ctxt->comp->last;
11059
11060     SKIP_BLANKS;
11061     if (CUR != '[') {
11062         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11063     }
11064     NEXT;
11065     SKIP_BLANKS;
11066
11067     ctxt->comp->last = -1;
11068     /*
11069     * This call to xmlXPathCompileExpr() will deactivate sorting
11070     * of the predicate result.
11071     * TODO: Sorting is still activated for filters, since I'm not
11072     *  sure if needed. Normally sorting should not be needed, since
11073     *  a filter can only diminish the number of items in a sequence,
11074     *  but won't change its order; so if the initial sequence is sorted,
11075     *  subsequent sorting is not needed.
11076     */
11077     if (! filter)
11078         xmlXPathCompileExpr(ctxt, 0);
11079     else
11080         xmlXPathCompileExpr(ctxt, 1);
11081     CHECK_ERROR;
11082
11083     if (CUR != ']') {
11084         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11085     }
11086
11087     if (filter)
11088         PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11089     else
11090         PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11091
11092     NEXT;
11093     SKIP_BLANKS;
11094 }
11095
11096 /**
11097  * xmlXPathCompNodeTest:
11098  * @ctxt:  the XPath Parser context
11099  * @test:  pointer to a xmlXPathTestVal
11100  * @type:  pointer to a xmlXPathTypeVal
11101  * @prefix:  placeholder for a possible name prefix
11102  *
11103  * [7] NodeTest ::=   NameTest
11104  *                  | NodeType '(' ')'
11105  *                  | 'processing-instruction' '(' Literal ')'
11106  *
11107  * [37] NameTest ::=  '*'
11108  *                  | NCName ':' '*'
11109  *                  | QName
11110  * [38] NodeType ::= 'comment'
11111  *                 | 'text'
11112  *                 | 'processing-instruction'
11113  *                 | 'node'
11114  *
11115  * Returns the name found and updates @test, @type and @prefix appropriately
11116  */
11117 static xmlChar *
11118 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11119                      xmlXPathTypeVal *type, const xmlChar **prefix,
11120                      xmlChar *name) {
11121     int blanks;
11122
11123     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11124         STRANGE;
11125         return(NULL);
11126     }
11127     *type = (xmlXPathTypeVal) 0;
11128     *test = (xmlXPathTestVal) 0;
11129     *prefix = NULL;
11130     SKIP_BLANKS;
11131
11132     if ((name == NULL) && (CUR == '*')) {
11133         /*
11134          * All elements
11135          */
11136         NEXT;
11137         *test = NODE_TEST_ALL;
11138         return(NULL);
11139     }
11140
11141     if (name == NULL)
11142         name = xmlXPathParseNCName(ctxt);
11143     if (name == NULL) {
11144         XP_ERRORNULL(XPATH_EXPR_ERROR);
11145     }
11146
11147     blanks = IS_BLANK_CH(CUR);
11148     SKIP_BLANKS;
11149     if (CUR == '(') {
11150         NEXT;
11151         /*
11152          * NodeType or PI search
11153          */
11154         if (xmlStrEqual(name, BAD_CAST "comment"))
11155             *type = NODE_TYPE_COMMENT;
11156         else if (xmlStrEqual(name, BAD_CAST "node"))
11157             *type = NODE_TYPE_NODE;
11158         else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11159             *type = NODE_TYPE_PI;
11160         else if (xmlStrEqual(name, BAD_CAST "text"))
11161             *type = NODE_TYPE_TEXT;
11162         else {
11163             if (name != NULL)
11164                 xmlFree(name);
11165             XP_ERRORNULL(XPATH_EXPR_ERROR);
11166         }
11167
11168         *test = NODE_TEST_TYPE;
11169
11170         SKIP_BLANKS;
11171         if (*type == NODE_TYPE_PI) {
11172             /*
11173              * Specific case: search a PI by name.
11174              */
11175             if (name != NULL)
11176                 xmlFree(name);
11177             name = NULL;
11178             if (CUR != ')') {
11179                 name = xmlXPathParseLiteral(ctxt);
11180                 CHECK_ERROR NULL;
11181                 *test = NODE_TEST_PI;
11182                 SKIP_BLANKS;
11183             }
11184         }
11185         if (CUR != ')') {
11186             if (name != NULL)
11187                 xmlFree(name);
11188             XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11189         }
11190         NEXT;
11191         return(name);
11192     }
11193     *test = NODE_TEST_NAME;
11194     if ((!blanks) && (CUR == ':')) {
11195         NEXT;
11196
11197         /*
11198          * Since currently the parser context don't have a
11199          * namespace list associated:
11200          * The namespace name for this prefix can be computed
11201          * only at evaluation time. The compilation is done
11202          * outside of any context.
11203          */
11204 #if 0
11205         *prefix = xmlXPathNsLookup(ctxt->context, name);
11206         if (name != NULL)
11207             xmlFree(name);
11208         if (*prefix == NULL) {
11209             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11210         }
11211 #else
11212         *prefix = name;
11213 #endif
11214
11215         if (CUR == '*') {
11216             /*
11217              * All elements
11218              */
11219             NEXT;
11220             *test = NODE_TEST_ALL;
11221             return(NULL);
11222         }
11223
11224         name = xmlXPathParseNCName(ctxt);
11225         if (name == NULL) {
11226             XP_ERRORNULL(XPATH_EXPR_ERROR);
11227         }
11228     }
11229     return(name);
11230 }
11231
11232 /**
11233  * xmlXPathIsAxisName:
11234  * @name:  a preparsed name token
11235  *
11236  * [6] AxisName ::=   'ancestor'
11237  *                  | 'ancestor-or-self'
11238  *                  | 'attribute'
11239  *                  | 'child'
11240  *                  | 'descendant'
11241  *                  | 'descendant-or-self'
11242  *                  | 'following'
11243  *                  | 'following-sibling'
11244  *                  | 'namespace'
11245  *                  | 'parent'
11246  *                  | 'preceding'
11247  *                  | 'preceding-sibling'
11248  *                  | 'self'
11249  *
11250  * Returns the axis or 0
11251  */
11252 static xmlXPathAxisVal
11253 xmlXPathIsAxisName(const xmlChar *name) {
11254     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11255     switch (name[0]) {
11256         case 'a':
11257             if (xmlStrEqual(name, BAD_CAST "ancestor"))
11258                 ret = AXIS_ANCESTOR;
11259             if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11260                 ret = AXIS_ANCESTOR_OR_SELF;
11261             if (xmlStrEqual(name, BAD_CAST "attribute"))
11262                 ret = AXIS_ATTRIBUTE;
11263             break;
11264         case 'c':
11265             if (xmlStrEqual(name, BAD_CAST "child"))
11266                 ret = AXIS_CHILD;
11267             break;
11268         case 'd':
11269             if (xmlStrEqual(name, BAD_CAST "descendant"))
11270                 ret = AXIS_DESCENDANT;
11271             if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11272                 ret = AXIS_DESCENDANT_OR_SELF;
11273             break;
11274         case 'f':
11275             if (xmlStrEqual(name, BAD_CAST "following"))
11276                 ret = AXIS_FOLLOWING;
11277             if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11278                 ret = AXIS_FOLLOWING_SIBLING;
11279             break;
11280         case 'n':
11281             if (xmlStrEqual(name, BAD_CAST "namespace"))
11282                 ret = AXIS_NAMESPACE;
11283             break;
11284         case 'p':
11285             if (xmlStrEqual(name, BAD_CAST "parent"))
11286                 ret = AXIS_PARENT;
11287             if (xmlStrEqual(name, BAD_CAST "preceding"))
11288                 ret = AXIS_PRECEDING;
11289             if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11290                 ret = AXIS_PRECEDING_SIBLING;
11291             break;
11292         case 's':
11293             if (xmlStrEqual(name, BAD_CAST "self"))
11294                 ret = AXIS_SELF;
11295             break;
11296     }
11297     return(ret);
11298 }
11299
11300 /**
11301  * xmlXPathCompStep:
11302  * @ctxt:  the XPath Parser context
11303  *
11304  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11305  *                  | AbbreviatedStep
11306  *
11307  * [12] AbbreviatedStep ::=   '.' | '..'
11308  *
11309  * [5] AxisSpecifier ::= AxisName '::'
11310  *                  | AbbreviatedAxisSpecifier
11311  *
11312  * [13] AbbreviatedAxisSpecifier ::= '@'?
11313  *
11314  * Modified for XPtr range support as:
11315  *
11316  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11317  *                     | AbbreviatedStep
11318  *                     | 'range-to' '(' Expr ')' Predicate*
11319  *
11320  * Compile one step in a Location Path
11321  * A location step of . is short for self::node(). This is
11322  * particularly useful in conjunction with //. For example, the
11323  * location path .//para is short for
11324  * self::node()/descendant-or-self::node()/child::para
11325  * and so will select all para descendant elements of the context
11326  * node.
11327  * Similarly, a location step of .. is short for parent::node().
11328  * For example, ../title is short for parent::node()/child::title
11329  * and so will select the title children of the parent of the context
11330  * node.
11331  */
11332 static void
11333 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11334 #ifdef LIBXML_XPTR_ENABLED
11335     int rangeto = 0;
11336     int op2 = -1;
11337 #endif
11338
11339     SKIP_BLANKS;
11340     if ((CUR == '.') && (NXT(1) == '.')) {
11341         SKIP(2);
11342         SKIP_BLANKS;
11343         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11344                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11345     } else if (CUR == '.') {
11346         NEXT;
11347         SKIP_BLANKS;
11348     } else {
11349         xmlChar *name = NULL;
11350         const xmlChar *prefix = NULL;
11351         xmlXPathTestVal test = (xmlXPathTestVal) 0;
11352         xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11353         xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11354         int op1;
11355
11356         /*
11357          * The modification needed for XPointer change to the production
11358          */
11359 #ifdef LIBXML_XPTR_ENABLED
11360         if (ctxt->xptr) {
11361             name = xmlXPathParseNCName(ctxt);
11362             if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11363                 op2 = ctxt->comp->last;
11364                 xmlFree(name);
11365                 SKIP_BLANKS;
11366                 if (CUR != '(') {
11367                     XP_ERROR(XPATH_EXPR_ERROR);
11368                 }
11369                 NEXT;
11370                 SKIP_BLANKS;
11371
11372                 xmlXPathCompileExpr(ctxt, 1);
11373                 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11374                 CHECK_ERROR;
11375
11376                 SKIP_BLANKS;
11377                 if (CUR != ')') {
11378                     XP_ERROR(XPATH_EXPR_ERROR);
11379                 }
11380                 NEXT;
11381                 rangeto = 1;
11382                 goto eval_predicates;
11383             }
11384         }
11385 #endif
11386         if (CUR == '*') {
11387             axis = AXIS_CHILD;
11388         } else {
11389             if (name == NULL)
11390                 name = xmlXPathParseNCName(ctxt);
11391             if (name != NULL) {
11392                 axis = xmlXPathIsAxisName(name);
11393                 if (axis != 0) {
11394                     SKIP_BLANKS;
11395                     if ((CUR == ':') && (NXT(1) == ':')) {
11396                         SKIP(2);
11397                         xmlFree(name);
11398                         name = NULL;
11399                     } else {
11400                         /* an element name can conflict with an axis one :-\ */
11401                         axis = AXIS_CHILD;
11402                     }
11403                 } else {
11404                     axis = AXIS_CHILD;
11405                 }
11406             } else if (CUR == '@') {
11407                 NEXT;
11408                 axis = AXIS_ATTRIBUTE;
11409             } else {
11410                 axis = AXIS_CHILD;
11411             }
11412         }
11413
11414         if (ctxt->error != XPATH_EXPRESSION_OK) {
11415             xmlFree(name);
11416             return;
11417         }
11418
11419         name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11420         if (test == 0)
11421             return;
11422
11423         if ((prefix != NULL) && (ctxt->context != NULL) &&
11424             (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11425             if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11426                 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11427             }
11428         }
11429 #ifdef DEBUG_STEP
11430         xmlGenericError(xmlGenericErrorContext,
11431                 "Basis : computing new set\n");
11432 #endif
11433
11434 #ifdef DEBUG_STEP
11435         xmlGenericError(xmlGenericErrorContext, "Basis : ");
11436         if (ctxt->value == NULL)
11437             xmlGenericError(xmlGenericErrorContext, "no value\n");
11438         else if (ctxt->value->nodesetval == NULL)
11439             xmlGenericError(xmlGenericErrorContext, "Empty\n");
11440         else
11441             xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11442 #endif
11443
11444 #ifdef LIBXML_XPTR_ENABLED
11445 eval_predicates:
11446 #endif
11447         op1 = ctxt->comp->last;
11448         ctxt->comp->last = -1;
11449
11450         SKIP_BLANKS;
11451         while (CUR == '[') {
11452             xmlXPathCompPredicate(ctxt, 0);
11453         }
11454
11455 #ifdef LIBXML_XPTR_ENABLED
11456         if (rangeto) {
11457             PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11458         } else
11459 #endif
11460             PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11461                            test, type, (void *)prefix, (void *)name);
11462
11463     }
11464 #ifdef DEBUG_STEP
11465     xmlGenericError(xmlGenericErrorContext, "Step : ");
11466     if (ctxt->value == NULL)
11467         xmlGenericError(xmlGenericErrorContext, "no value\n");
11468     else if (ctxt->value->nodesetval == NULL)
11469         xmlGenericError(xmlGenericErrorContext, "Empty\n");
11470     else
11471         xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11472                 ctxt->value->nodesetval);
11473 #endif
11474 }
11475
11476 /**
11477  * xmlXPathCompRelativeLocationPath:
11478  * @ctxt:  the XPath Parser context
11479  *
11480  *  [3]   RelativeLocationPath ::=   Step
11481  *                     | RelativeLocationPath '/' Step
11482  *                     | AbbreviatedRelativeLocationPath
11483  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11484  *
11485  * Compile a relative location path.
11486  */
11487 static void
11488 xmlXPathCompRelativeLocationPath
11489 (xmlXPathParserContextPtr ctxt) {
11490     SKIP_BLANKS;
11491     if ((CUR == '/') && (NXT(1) == '/')) {
11492         SKIP(2);
11493         SKIP_BLANKS;
11494         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11495                          NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11496     } else if (CUR == '/') {
11497             NEXT;
11498         SKIP_BLANKS;
11499     }
11500     xmlXPathCompStep(ctxt);
11501     CHECK_ERROR;
11502     SKIP_BLANKS;
11503     while (CUR == '/') {
11504         if ((CUR == '/') && (NXT(1) == '/')) {
11505             SKIP(2);
11506             SKIP_BLANKS;
11507             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11508                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11509             xmlXPathCompStep(ctxt);
11510         } else if (CUR == '/') {
11511             NEXT;
11512             SKIP_BLANKS;
11513             xmlXPathCompStep(ctxt);
11514         }
11515         SKIP_BLANKS;
11516     }
11517 }
11518
11519 /**
11520  * xmlXPathCompLocationPath:
11521  * @ctxt:  the XPath Parser context
11522  *
11523  *  [1]   LocationPath ::=   RelativeLocationPath
11524  *                     | AbsoluteLocationPath
11525  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11526  *                     | AbbreviatedAbsoluteLocationPath
11527  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11528  *                           '//' RelativeLocationPath
11529  *
11530  * Compile a location path
11531  *
11532  * // is short for /descendant-or-self::node()/. For example,
11533  * //para is short for /descendant-or-self::node()/child::para and
11534  * so will select any para element in the document (even a para element
11535  * that is a document element will be selected by //para since the
11536  * document element node is a child of the root node); div//para is
11537  * short for div/descendant-or-self::node()/child::para and so will
11538  * select all para descendants of div children.
11539  */
11540 static void
11541 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11542     SKIP_BLANKS;
11543     if (CUR != '/') {
11544         xmlXPathCompRelativeLocationPath(ctxt);
11545     } else {
11546         while (CUR == '/') {
11547             if ((CUR == '/') && (NXT(1) == '/')) {
11548                 SKIP(2);
11549                 SKIP_BLANKS;
11550                 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11551                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11552                 xmlXPathCompRelativeLocationPath(ctxt);
11553             } else if (CUR == '/') {
11554                 NEXT;
11555                 SKIP_BLANKS;
11556                 if ((CUR != 0 ) &&
11557                     ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11558                      (CUR == '@') || (CUR == '*')))
11559                     xmlXPathCompRelativeLocationPath(ctxt);
11560             }
11561             CHECK_ERROR;
11562         }
11563     }
11564 }
11565
11566 /************************************************************************
11567  *                                                                      *
11568  *              XPath precompiled expression evaluation                 *
11569  *                                                                      *
11570  ************************************************************************/
11571
11572 static int
11573 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11574
11575 #ifdef DEBUG_STEP
11576 static void
11577 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11578                           int nbNodes)
11579 {
11580     xmlGenericError(xmlGenericErrorContext, "new step : ");
11581     switch (op->value) {
11582         case AXIS_ANCESTOR:
11583             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11584             break;
11585         case AXIS_ANCESTOR_OR_SELF:
11586             xmlGenericError(xmlGenericErrorContext,
11587                             "axis 'ancestors-or-self' ");
11588             break;
11589         case AXIS_ATTRIBUTE:
11590             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11591             break;
11592         case AXIS_CHILD:
11593             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11594             break;
11595         case AXIS_DESCENDANT:
11596             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11597             break;
11598         case AXIS_DESCENDANT_OR_SELF:
11599             xmlGenericError(xmlGenericErrorContext,
11600                             "axis 'descendant-or-self' ");
11601             break;
11602         case AXIS_FOLLOWING:
11603             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11604             break;
11605         case AXIS_FOLLOWING_SIBLING:
11606             xmlGenericError(xmlGenericErrorContext,
11607                             "axis 'following-siblings' ");
11608             break;
11609         case AXIS_NAMESPACE:
11610             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11611             break;
11612         case AXIS_PARENT:
11613             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11614             break;
11615         case AXIS_PRECEDING:
11616             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11617             break;
11618         case AXIS_PRECEDING_SIBLING:
11619             xmlGenericError(xmlGenericErrorContext,
11620                             "axis 'preceding-sibling' ");
11621             break;
11622         case AXIS_SELF:
11623             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11624             break;
11625     }
11626     xmlGenericError(xmlGenericErrorContext,
11627         " context contains %d nodes\n", nbNodes);
11628     switch (op->value2) {
11629         case NODE_TEST_NONE:
11630             xmlGenericError(xmlGenericErrorContext,
11631                             "           searching for none !!!\n");
11632             break;
11633         case NODE_TEST_TYPE:
11634             xmlGenericError(xmlGenericErrorContext,
11635                             "           searching for type %d\n", op->value3);
11636             break;
11637         case NODE_TEST_PI:
11638             xmlGenericError(xmlGenericErrorContext,
11639                             "           searching for PI !!!\n");
11640             break;
11641         case NODE_TEST_ALL:
11642             xmlGenericError(xmlGenericErrorContext,
11643                             "           searching for *\n");
11644             break;
11645         case NODE_TEST_NS:
11646             xmlGenericError(xmlGenericErrorContext,
11647                             "           searching for namespace %s\n",
11648                             op->value5);
11649             break;
11650         case NODE_TEST_NAME:
11651             xmlGenericError(xmlGenericErrorContext,
11652                             "           searching for name %s\n", op->value5);
11653             if (op->value4)
11654                 xmlGenericError(xmlGenericErrorContext,
11655                                 "           with namespace %s\n", op->value4);
11656             break;
11657     }
11658     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11659 }
11660 #endif /* DEBUG_STEP */
11661
11662 static int
11663 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11664                             xmlXPathStepOpPtr op,
11665                             xmlNodeSetPtr set,
11666                             int contextSize,
11667                             int hasNsNodes)
11668 {
11669     if (op->ch1 != -1) {
11670         xmlXPathCompExprPtr comp = ctxt->comp;
11671         /*
11672         * Process inner predicates first.
11673         */
11674         if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11675             /*
11676             * TODO: raise an internal error.
11677             */
11678         }
11679         contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11680             &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11681         CHECK_ERROR0;
11682         if (contextSize <= 0)
11683             return(0);
11684     }
11685     if (op->ch2 != -1) {
11686         xmlXPathContextPtr xpctxt = ctxt->context;
11687         xmlNodePtr contextNode, oldContextNode;
11688         xmlDocPtr oldContextDoc;
11689         int i, res, contextPos = 0, newContextSize;
11690         xmlXPathStepOpPtr exprOp;
11691         xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11692
11693 #ifdef LIBXML_XPTR_ENABLED
11694         /*
11695         * URGENT TODO: Check the following:
11696         *  We don't expect location sets if evaluating prediates, right?
11697         *  Only filters should expect location sets, right?
11698         */
11699 #endif
11700         /*
11701         * SPEC XPath 1.0:
11702         *  "For each node in the node-set to be filtered, the
11703         *  PredicateExpr is evaluated with that node as the
11704         *  context node, with the number of nodes in the
11705         *  node-set as the context size, and with the proximity
11706         *  position of the node in the node-set with respect to
11707         *  the axis as the context position;"
11708         * @oldset is the node-set" to be filtered.
11709         *
11710         * SPEC XPath 1.0:
11711         *  "only predicates change the context position and
11712         *  context size (see [2.4 Predicates])."
11713         * Example:
11714         *   node-set  context pos
11715         *    nA         1
11716         *    nB         2
11717         *    nC         3
11718         *   After applying predicate [position() > 1] :
11719         *   node-set  context pos
11720         *    nB         1
11721         *    nC         2
11722         */
11723         oldContextNode = xpctxt->node;
11724         oldContextDoc = xpctxt->doc;
11725         /*
11726         * Get the expression of this predicate.
11727         */
11728         exprOp = &ctxt->comp->steps[op->ch2];
11729         newContextSize = 0;
11730         for (i = 0; i < set->nodeNr; i++) {
11731             if (set->nodeTab[i] == NULL)
11732                 continue;
11733
11734             contextNode = set->nodeTab[i];
11735             xpctxt->node = contextNode;
11736             xpctxt->contextSize = contextSize;
11737             xpctxt->proximityPosition = ++contextPos;
11738
11739             /*
11740             * Also set the xpath document in case things like
11741             * key() are evaluated in the predicate.
11742             */
11743             if ((contextNode->type != XML_NAMESPACE_DECL) &&
11744                 (contextNode->doc != NULL))
11745                 xpctxt->doc = contextNode->doc;
11746             /*
11747             * Evaluate the predicate expression with 1 context node
11748             * at a time; this node is packaged into a node set; this
11749             * node set is handed over to the evaluation mechanism.
11750             */
11751             if (contextObj == NULL)
11752                 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11753             else {
11754                 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11755                     contextNode) < 0) {
11756                     ctxt->error = XPATH_MEMORY_ERROR;
11757                     goto evaluation_exit;
11758                 }
11759             }
11760
11761             valuePush(ctxt, contextObj);
11762
11763             res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11764
11765             if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11766                 xmlXPathNodeSetClear(set, hasNsNodes);
11767                 newContextSize = 0;
11768                 goto evaluation_exit;
11769             }
11770
11771             if (res != 0) {
11772                 newContextSize++;
11773             } else {
11774                 /*
11775                 * Remove the entry from the initial node set.
11776                 */
11777                 set->nodeTab[i] = NULL;
11778                 if (contextNode->type == XML_NAMESPACE_DECL)
11779                     xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11780             }
11781             if (ctxt->value == contextObj) {
11782                 /*
11783                 * Don't free the temporary XPath object holding the
11784                 * context node, in order to avoid massive recreation
11785                 * inside this loop.
11786                 */
11787                 valuePop(ctxt);
11788                 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11789             } else {
11790                 /*
11791                 * TODO: The object was lost in the evaluation machinery.
11792                 *  Can this happen? Maybe in internal-error cases.
11793                 */
11794                 contextObj = NULL;
11795             }
11796         }
11797
11798         if (contextObj != NULL) {
11799             if (ctxt->value == contextObj)
11800                 valuePop(ctxt);
11801             xmlXPathReleaseObject(xpctxt, contextObj);
11802         }
11803 evaluation_exit:
11804         if (exprRes != NULL)
11805             xmlXPathReleaseObject(ctxt->context, exprRes);
11806         /*
11807         * Reset/invalidate the context.
11808         */
11809         xpctxt->node = oldContextNode;
11810         xpctxt->doc = oldContextDoc;
11811         xpctxt->contextSize = -1;
11812         xpctxt->proximityPosition = -1;
11813         return(newContextSize);
11814     }
11815     return(contextSize);
11816 }
11817
11818 static int
11819 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11820                                       xmlXPathStepOpPtr op,
11821                                       xmlNodeSetPtr set,
11822                                       int contextSize,
11823                                       int minPos,
11824                                       int maxPos,
11825                                       int hasNsNodes)
11826 {
11827     if (op->ch1 != -1) {
11828         xmlXPathCompExprPtr comp = ctxt->comp;
11829         if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11830             /*
11831             * TODO: raise an internal error.
11832             */
11833         }
11834         contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11835             &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11836         CHECK_ERROR0;
11837         if (contextSize <= 0)
11838             return(0);
11839     }
11840     /*
11841     * Check if the node set contains a sufficient number of nodes for
11842     * the requested range.
11843     */
11844     if (contextSize < minPos) {
11845         xmlXPathNodeSetClear(set, hasNsNodes);
11846         return(0);
11847     }
11848     if (op->ch2 == -1) {
11849         /*
11850         * TODO: Can this ever happen?
11851         */
11852         return (contextSize);
11853     } else {
11854         xmlDocPtr oldContextDoc;
11855         int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11856         xmlXPathStepOpPtr exprOp;
11857         xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11858         xmlNodePtr oldContextNode, contextNode = NULL;
11859         xmlXPathContextPtr xpctxt = ctxt->context;
11860         int frame;
11861
11862 #ifdef LIBXML_XPTR_ENABLED
11863             /*
11864             * URGENT TODO: Check the following:
11865             *  We don't expect location sets if evaluating prediates, right?
11866             *  Only filters should expect location sets, right?
11867         */
11868 #endif /* LIBXML_XPTR_ENABLED */
11869
11870         /*
11871         * Save old context.
11872         */
11873         oldContextNode = xpctxt->node;
11874         oldContextDoc = xpctxt->doc;
11875         /*
11876         * Get the expression of this predicate.
11877         */
11878         exprOp = &ctxt->comp->steps[op->ch2];
11879         for (i = 0; i < set->nodeNr; i++) {
11880             xmlXPathObjectPtr tmp;
11881
11882             if (set->nodeTab[i] == NULL)
11883                 continue;
11884
11885             contextNode = set->nodeTab[i];
11886             xpctxt->node = contextNode;
11887             xpctxt->contextSize = contextSize;
11888             xpctxt->proximityPosition = ++contextPos;
11889
11890             /*
11891             * Initialize the new set.
11892             * Also set the xpath document in case things like
11893             * key() evaluation are attempted on the predicate
11894             */
11895             if ((contextNode->type != XML_NAMESPACE_DECL) &&
11896                 (contextNode->doc != NULL))
11897                 xpctxt->doc = contextNode->doc;
11898             /*
11899             * Evaluate the predicate expression with 1 context node
11900             * at a time; this node is packaged into a node set; this
11901             * node set is handed over to the evaluation mechanism.
11902             */
11903             if (contextObj == NULL)
11904                 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11905             else {
11906                 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11907                     contextNode) < 0) {
11908                     ctxt->error = XPATH_MEMORY_ERROR;
11909                     goto evaluation_exit;
11910                 }
11911             }
11912
11913             frame = xmlXPathSetFrame(ctxt);
11914             valuePush(ctxt, contextObj);
11915             res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11916             tmp = valuePop(ctxt);
11917             xmlXPathPopFrame(ctxt, frame);
11918
11919             if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11920                 while (tmp != contextObj) {
11921                     /*
11922                      * Free up the result
11923                      * then pop off contextObj, which will be freed later
11924                      */
11925                     xmlXPathReleaseObject(xpctxt, tmp);
11926                     tmp = valuePop(ctxt);
11927                 }
11928                 goto evaluation_error;
11929             }
11930             /* push the result back onto the stack */
11931             valuePush(ctxt, tmp);
11932
11933             if (res)
11934                 pos++;
11935
11936             if (res && (pos >= minPos) && (pos <= maxPos)) {
11937                 /*
11938                 * Fits in the requested range.
11939                 */
11940                 newContextSize++;
11941                 if (minPos == maxPos) {
11942                     /*
11943                     * Only 1 node was requested.
11944                     */
11945                     if (contextNode->type == XML_NAMESPACE_DECL) {
11946                         /*
11947                         * As always: take care of those nasty
11948                         * namespace nodes.
11949                         */
11950                         set->nodeTab[i] = NULL;
11951                     }
11952                     xmlXPathNodeSetClear(set, hasNsNodes);
11953                     set->nodeNr = 1;
11954                     set->nodeTab[0] = contextNode;
11955                     goto evaluation_exit;
11956                 }
11957                 if (pos == maxPos) {
11958                     /*
11959                     * We are done.
11960                     */
11961                     xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11962                     goto evaluation_exit;
11963                 }
11964             } else {
11965                 /*
11966                 * Remove the entry from the initial node set.
11967                 */
11968                 set->nodeTab[i] = NULL;
11969                 if (contextNode->type == XML_NAMESPACE_DECL)
11970                     xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11971             }
11972             if (exprRes != NULL) {
11973                 xmlXPathReleaseObject(ctxt->context, exprRes);
11974                 exprRes = NULL;
11975             }
11976             if (ctxt->value == contextObj) {
11977                 /*
11978                 * Don't free the temporary XPath object holding the
11979                 * context node, in order to avoid massive recreation
11980                 * inside this loop.
11981                 */
11982                 valuePop(ctxt);
11983                 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11984             } else {
11985                 /*
11986                 * The object was lost in the evaluation machinery.
11987                 * Can this happen? Maybe in case of internal-errors.
11988                 */
11989                 contextObj = NULL;
11990             }
11991         }
11992         goto evaluation_exit;
11993
11994 evaluation_error:
11995         xmlXPathNodeSetClear(set, hasNsNodes);
11996         newContextSize = 0;
11997
11998 evaluation_exit:
11999         if (contextObj != NULL) {
12000             if (ctxt->value == contextObj)
12001                 valuePop(ctxt);
12002             xmlXPathReleaseObject(xpctxt, contextObj);
12003         }
12004         if (exprRes != NULL)
12005             xmlXPathReleaseObject(ctxt->context, exprRes);
12006         /*
12007         * Reset/invalidate the context.
12008         */
12009         xpctxt->node = oldContextNode;
12010         xpctxt->doc = oldContextDoc;
12011         xpctxt->contextSize = -1;
12012         xpctxt->proximityPosition = -1;
12013         return(newContextSize);
12014     }
12015     return(contextSize);
12016 }
12017
12018 static int
12019 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12020                             xmlXPathStepOpPtr op,
12021                             int *maxPos)
12022 {
12023
12024     xmlXPathStepOpPtr exprOp;
12025
12026     /*
12027     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12028     */
12029
12030     /*
12031     * If not -1, then ch1 will point to:
12032     * 1) For predicates (XPATH_OP_PREDICATE):
12033     *    - an inner predicate operator
12034     * 2) For filters (XPATH_OP_FILTER):
12035     *    - an inner filter operater OR
12036     *    - an expression selecting the node set.
12037     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
12038     */
12039     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12040         return(0);
12041
12042     if (op->ch2 != -1) {
12043         exprOp = &ctxt->comp->steps[op->ch2];
12044     } else
12045         return(0);
12046
12047     if ((exprOp != NULL) &&
12048         (exprOp->op == XPATH_OP_VALUE) &&
12049         (exprOp->value4 != NULL) &&
12050         (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12051     {
12052         /*
12053         * We have a "[n]" predicate here.
12054         * TODO: Unfortunately this simplistic test here is not
12055         * able to detect a position() predicate in compound
12056         * expressions like "[@attr = 'a" and position() = 1],
12057         * and even not the usage of position() in
12058         * "[position() = 1]"; thus - obviously - a position-range,
12059         * like it "[position() < 5]", is also not detected.
12060         * Maybe we could rewrite the AST to ease the optimization.
12061         */
12062         *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12063
12064         if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
12065             (float) *maxPos)
12066         {
12067             return(1);
12068         }
12069     }
12070     return(0);
12071 }
12072
12073 static int
12074 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12075                            xmlXPathStepOpPtr op,
12076                            xmlNodePtr * first, xmlNodePtr * last,
12077                            int toBool)
12078 {
12079
12080 #define XP_TEST_HIT \
12081     if (hasAxisRange != 0) { \
12082         if (++pos == maxPos) { \
12083             if (addNode(seq, cur) < 0) \
12084                 ctxt->error = XPATH_MEMORY_ERROR; \
12085             goto axis_range_end; } \
12086     } else { \
12087         if (addNode(seq, cur) < 0) \
12088             ctxt->error = XPATH_MEMORY_ERROR; \
12089         if (breakOnFirstHit) goto first_hit; }
12090
12091 #define XP_TEST_HIT_NS \
12092     if (hasAxisRange != 0) { \
12093         if (++pos == maxPos) { \
12094             hasNsNodes = 1; \
12095             if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12096                 ctxt->error = XPATH_MEMORY_ERROR; \
12097         goto axis_range_end; } \
12098     } else { \
12099         hasNsNodes = 1; \
12100         if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12101             ctxt->error = XPATH_MEMORY_ERROR; \
12102         if (breakOnFirstHit) goto first_hit; }
12103
12104     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12105     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12106     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12107     const xmlChar *prefix = op->value4;
12108     const xmlChar *name = op->value5;
12109     const xmlChar *URI = NULL;
12110
12111 #ifdef DEBUG_STEP
12112     int nbMatches = 0, prevMatches = 0;
12113 #endif
12114     int total = 0, hasNsNodes = 0;
12115     /* The popped object holding the context nodes */
12116     xmlXPathObjectPtr obj;
12117     /* The set of context nodes for the node tests */
12118     xmlNodeSetPtr contextSeq;
12119     int contextIdx;
12120     xmlNodePtr contextNode;
12121     /* The final resulting node set wrt to all context nodes */
12122     xmlNodeSetPtr outSeq;
12123     /*
12124     * The temporary resulting node set wrt 1 context node.
12125     * Used to feed predicate evaluation.
12126     */
12127     xmlNodeSetPtr seq;
12128     xmlNodePtr cur;
12129     /* First predicate operator */
12130     xmlXPathStepOpPtr predOp;
12131     int maxPos; /* The requested position() (when a "[n]" predicate) */
12132     int hasPredicateRange, hasAxisRange, pos, size, newSize;
12133     int breakOnFirstHit;
12134
12135     xmlXPathTraversalFunction next = NULL;
12136     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12137     xmlXPathNodeSetMergeFunction mergeAndClear;
12138     xmlNodePtr oldContextNode;
12139     xmlXPathContextPtr xpctxt = ctxt->context;
12140
12141
12142     CHECK_TYPE0(XPATH_NODESET);
12143     obj = valuePop(ctxt);
12144     /*
12145     * Setup namespaces.
12146     */
12147     if (prefix != NULL) {
12148         URI = xmlXPathNsLookup(xpctxt, prefix);
12149         if (URI == NULL) {
12150             xmlXPathReleaseObject(xpctxt, obj);
12151             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12152         }
12153     }
12154     /*
12155     * Setup axis.
12156     *
12157     * MAYBE FUTURE TODO: merging optimizations:
12158     * - If the nodes to be traversed wrt to the initial nodes and
12159     *   the current axis cannot overlap, then we could avoid searching
12160     *   for duplicates during the merge.
12161     *   But the question is how/when to evaluate if they cannot overlap.
12162     *   Example: if we know that for two initial nodes, the one is
12163     *   not in the ancestor-or-self axis of the other, then we could safely
12164     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12165     *   the descendant-or-self axis.
12166     */
12167     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12168     switch (axis) {
12169         case AXIS_ANCESTOR:
12170             first = NULL;
12171             next = xmlXPathNextAncestor;
12172             break;
12173         case AXIS_ANCESTOR_OR_SELF:
12174             first = NULL;
12175             next = xmlXPathNextAncestorOrSelf;
12176             break;
12177         case AXIS_ATTRIBUTE:
12178             first = NULL;
12179             last = NULL;
12180             next = xmlXPathNextAttribute;
12181             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12182             break;
12183         case AXIS_CHILD:
12184             last = NULL;
12185             if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12186                 (type == NODE_TYPE_NODE))
12187             {
12188                 /*
12189                 * Optimization if an element node type is 'element'.
12190                 */
12191                 next = xmlXPathNextChildElement;
12192             } else
12193                 next = xmlXPathNextChild;
12194             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12195             break;
12196         case AXIS_DESCENDANT:
12197             last = NULL;
12198             next = xmlXPathNextDescendant;
12199             break;
12200         case AXIS_DESCENDANT_OR_SELF:
12201             last = NULL;
12202             next = xmlXPathNextDescendantOrSelf;
12203             break;
12204         case AXIS_FOLLOWING:
12205             last = NULL;
12206             next = xmlXPathNextFollowing;
12207             break;
12208         case AXIS_FOLLOWING_SIBLING:
12209             last = NULL;
12210             next = xmlXPathNextFollowingSibling;
12211             break;
12212         case AXIS_NAMESPACE:
12213             first = NULL;
12214             last = NULL;
12215             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12216             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12217             break;
12218         case AXIS_PARENT:
12219             first = NULL;
12220             next = xmlXPathNextParent;
12221             break;
12222         case AXIS_PRECEDING:
12223             first = NULL;
12224             next = xmlXPathNextPrecedingInternal;
12225             break;
12226         case AXIS_PRECEDING_SIBLING:
12227             first = NULL;
12228             next = xmlXPathNextPrecedingSibling;
12229             break;
12230         case AXIS_SELF:
12231             first = NULL;
12232             last = NULL;
12233             next = xmlXPathNextSelf;
12234             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12235             break;
12236     }
12237
12238 #ifdef DEBUG_STEP
12239     xmlXPathDebugDumpStepAxis(op,
12240         (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12241 #endif
12242
12243     if (next == NULL) {
12244         xmlXPathReleaseObject(xpctxt, obj);
12245         return(0);
12246     }
12247     contextSeq = obj->nodesetval;
12248     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12249         xmlXPathReleaseObject(xpctxt, obj);
12250         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12251         return(0);
12252     }
12253     /*
12254     * Predicate optimization ---------------------------------------------
12255     * If this step has a last predicate, which contains a position(),
12256     * then we'll optimize (although not exactly "position()", but only
12257     * the  short-hand form, i.e., "[n]".
12258     *
12259     * Example - expression "/foo[parent::bar][1]":
12260     *
12261     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12262     *   ROOT                               -- op->ch1
12263     *   PREDICATE                          -- op->ch2 (predOp)
12264     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12265     *       SORT
12266     *         COLLECT  'parent' 'name' 'node' bar
12267     *           NODE
12268     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12269     *
12270     */
12271     maxPos = 0;
12272     predOp = NULL;
12273     hasPredicateRange = 0;
12274     hasAxisRange = 0;
12275     if (op->ch2 != -1) {
12276         /*
12277         * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12278         */
12279         predOp = &ctxt->comp->steps[op->ch2];
12280         if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12281             if (predOp->ch1 != -1) {
12282                 /*
12283                 * Use the next inner predicate operator.
12284                 */
12285                 predOp = &ctxt->comp->steps[predOp->ch1];
12286                 hasPredicateRange = 1;
12287             } else {
12288                 /*
12289                 * There's no other predicate than the [n] predicate.
12290                 */
12291                 predOp = NULL;
12292                 hasAxisRange = 1;
12293             }
12294         }
12295     }
12296     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12297     /*
12298     * Axis traversal -----------------------------------------------------
12299     */
12300     /*
12301      * 2.3 Node Tests
12302      *  - For the attribute axis, the principal node type is attribute.
12303      *  - For the namespace axis, the principal node type is namespace.
12304      *  - For other axes, the principal node type is element.
12305      *
12306      * A node test * is true for any node of the
12307      * principal node type. For example, child::* will
12308      * select all element children of the context node
12309      */
12310     oldContextNode = xpctxt->node;
12311     addNode = xmlXPathNodeSetAddUnique;
12312     outSeq = NULL;
12313     seq = NULL;
12314     contextNode = NULL;
12315     contextIdx = 0;
12316
12317
12318     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12319            (ctxt->error == XPATH_EXPRESSION_OK)) {
12320         xpctxt->node = contextSeq->nodeTab[contextIdx++];
12321
12322         if (seq == NULL) {
12323             seq = xmlXPathNodeSetCreate(NULL);
12324             if (seq == NULL) {
12325                 total = 0;
12326                 goto error;
12327             }
12328         }
12329         /*
12330         * Traverse the axis and test the nodes.
12331         */
12332         pos = 0;
12333         cur = NULL;
12334         hasNsNodes = 0;
12335         do {
12336             cur = next(ctxt, cur);
12337             if (cur == NULL)
12338                 break;
12339
12340             /*
12341             * QUESTION TODO: What does the "first" and "last" stuff do?
12342             */
12343             if ((first != NULL) && (*first != NULL)) {
12344                 if (*first == cur)
12345                     break;
12346                 if (((total % 256) == 0) &&
12347 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12348                     (xmlXPathCmpNodesExt(*first, cur) >= 0))
12349 #else
12350                     (xmlXPathCmpNodes(*first, cur) >= 0))
12351 #endif
12352                 {
12353                     break;
12354                 }
12355             }
12356             if ((last != NULL) && (*last != NULL)) {
12357                 if (*last == cur)
12358                     break;
12359                 if (((total % 256) == 0) &&
12360 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12361                     (xmlXPathCmpNodesExt(cur, *last) >= 0))
12362 #else
12363                     (xmlXPathCmpNodes(cur, *last) >= 0))
12364 #endif
12365                 {
12366                     break;
12367                 }
12368             }
12369
12370             total++;
12371
12372 #ifdef DEBUG_STEP
12373             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12374 #endif
12375
12376             switch (test) {
12377                 case NODE_TEST_NONE:
12378                     total = 0;
12379                     STRANGE
12380                     goto error;
12381                 case NODE_TEST_TYPE:
12382                     if (type == NODE_TYPE_NODE) {
12383                         switch (cur->type) {
12384                             case XML_DOCUMENT_NODE:
12385                             case XML_HTML_DOCUMENT_NODE:
12386 #ifdef LIBXML_DOCB_ENABLED
12387                             case XML_DOCB_DOCUMENT_NODE:
12388 #endif
12389                             case XML_ELEMENT_NODE:
12390                             case XML_ATTRIBUTE_NODE:
12391                             case XML_PI_NODE:
12392                             case XML_COMMENT_NODE:
12393                             case XML_CDATA_SECTION_NODE:
12394                             case XML_TEXT_NODE:
12395                                 XP_TEST_HIT
12396                                 break;
12397                             case XML_NAMESPACE_DECL: {
12398                                 if (axis == AXIS_NAMESPACE) {
12399                                     XP_TEST_HIT_NS
12400                                 } else {
12401                                     hasNsNodes = 1;
12402                                     XP_TEST_HIT
12403                                 }
12404                                 break;
12405                             }
12406                             default:
12407                                 break;
12408                         }
12409                     } else if (cur->type == type) {
12410                         if (cur->type == XML_NAMESPACE_DECL)
12411                             XP_TEST_HIT_NS
12412                         else
12413                             XP_TEST_HIT
12414                     } else if ((type == NODE_TYPE_TEXT) &&
12415                          (cur->type == XML_CDATA_SECTION_NODE))
12416                     {
12417                         XP_TEST_HIT
12418                     }
12419                     break;
12420                 case NODE_TEST_PI:
12421                     if ((cur->type == XML_PI_NODE) &&
12422                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12423                     {
12424                         XP_TEST_HIT
12425                     }
12426                     break;
12427                 case NODE_TEST_ALL:
12428                     if (axis == AXIS_ATTRIBUTE) {
12429                         if (cur->type == XML_ATTRIBUTE_NODE)
12430                         {
12431                             if (prefix == NULL)
12432                             {
12433                                 XP_TEST_HIT
12434                             } else if ((cur->ns != NULL) &&
12435                                 (xmlStrEqual(URI, cur->ns->href)))
12436                             {
12437                                 XP_TEST_HIT
12438                             }
12439                         }
12440                     } else if (axis == AXIS_NAMESPACE) {
12441                         if (cur->type == XML_NAMESPACE_DECL)
12442                         {
12443                             XP_TEST_HIT_NS
12444                         }
12445                     } else {
12446                         if (cur->type == XML_ELEMENT_NODE) {
12447                             if (prefix == NULL)
12448                             {
12449                                 XP_TEST_HIT
12450
12451                             } else if ((cur->ns != NULL) &&
12452                                 (xmlStrEqual(URI, cur->ns->href)))
12453                             {
12454                                 XP_TEST_HIT
12455                             }
12456                         }
12457                     }
12458                     break;
12459                 case NODE_TEST_NS:{
12460                         TODO;
12461                         break;
12462                     }
12463                 case NODE_TEST_NAME:
12464                     if (axis == AXIS_ATTRIBUTE) {
12465                         if (cur->type != XML_ATTRIBUTE_NODE)
12466                             break;
12467                     } else if (axis == AXIS_NAMESPACE) {
12468                         if (cur->type != XML_NAMESPACE_DECL)
12469                             break;
12470                     } else {
12471                         if (cur->type != XML_ELEMENT_NODE)
12472                             break;
12473                     }
12474                     switch (cur->type) {
12475                         case XML_ELEMENT_NODE:
12476                             if (xmlStrEqual(name, cur->name)) {
12477                                 if (prefix == NULL) {
12478                                     if (cur->ns == NULL)
12479                                     {
12480                                         XP_TEST_HIT
12481                                     }
12482                                 } else {
12483                                     if ((cur->ns != NULL) &&
12484                                         (xmlStrEqual(URI, cur->ns->href)))
12485                                     {
12486                                         XP_TEST_HIT
12487                                     }
12488                                 }
12489                             }
12490                             break;
12491                         case XML_ATTRIBUTE_NODE:{
12492                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12493
12494                                 if (xmlStrEqual(name, attr->name)) {
12495                                     if (prefix == NULL) {
12496                                         if ((attr->ns == NULL) ||
12497                                             (attr->ns->prefix == NULL))
12498                                         {
12499                                             XP_TEST_HIT
12500                                         }
12501                                     } else {
12502                                         if ((attr->ns != NULL) &&
12503                                             (xmlStrEqual(URI,
12504                                               attr->ns->href)))
12505                                         {
12506                                             XP_TEST_HIT
12507                                         }
12508                                     }
12509                                 }
12510                                 break;
12511                             }
12512                         case XML_NAMESPACE_DECL:
12513                             if (cur->type == XML_NAMESPACE_DECL) {
12514                                 xmlNsPtr ns = (xmlNsPtr) cur;
12515
12516                                 if ((ns->prefix != NULL) && (name != NULL)
12517                                     && (xmlStrEqual(ns->prefix, name)))
12518                                 {
12519                                     XP_TEST_HIT_NS
12520                                 }
12521                             }
12522                             break;
12523                         default:
12524                             break;
12525                     }
12526                     break;
12527             } /* switch(test) */
12528         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12529
12530         goto apply_predicates;
12531
12532 axis_range_end: /* ----------------------------------------------------- */
12533         /*
12534         * We have a "/foo[n]", and position() = n was reached.
12535         * Note that we can have as well "/foo/::parent::foo[1]", so
12536         * a duplicate-aware merge is still needed.
12537         * Merge with the result.
12538         */
12539         if (outSeq == NULL) {
12540             outSeq = seq;
12541             seq = NULL;
12542         } else
12543             outSeq = mergeAndClear(outSeq, seq, 0);
12544         /*
12545         * Break if only a true/false result was requested.
12546         */
12547         if (toBool)
12548             break;
12549         continue;
12550
12551 first_hit: /* ---------------------------------------------------------- */
12552         /*
12553         * Break if only a true/false result was requested and
12554         * no predicates existed and a node test succeeded.
12555         */
12556         if (outSeq == NULL) {
12557             outSeq = seq;
12558             seq = NULL;
12559         } else
12560             outSeq = mergeAndClear(outSeq, seq, 0);
12561         break;
12562
12563 #ifdef DEBUG_STEP
12564         if (seq != NULL)
12565             nbMatches += seq->nodeNr;
12566 #endif
12567
12568 apply_predicates: /* --------------------------------------------------- */
12569         if (ctxt->error != XPATH_EXPRESSION_OK)
12570             goto error;
12571
12572         /*
12573         * Apply predicates.
12574         */
12575         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12576             /*
12577             * E.g. when we have a "/foo[some expression][n]".
12578             */
12579             /*
12580             * QUESTION TODO: The old predicate evaluation took into
12581             *  account location-sets.
12582             *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12583             *  Do we expect such a set here?
12584             *  All what I learned now from the evaluation semantics
12585             *  does not indicate that a location-set will be processed
12586             *  here, so this looks OK.
12587             */
12588             /*
12589             * Iterate over all predicates, starting with the outermost
12590             * predicate.
12591             * TODO: Problem: we cannot execute the inner predicates first
12592             *  since we cannot go back *up* the operator tree!
12593             *  Options we have:
12594             *  1) Use of recursive functions (like is it currently done
12595             *     via xmlXPathCompOpEval())
12596             *  2) Add a predicate evaluation information stack to the
12597             *     context struct
12598             *  3) Change the way the operators are linked; we need a
12599             *     "parent" field on xmlXPathStepOp
12600             *
12601             * For the moment, I'll try to solve this with a recursive
12602             * function: xmlXPathCompOpEvalPredicate().
12603             */
12604             size = seq->nodeNr;
12605             if (hasPredicateRange != 0)
12606                 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12607                     predOp, seq, size, maxPos, maxPos, hasNsNodes);
12608             else
12609                 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12610                     predOp, seq, size, hasNsNodes);
12611
12612             if (ctxt->error != XPATH_EXPRESSION_OK) {
12613                 total = 0;
12614                 goto error;
12615             }
12616             /*
12617             * Add the filtered set of nodes to the result node set.
12618             */
12619             if (newSize == 0) {
12620                 /*
12621                 * The predicates filtered all nodes out.
12622                 */
12623                 xmlXPathNodeSetClear(seq, hasNsNodes);
12624             } else if (seq->nodeNr > 0) {
12625                 /*
12626                 * Add to result set.
12627                 */
12628                 if (outSeq == NULL) {
12629                     if (size != newSize) {
12630                         /*
12631                         * We need to merge and clear here, since
12632                         * the sequence will contained NULLed entries.
12633                         */
12634                         outSeq = mergeAndClear(NULL, seq, 1);
12635                     } else {
12636                         outSeq = seq;
12637                         seq = NULL;
12638                     }
12639                 } else
12640                     outSeq = mergeAndClear(outSeq, seq,
12641                         (size != newSize) ? 1: 0);
12642                 /*
12643                 * Break if only a true/false result was requested.
12644                 */
12645                 if (toBool)
12646                     break;
12647             }
12648         } else if (seq->nodeNr > 0) {
12649             /*
12650             * Add to result set.
12651             */
12652             if (outSeq == NULL) {
12653                 outSeq = seq;
12654                 seq = NULL;
12655             } else {
12656                 outSeq = mergeAndClear(outSeq, seq, 0);
12657             }
12658         }
12659     }
12660
12661 error:
12662     if ((obj->boolval) && (obj->user != NULL)) {
12663         /*
12664         * QUESTION TODO: What does this do and why?
12665         * TODO: Do we have to do this also for the "error"
12666         * cleanup further down?
12667         */
12668         ctxt->value->boolval = 1;
12669         ctxt->value->user = obj->user;
12670         obj->user = NULL;
12671         obj->boolval = 0;
12672     }
12673     xmlXPathReleaseObject(xpctxt, obj);
12674
12675     /*
12676     * Ensure we return at least an emtpy set.
12677     */
12678     if (outSeq == NULL) {
12679         if ((seq != NULL) && (seq->nodeNr == 0))
12680             outSeq = seq;
12681         else
12682             outSeq = xmlXPathNodeSetCreate(NULL);
12683         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12684     }
12685     if ((seq != NULL) && (seq != outSeq)) {
12686          xmlXPathFreeNodeSet(seq);
12687     }
12688     /*
12689     * Hand over the result. Better to push the set also in
12690     * case of errors.
12691     */
12692     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12693     /*
12694     * Reset the context node.
12695     */
12696     xpctxt->node = oldContextNode;
12697     /*
12698     * When traversing the namespace axis in "toBool" mode, it's
12699     * possible that tmpNsList wasn't freed.
12700     */
12701     if (xpctxt->tmpNsList != NULL) {
12702         xmlFree(xpctxt->tmpNsList);
12703         xpctxt->tmpNsList = NULL;
12704     }
12705
12706 #ifdef DEBUG_STEP
12707     xmlGenericError(xmlGenericErrorContext,
12708         "\nExamined %d nodes, found %d nodes at that step\n",
12709         total, nbMatches);
12710 #endif
12711
12712     return(total);
12713 }
12714
12715 static int
12716 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12717                               xmlXPathStepOpPtr op, xmlNodePtr * first);
12718
12719 /**
12720  * xmlXPathCompOpEvalFirst:
12721  * @ctxt:  the XPath parser context with the compiled expression
12722  * @op:  an XPath compiled operation
12723  * @first:  the first elem found so far
12724  *
12725  * Evaluate the Precompiled XPath operation searching only the first
12726  * element in document order
12727  *
12728  * Returns the number of examined objects.
12729  */
12730 static int
12731 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12732                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12733 {
12734     int total = 0, cur;
12735     xmlXPathCompExprPtr comp;
12736     xmlXPathObjectPtr arg1, arg2;
12737
12738     CHECK_ERROR0;
12739     comp = ctxt->comp;
12740     switch (op->op) {
12741         case XPATH_OP_END:
12742             return (0);
12743         case XPATH_OP_UNION:
12744             total =
12745                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12746                                         first);
12747             CHECK_ERROR0;
12748             if ((ctxt->value != NULL)
12749                 && (ctxt->value->type == XPATH_NODESET)
12750                 && (ctxt->value->nodesetval != NULL)
12751                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12752                 /*
12753                  * limit tree traversing to first node in the result
12754                  */
12755                 /*
12756                 * OPTIMIZE TODO: This implicitely sorts
12757                 *  the result, even if not needed. E.g. if the argument
12758                 *  of the count() function, no sorting is needed.
12759                 * OPTIMIZE TODO: How do we know if the node-list wasn't
12760                 *  aready sorted?
12761                 */
12762                 if (ctxt->value->nodesetval->nodeNr > 1)
12763                     xmlXPathNodeSetSort(ctxt->value->nodesetval);
12764                 *first = ctxt->value->nodesetval->nodeTab[0];
12765             }
12766             cur =
12767                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12768                                         first);
12769             CHECK_ERROR0;
12770             CHECK_TYPE0(XPATH_NODESET);
12771             arg2 = valuePop(ctxt);
12772
12773             CHECK_TYPE0(XPATH_NODESET);
12774             arg1 = valuePop(ctxt);
12775
12776             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12777                                                     arg2->nodesetval);
12778             valuePush(ctxt, arg1);
12779             xmlXPathReleaseObject(ctxt->context, arg2);
12780             /* optimizer */
12781             if (total > cur)
12782                 xmlXPathCompSwap(op);
12783             return (total + cur);
12784         case XPATH_OP_ROOT:
12785             xmlXPathRoot(ctxt);
12786             return (0);
12787         case XPATH_OP_NODE:
12788             if (op->ch1 != -1)
12789                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12790             CHECK_ERROR0;
12791             if (op->ch2 != -1)
12792                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12793             CHECK_ERROR0;
12794             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12795                 ctxt->context->node));
12796             return (total);
12797         case XPATH_OP_RESET:
12798             if (op->ch1 != -1)
12799                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12800             CHECK_ERROR0;
12801             if (op->ch2 != -1)
12802                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12803             CHECK_ERROR0;
12804             ctxt->context->node = NULL;
12805             return (total);
12806         case XPATH_OP_COLLECT:{
12807                 if (op->ch1 == -1)
12808                     return (total);
12809
12810                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12811                 CHECK_ERROR0;
12812
12813                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12814                 return (total);
12815             }
12816         case XPATH_OP_VALUE:
12817             valuePush(ctxt,
12818                       xmlXPathCacheObjectCopy(ctxt->context,
12819                         (xmlXPathObjectPtr) op->value4));
12820             return (0);
12821         case XPATH_OP_SORT:
12822             if (op->ch1 != -1)
12823                 total +=
12824                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12825                                             first);
12826             CHECK_ERROR0;
12827             if ((ctxt->value != NULL)
12828                 && (ctxt->value->type == XPATH_NODESET)
12829                 && (ctxt->value->nodesetval != NULL)
12830                 && (ctxt->value->nodesetval->nodeNr > 1))
12831                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12832             return (total);
12833 #ifdef XP_OPTIMIZED_FILTER_FIRST
12834         case XPATH_OP_FILTER:
12835                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12836             return (total);
12837 #endif
12838         default:
12839             return (xmlXPathCompOpEval(ctxt, op));
12840     }
12841 }
12842
12843 /**
12844  * xmlXPathCompOpEvalLast:
12845  * @ctxt:  the XPath parser context with the compiled expression
12846  * @op:  an XPath compiled operation
12847  * @last:  the last elem found so far
12848  *
12849  * Evaluate the Precompiled XPath operation searching only the last
12850  * element in document order
12851  *
12852  * Returns the number of nodes traversed
12853  */
12854 static int
12855 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12856                        xmlNodePtr * last)
12857 {
12858     int total = 0, cur;
12859     xmlXPathCompExprPtr comp;
12860     xmlXPathObjectPtr arg1, arg2;
12861     xmlNodePtr bak;
12862     xmlDocPtr bakd;
12863     int pp;
12864     int cs;
12865
12866     CHECK_ERROR0;
12867     comp = ctxt->comp;
12868     switch (op->op) {
12869         case XPATH_OP_END:
12870             return (0);
12871         case XPATH_OP_UNION:
12872             bakd = ctxt->context->doc;
12873             bak = ctxt->context->node;
12874             pp = ctxt->context->proximityPosition;
12875             cs = ctxt->context->contextSize;
12876             total =
12877                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12878             CHECK_ERROR0;
12879             if ((ctxt->value != NULL)
12880                 && (ctxt->value->type == XPATH_NODESET)
12881                 && (ctxt->value->nodesetval != NULL)
12882                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12883                 /*
12884                  * limit tree traversing to first node in the result
12885                  */
12886                 if (ctxt->value->nodesetval->nodeNr > 1)
12887                     xmlXPathNodeSetSort(ctxt->value->nodesetval);
12888                 *last =
12889                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12890                                                      nodesetval->nodeNr -
12891                                                      1];
12892             }
12893             ctxt->context->doc = bakd;
12894             ctxt->context->node = bak;
12895             ctxt->context->proximityPosition = pp;
12896             ctxt->context->contextSize = cs;
12897             cur =
12898                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12899             CHECK_ERROR0;
12900             if ((ctxt->value != NULL)
12901                 && (ctxt->value->type == XPATH_NODESET)
12902                 && (ctxt->value->nodesetval != NULL)
12903                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12904             }
12905             CHECK_TYPE0(XPATH_NODESET);
12906             arg2 = valuePop(ctxt);
12907
12908             CHECK_TYPE0(XPATH_NODESET);
12909             arg1 = valuePop(ctxt);
12910
12911             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12912                                                     arg2->nodesetval);
12913             valuePush(ctxt, arg1);
12914             xmlXPathReleaseObject(ctxt->context, arg2);
12915             /* optimizer */
12916             if (total > cur)
12917                 xmlXPathCompSwap(op);
12918             return (total + cur);
12919         case XPATH_OP_ROOT:
12920             xmlXPathRoot(ctxt);
12921             return (0);
12922         case XPATH_OP_NODE:
12923             if (op->ch1 != -1)
12924                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12925             CHECK_ERROR0;
12926             if (op->ch2 != -1)
12927                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12928             CHECK_ERROR0;
12929             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12930                 ctxt->context->node));
12931             return (total);
12932         case XPATH_OP_RESET:
12933             if (op->ch1 != -1)
12934                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12935             CHECK_ERROR0;
12936             if (op->ch2 != -1)
12937                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12938             CHECK_ERROR0;
12939             ctxt->context->node = NULL;
12940             return (total);
12941         case XPATH_OP_COLLECT:{
12942                 if (op->ch1 == -1)
12943                     return (0);
12944
12945                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12946                 CHECK_ERROR0;
12947
12948                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12949                 return (total);
12950             }
12951         case XPATH_OP_VALUE:
12952             valuePush(ctxt,
12953                       xmlXPathCacheObjectCopy(ctxt->context,
12954                         (xmlXPathObjectPtr) op->value4));
12955             return (0);
12956         case XPATH_OP_SORT:
12957             if (op->ch1 != -1)
12958                 total +=
12959                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12960                                            last);
12961             CHECK_ERROR0;
12962             if ((ctxt->value != NULL)
12963                 && (ctxt->value->type == XPATH_NODESET)
12964                 && (ctxt->value->nodesetval != NULL)
12965                 && (ctxt->value->nodesetval->nodeNr > 1))
12966                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12967             return (total);
12968         default:
12969             return (xmlXPathCompOpEval(ctxt, op));
12970     }
12971 }
12972
12973 #ifdef XP_OPTIMIZED_FILTER_FIRST
12974 static int
12975 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12976                               xmlXPathStepOpPtr op, xmlNodePtr * first)
12977 {
12978     int total = 0;
12979     xmlXPathCompExprPtr comp;
12980     xmlXPathObjectPtr res;
12981     xmlXPathObjectPtr obj;
12982     xmlNodeSetPtr oldset;
12983     xmlNodePtr oldnode;
12984     xmlDocPtr oldDoc;
12985     int i;
12986
12987     CHECK_ERROR0;
12988     comp = ctxt->comp;
12989     /*
12990     * Optimization for ()[last()] selection i.e. the last elem
12991     */
12992     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12993         (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12994         (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12995         int f = comp->steps[op->ch2].ch1;
12996
12997         if ((f != -1) &&
12998             (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12999             (comp->steps[f].value5 == NULL) &&
13000             (comp->steps[f].value == 0) &&
13001             (comp->steps[f].value4 != NULL) &&
13002             (xmlStrEqual
13003             (comp->steps[f].value4, BAD_CAST "last"))) {
13004             xmlNodePtr last = NULL;
13005
13006             total +=
13007                 xmlXPathCompOpEvalLast(ctxt,
13008                     &comp->steps[op->ch1],
13009                     &last);
13010             CHECK_ERROR0;
13011             /*
13012             * The nodeset should be in document order,
13013             * Keep only the last value
13014             */
13015             if ((ctxt->value != NULL) &&
13016                 (ctxt->value->type == XPATH_NODESET) &&
13017                 (ctxt->value->nodesetval != NULL) &&
13018                 (ctxt->value->nodesetval->nodeTab != NULL) &&
13019                 (ctxt->value->nodesetval->nodeNr > 1)) {
13020                 ctxt->value->nodesetval->nodeTab[0] =
13021                     ctxt->value->nodesetval->nodeTab[ctxt->
13022                     value->
13023                     nodesetval->
13024                     nodeNr -
13025                     1];
13026                 ctxt->value->nodesetval->nodeNr = 1;
13027                 *first = *(ctxt->value->nodesetval->nodeTab);
13028             }
13029             return (total);
13030         }
13031     }
13032
13033     if (op->ch1 != -1)
13034         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13035     CHECK_ERROR0;
13036     if (op->ch2 == -1)
13037         return (total);
13038     if (ctxt->value == NULL)
13039         return (total);
13040
13041 #ifdef LIBXML_XPTR_ENABLED
13042     oldnode = ctxt->context->node;
13043     /*
13044     * Hum are we filtering the result of an XPointer expression
13045     */
13046     if (ctxt->value->type == XPATH_LOCATIONSET) {
13047         xmlXPathObjectPtr tmp = NULL;
13048         xmlLocationSetPtr newlocset = NULL;
13049         xmlLocationSetPtr oldlocset;
13050
13051         /*
13052         * Extract the old locset, and then evaluate the result of the
13053         * expression for all the element in the locset. use it to grow
13054         * up a new locset.
13055         */
13056         CHECK_TYPE0(XPATH_LOCATIONSET);
13057         obj = valuePop(ctxt);
13058         oldlocset = obj->user;
13059         ctxt->context->node = NULL;
13060
13061         if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13062             ctxt->context->contextSize = 0;
13063             ctxt->context->proximityPosition = 0;
13064             if (op->ch2 != -1)
13065                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13066             res = valuePop(ctxt);
13067             if (res != NULL) {
13068                 xmlXPathReleaseObject(ctxt->context, res);
13069             }
13070             valuePush(ctxt, obj);
13071             CHECK_ERROR0;
13072             return (total);
13073         }
13074         newlocset = xmlXPtrLocationSetCreate(NULL);
13075
13076         for (i = 0; i < oldlocset->locNr; i++) {
13077             /*
13078             * Run the evaluation with a node list made of a
13079             * single item in the nodelocset.
13080             */
13081             ctxt->context->node = oldlocset->locTab[i]->user;
13082             ctxt->context->contextSize = oldlocset->locNr;
13083             ctxt->context->proximityPosition = i + 1;
13084             if (tmp == NULL) {
13085                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13086                     ctxt->context->node);
13087             } else {
13088                 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13089                                              ctxt->context->node) < 0) {
13090                     ctxt->error = XPATH_MEMORY_ERROR;
13091                 }
13092             }
13093             valuePush(ctxt, tmp);
13094             if (op->ch2 != -1)
13095                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13096             if (ctxt->error != XPATH_EXPRESSION_OK) {
13097                 xmlXPathFreeObject(obj);
13098                 return(0);
13099             }
13100             /*
13101             * The result of the evaluation need to be tested to
13102             * decided whether the filter succeeded or not
13103             */
13104             res = valuePop(ctxt);
13105             if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13106                 xmlXPtrLocationSetAdd(newlocset,
13107                     xmlXPathCacheObjectCopy(ctxt->context,
13108                         oldlocset->locTab[i]));
13109             }
13110             /*
13111             * Cleanup
13112             */
13113             if (res != NULL) {
13114                 xmlXPathReleaseObject(ctxt->context, res);
13115             }
13116             if (ctxt->value == tmp) {
13117                 valuePop(ctxt);
13118                 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13119                 /*
13120                 * REVISIT TODO: Don't create a temporary nodeset
13121                 * for everly iteration.
13122                 */
13123                 /* OLD: xmlXPathFreeObject(res); */
13124             } else
13125                 tmp = NULL;
13126             ctxt->context->node = NULL;
13127             /*
13128             * Only put the first node in the result, then leave.
13129             */
13130             if (newlocset->locNr > 0) {
13131                 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13132                 break;
13133             }
13134         }
13135         if (tmp != NULL) {
13136             xmlXPathReleaseObject(ctxt->context, tmp);
13137         }
13138         /*
13139         * The result is used as the new evaluation locset.
13140         */
13141         xmlXPathReleaseObject(ctxt->context, obj);
13142         ctxt->context->node = NULL;
13143         ctxt->context->contextSize = -1;
13144         ctxt->context->proximityPosition = -1;
13145         valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13146         ctxt->context->node = oldnode;
13147         return (total);
13148     }
13149 #endif /* LIBXML_XPTR_ENABLED */
13150
13151     /*
13152     * Extract the old set, and then evaluate the result of the
13153     * expression for all the element in the set. use it to grow
13154     * up a new set.
13155     */
13156     CHECK_TYPE0(XPATH_NODESET);
13157     obj = valuePop(ctxt);
13158     oldset = obj->nodesetval;
13159
13160     oldnode = ctxt->context->node;
13161     oldDoc = ctxt->context->doc;
13162     ctxt->context->node = NULL;
13163
13164     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13165         ctxt->context->contextSize = 0;
13166         ctxt->context->proximityPosition = 0;
13167         /* QUESTION TODO: Why was this code commented out?
13168             if (op->ch2 != -1)
13169                 total +=
13170                     xmlXPathCompOpEval(ctxt,
13171                         &comp->steps[op->ch2]);
13172             CHECK_ERROR0;
13173             res = valuePop(ctxt);
13174             if (res != NULL)
13175                 xmlXPathFreeObject(res);
13176         */
13177         valuePush(ctxt, obj);
13178         ctxt->context->node = oldnode;
13179         CHECK_ERROR0;
13180     } else {
13181         xmlNodeSetPtr newset;
13182         xmlXPathObjectPtr tmp = NULL;
13183         /*
13184         * Initialize the new set.
13185         * Also set the xpath document in case things like
13186         * key() evaluation are attempted on the predicate
13187         */
13188         newset = xmlXPathNodeSetCreate(NULL);
13189         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13190
13191         for (i = 0; i < oldset->nodeNr; i++) {
13192             /*
13193             * Run the evaluation with a node list made of
13194             * a single item in the nodeset.
13195             */
13196             ctxt->context->node = oldset->nodeTab[i];
13197             if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13198                 (oldset->nodeTab[i]->doc != NULL))
13199                 ctxt->context->doc = oldset->nodeTab[i]->doc;
13200             if (tmp == NULL) {
13201                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13202                     ctxt->context->node);
13203             } else {
13204                 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13205                                              ctxt->context->node) < 0) {
13206                     ctxt->error = XPATH_MEMORY_ERROR;
13207                 }
13208             }
13209             valuePush(ctxt, tmp);
13210             ctxt->context->contextSize = oldset->nodeNr;
13211             ctxt->context->proximityPosition = i + 1;
13212             if (op->ch2 != -1)
13213                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13214             if (ctxt->error != XPATH_EXPRESSION_OK) {
13215                 xmlXPathFreeNodeSet(newset);
13216                 xmlXPathFreeObject(obj);
13217                 return(0);
13218             }
13219             /*
13220             * The result of the evaluation needs to be tested to
13221             * decide whether the filter succeeded or not
13222             */
13223             res = valuePop(ctxt);
13224             if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13225                 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13226                     ctxt->error = XPATH_MEMORY_ERROR;
13227             }
13228             /*
13229             * Cleanup
13230             */
13231             if (res != NULL) {
13232                 xmlXPathReleaseObject(ctxt->context, res);
13233             }
13234             if (ctxt->value == tmp) {
13235                 valuePop(ctxt);
13236                 /*
13237                 * Don't free the temporary nodeset
13238                 * in order to avoid massive recreation inside this
13239                 * loop.
13240                 */
13241                 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13242             } else
13243                 tmp = NULL;
13244             ctxt->context->node = NULL;
13245             /*
13246             * Only put the first node in the result, then leave.
13247             */
13248             if (newset->nodeNr > 0) {
13249                 *first = *(newset->nodeTab);
13250                 break;
13251             }
13252         }
13253         if (tmp != NULL) {
13254             xmlXPathReleaseObject(ctxt->context, tmp);
13255         }
13256         /*
13257         * The result is used as the new evaluation set.
13258         */
13259         xmlXPathReleaseObject(ctxt->context, obj);
13260         ctxt->context->node = NULL;
13261         ctxt->context->contextSize = -1;
13262         ctxt->context->proximityPosition = -1;
13263         /* may want to move this past the '}' later */
13264         ctxt->context->doc = oldDoc;
13265         valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13266     }
13267     ctxt->context->node = oldnode;
13268     return(total);
13269 }
13270 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13271
13272 /**
13273  * xmlXPathCompOpEval:
13274  * @ctxt:  the XPath parser context with the compiled expression
13275  * @op:  an XPath compiled operation
13276  *
13277  * Evaluate the Precompiled XPath operation
13278  * Returns the number of nodes traversed
13279  */
13280 static int
13281 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13282 {
13283     int total = 0;
13284     int equal, ret;
13285     xmlXPathCompExprPtr comp;
13286     xmlXPathObjectPtr arg1, arg2;
13287     xmlNodePtr bak;
13288     xmlDocPtr bakd;
13289     int pp;
13290     int cs;
13291
13292     CHECK_ERROR0;
13293     comp = ctxt->comp;
13294     switch (op->op) {
13295         case XPATH_OP_END:
13296             return (0);
13297         case XPATH_OP_AND:
13298             bakd = ctxt->context->doc;
13299             bak = ctxt->context->node;
13300             pp = ctxt->context->proximityPosition;
13301             cs = ctxt->context->contextSize;
13302             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13303             CHECK_ERROR0;
13304             xmlXPathBooleanFunction(ctxt, 1);
13305             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13306                 return (total);
13307             arg2 = valuePop(ctxt);
13308             ctxt->context->doc = bakd;
13309             ctxt->context->node = bak;
13310             ctxt->context->proximityPosition = pp;
13311             ctxt->context->contextSize = cs;
13312             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13313             if (ctxt->error) {
13314                 xmlXPathFreeObject(arg2);
13315                 return(0);
13316             }
13317             xmlXPathBooleanFunction(ctxt, 1);
13318             arg1 = valuePop(ctxt);
13319             arg1->boolval &= arg2->boolval;
13320             valuePush(ctxt, arg1);
13321             xmlXPathReleaseObject(ctxt->context, arg2);
13322             return (total);
13323         case XPATH_OP_OR:
13324             bakd = ctxt->context->doc;
13325             bak = ctxt->context->node;
13326             pp = ctxt->context->proximityPosition;
13327             cs = ctxt->context->contextSize;
13328             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13329             CHECK_ERROR0;
13330             xmlXPathBooleanFunction(ctxt, 1);
13331             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13332                 return (total);
13333             arg2 = valuePop(ctxt);
13334             ctxt->context->doc = bakd;
13335             ctxt->context->node = bak;
13336             ctxt->context->proximityPosition = pp;
13337             ctxt->context->contextSize = cs;
13338             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13339             if (ctxt->error) {
13340                 xmlXPathFreeObject(arg2);
13341                 return(0);
13342             }
13343             xmlXPathBooleanFunction(ctxt, 1);
13344             arg1 = valuePop(ctxt);
13345             arg1->boolval |= arg2->boolval;
13346             valuePush(ctxt, arg1);
13347             xmlXPathReleaseObject(ctxt->context, arg2);
13348             return (total);
13349         case XPATH_OP_EQUAL:
13350             bakd = ctxt->context->doc;
13351             bak = ctxt->context->node;
13352             pp = ctxt->context->proximityPosition;
13353             cs = ctxt->context->contextSize;
13354             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13355             CHECK_ERROR0;
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             CHECK_ERROR0;
13362             if (op->value)
13363                 equal = xmlXPathEqualValues(ctxt);
13364             else
13365                 equal = xmlXPathNotEqualValues(ctxt);
13366             valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13367             return (total);
13368         case XPATH_OP_CMP:
13369             bakd = ctxt->context->doc;
13370             bak = ctxt->context->node;
13371             pp = ctxt->context->proximityPosition;
13372             cs = ctxt->context->contextSize;
13373             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13374             CHECK_ERROR0;
13375             ctxt->context->doc = bakd;
13376             ctxt->context->node = bak;
13377             ctxt->context->proximityPosition = pp;
13378             ctxt->context->contextSize = cs;
13379             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13380             CHECK_ERROR0;
13381             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13382             valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13383             return (total);
13384         case XPATH_OP_PLUS:
13385             bakd = ctxt->context->doc;
13386             bak = ctxt->context->node;
13387             pp = ctxt->context->proximityPosition;
13388             cs = ctxt->context->contextSize;
13389             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13390             CHECK_ERROR0;
13391             if (op->ch2 != -1) {
13392                 ctxt->context->doc = bakd;
13393                 ctxt->context->node = bak;
13394                 ctxt->context->proximityPosition = pp;
13395                 ctxt->context->contextSize = cs;
13396                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13397             }
13398             CHECK_ERROR0;
13399             if (op->value == 0)
13400                 xmlXPathSubValues(ctxt);
13401             else if (op->value == 1)
13402                 xmlXPathAddValues(ctxt);
13403             else if (op->value == 2)
13404                 xmlXPathValueFlipSign(ctxt);
13405             else if (op->value == 3) {
13406                 CAST_TO_NUMBER;
13407                 CHECK_TYPE0(XPATH_NUMBER);
13408             }
13409             return (total);
13410         case XPATH_OP_MULT:
13411             bakd = ctxt->context->doc;
13412             bak = ctxt->context->node;
13413             pp = ctxt->context->proximityPosition;
13414             cs = ctxt->context->contextSize;
13415             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13416             CHECK_ERROR0;
13417             ctxt->context->doc = bakd;
13418             ctxt->context->node = bak;
13419             ctxt->context->proximityPosition = pp;
13420             ctxt->context->contextSize = cs;
13421             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13422             CHECK_ERROR0;
13423             if (op->value == 0)
13424                 xmlXPathMultValues(ctxt);
13425             else if (op->value == 1)
13426                 xmlXPathDivValues(ctxt);
13427             else if (op->value == 2)
13428                 xmlXPathModValues(ctxt);
13429             return (total);
13430         case XPATH_OP_UNION:
13431             bakd = ctxt->context->doc;
13432             bak = ctxt->context->node;
13433             pp = ctxt->context->proximityPosition;
13434             cs = ctxt->context->contextSize;
13435             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13436             CHECK_ERROR0;
13437             ctxt->context->doc = bakd;
13438             ctxt->context->node = bak;
13439             ctxt->context->proximityPosition = pp;
13440             ctxt->context->contextSize = cs;
13441             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13442             CHECK_ERROR0;
13443             CHECK_TYPE0(XPATH_NODESET);
13444             arg2 = valuePop(ctxt);
13445
13446             CHECK_TYPE0(XPATH_NODESET);
13447             arg1 = valuePop(ctxt);
13448
13449             if ((arg1->nodesetval == NULL) ||
13450                 ((arg2->nodesetval != NULL) &&
13451                  (arg2->nodesetval->nodeNr != 0)))
13452             {
13453                 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13454                                                         arg2->nodesetval);
13455             }
13456
13457             valuePush(ctxt, arg1);
13458             xmlXPathReleaseObject(ctxt->context, arg2);
13459             return (total);
13460         case XPATH_OP_ROOT:
13461             xmlXPathRoot(ctxt);
13462             return (total);
13463         case XPATH_OP_NODE:
13464             if (op->ch1 != -1)
13465                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13466             CHECK_ERROR0;
13467             if (op->ch2 != -1)
13468                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13469             CHECK_ERROR0;
13470             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13471                 ctxt->context->node));
13472             return (total);
13473         case XPATH_OP_RESET:
13474             if (op->ch1 != -1)
13475                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13476             CHECK_ERROR0;
13477             if (op->ch2 != -1)
13478                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13479             CHECK_ERROR0;
13480             ctxt->context->node = NULL;
13481             return (total);
13482         case XPATH_OP_COLLECT:{
13483                 if (op->ch1 == -1)
13484                     return (total);
13485
13486                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13487                 CHECK_ERROR0;
13488
13489                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13490                 return (total);
13491             }
13492         case XPATH_OP_VALUE:
13493             valuePush(ctxt,
13494                       xmlXPathCacheObjectCopy(ctxt->context,
13495                         (xmlXPathObjectPtr) op->value4));
13496             return (total);
13497         case XPATH_OP_VARIABLE:{
13498                 xmlXPathObjectPtr val;
13499
13500                 if (op->ch1 != -1)
13501                     total +=
13502                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13503                 if (op->value5 == NULL) {
13504                     val = xmlXPathVariableLookup(ctxt->context, op->value4);
13505                     if (val == NULL) {
13506                         ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13507                         return(0);
13508                     }
13509                     valuePush(ctxt, val);
13510                 } else {
13511                     const xmlChar *URI;
13512
13513                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13514                     if (URI == NULL) {
13515                         xmlGenericError(xmlGenericErrorContext,
13516             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13517                                     (char *) op->value4, (char *)op->value5);
13518                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13519                         return (total);
13520                     }
13521                     val = xmlXPathVariableLookupNS(ctxt->context,
13522                                                        op->value4, URI);
13523                     if (val == NULL) {
13524                         ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13525                         return(0);
13526                     }
13527                     valuePush(ctxt, val);
13528                 }
13529                 return (total);
13530             }
13531         case XPATH_OP_FUNCTION:{
13532                 xmlXPathFunction func;
13533                 const xmlChar *oldFunc, *oldFuncURI;
13534                 int i;
13535                 int frame;
13536
13537                 frame = xmlXPathSetFrame(ctxt);
13538                 if (op->ch1 != -1) {
13539                     total +=
13540                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13541                     if (ctxt->error != XPATH_EXPRESSION_OK) {
13542                         xmlXPathPopFrame(ctxt, frame);
13543                         return (total);
13544                     }
13545                 }
13546                 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13547                     xmlGenericError(xmlGenericErrorContext,
13548                             "xmlXPathCompOpEval: parameter error\n");
13549                     ctxt->error = XPATH_INVALID_OPERAND;
13550                     xmlXPathPopFrame(ctxt, frame);
13551                     return (total);
13552                 }
13553                 for (i = 0; i < op->value; i++) {
13554                     if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13555                         xmlGenericError(xmlGenericErrorContext,
13556                                 "xmlXPathCompOpEval: parameter error\n");
13557                         ctxt->error = XPATH_INVALID_OPERAND;
13558                         xmlXPathPopFrame(ctxt, frame);
13559                         return (total);
13560                     }
13561                 }
13562                 if (op->cache != NULL)
13563                     XML_CAST_FPTR(func) = op->cache;
13564                 else {
13565                     const xmlChar *URI = NULL;
13566
13567                     if (op->value5 == NULL)
13568                         func =
13569                             xmlXPathFunctionLookup(ctxt->context,
13570                                                    op->value4);
13571                     else {
13572                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13573                         if (URI == NULL) {
13574                             xmlGenericError(xmlGenericErrorContext,
13575             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13576                                     (char *)op->value4, (char *)op->value5);
13577                             xmlXPathPopFrame(ctxt, frame);
13578                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13579                             return (total);
13580                         }
13581                         func = xmlXPathFunctionLookupNS(ctxt->context,
13582                                                         op->value4, URI);
13583                     }
13584                     if (func == NULL) {
13585                         xmlGenericError(xmlGenericErrorContext,
13586                                 "xmlXPathCompOpEval: function %s not found\n",
13587                                         (char *)op->value4);
13588                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13589                     }
13590                     op->cache = XML_CAST_FPTR(func);
13591                     op->cacheURI = (void *) URI;
13592                 }
13593                 oldFunc = ctxt->context->function;
13594                 oldFuncURI = ctxt->context->functionURI;
13595                 ctxt->context->function = op->value4;
13596                 ctxt->context->functionURI = op->cacheURI;
13597                 func(ctxt, op->value);
13598                 ctxt->context->function = oldFunc;
13599                 ctxt->context->functionURI = oldFuncURI;
13600                 xmlXPathPopFrame(ctxt, frame);
13601                 return (total);
13602             }
13603         case XPATH_OP_ARG:
13604             bakd = ctxt->context->doc;
13605             bak = ctxt->context->node;
13606             pp = ctxt->context->proximityPosition;
13607             cs = ctxt->context->contextSize;
13608             if (op->ch1 != -1) {
13609                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13610                 ctxt->context->contextSize = cs;
13611                 ctxt->context->proximityPosition = pp;
13612                 ctxt->context->node = bak;
13613                 ctxt->context->doc = bakd;
13614                 CHECK_ERROR0;
13615             }
13616             if (op->ch2 != -1) {
13617                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13618                 ctxt->context->contextSize = cs;
13619                 ctxt->context->proximityPosition = pp;
13620                 ctxt->context->node = bak;
13621                 ctxt->context->doc = bakd;
13622                 CHECK_ERROR0;
13623             }
13624             return (total);
13625         case XPATH_OP_PREDICATE:
13626         case XPATH_OP_FILTER:{
13627                 xmlXPathObjectPtr res;
13628                 xmlXPathObjectPtr obj, tmp;
13629                 xmlNodeSetPtr newset = NULL;
13630                 xmlNodeSetPtr oldset;
13631                 xmlNodePtr oldnode;
13632                 xmlDocPtr oldDoc;
13633                 int i;
13634
13635                 /*
13636                  * Optimization for ()[1] selection i.e. the first elem
13637                  */
13638                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13639 #ifdef XP_OPTIMIZED_FILTER_FIRST
13640                     /*
13641                     * FILTER TODO: Can we assume that the inner processing
13642                     *  will result in an ordered list if we have an
13643                     *  XPATH_OP_FILTER?
13644                     *  What about an additional field or flag on
13645                     *  xmlXPathObject like @sorted ? This way we wouln'd need
13646                     *  to assume anything, so it would be more robust and
13647                     *  easier to optimize.
13648                     */
13649                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13650                      (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13651 #else
13652                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13653 #endif
13654                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13655                     xmlXPathObjectPtr val;
13656
13657                     val = comp->steps[op->ch2].value4;
13658                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13659                         (val->floatval == 1.0)) {
13660                         xmlNodePtr first = NULL;
13661
13662                         total +=
13663                             xmlXPathCompOpEvalFirst(ctxt,
13664                                                     &comp->steps[op->ch1],
13665                                                     &first);
13666                         CHECK_ERROR0;
13667                         /*
13668                          * The nodeset should be in document order,
13669                          * Keep only the first value
13670                          */
13671                         if ((ctxt->value != NULL) &&
13672                             (ctxt->value->type == XPATH_NODESET) &&
13673                             (ctxt->value->nodesetval != NULL) &&
13674                             (ctxt->value->nodesetval->nodeNr > 1))
13675                             ctxt->value->nodesetval->nodeNr = 1;
13676                         return (total);
13677                     }
13678                 }
13679                 /*
13680                  * Optimization for ()[last()] selection i.e. the last elem
13681                  */
13682                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13683                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13684                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13685                     int f = comp->steps[op->ch2].ch1;
13686
13687                     if ((f != -1) &&
13688                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13689                         (comp->steps[f].value5 == NULL) &&
13690                         (comp->steps[f].value == 0) &&
13691                         (comp->steps[f].value4 != NULL) &&
13692                         (xmlStrEqual
13693                          (comp->steps[f].value4, BAD_CAST "last"))) {
13694                         xmlNodePtr last = NULL;
13695
13696                         total +=
13697                             xmlXPathCompOpEvalLast(ctxt,
13698                                                    &comp->steps[op->ch1],
13699                                                    &last);
13700                         CHECK_ERROR0;
13701                         /*
13702                          * The nodeset should be in document order,
13703                          * Keep only the last value
13704                          */
13705                         if ((ctxt->value != NULL) &&
13706                             (ctxt->value->type == XPATH_NODESET) &&
13707                             (ctxt->value->nodesetval != NULL) &&
13708                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13709                             (ctxt->value->nodesetval->nodeNr > 1)) {
13710                             ctxt->value->nodesetval->nodeTab[0] =
13711                                 ctxt->value->nodesetval->nodeTab[ctxt->
13712                                                                  value->
13713                                                                  nodesetval->
13714                                                                  nodeNr -
13715                                                                  1];
13716                             ctxt->value->nodesetval->nodeNr = 1;
13717                         }
13718                         return (total);
13719                     }
13720                 }
13721                 /*
13722                 * Process inner predicates first.
13723                 * Example "index[parent::book][1]":
13724                 * ...
13725                 *   PREDICATE   <-- we are here "[1]"
13726                 *     PREDICATE <-- process "[parent::book]" first
13727                 *       SORT
13728                 *         COLLECT  'parent' 'name' 'node' book
13729                 *           NODE
13730                 *     ELEM Object is a number : 1
13731                 */
13732                 if (op->ch1 != -1)
13733                     total +=
13734                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13735                 CHECK_ERROR0;
13736                 if (op->ch2 == -1)
13737                     return (total);
13738                 if (ctxt->value == NULL)
13739                     return (total);
13740
13741                 oldnode = ctxt->context->node;
13742
13743 #ifdef LIBXML_XPTR_ENABLED
13744                 /*
13745                  * Hum are we filtering the result of an XPointer expression
13746                  */
13747                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13748                     xmlLocationSetPtr newlocset = NULL;
13749                     xmlLocationSetPtr oldlocset;
13750
13751                     /*
13752                      * Extract the old locset, and then evaluate the result of the
13753                      * expression for all the element in the locset. use it to grow
13754                      * up a new locset.
13755                      */
13756                     CHECK_TYPE0(XPATH_LOCATIONSET);
13757                     obj = valuePop(ctxt);
13758                     oldlocset = obj->user;
13759                     ctxt->context->node = NULL;
13760
13761                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13762                         ctxt->context->contextSize = 0;
13763                         ctxt->context->proximityPosition = 0;
13764                         if (op->ch2 != -1)
13765                             total +=
13766                                 xmlXPathCompOpEval(ctxt,
13767                                                    &comp->steps[op->ch2]);
13768                         res = valuePop(ctxt);
13769                         if (res != NULL) {
13770                             xmlXPathReleaseObject(ctxt->context, res);
13771                         }
13772                         valuePush(ctxt, obj);
13773                         CHECK_ERROR0;
13774                         return (total);
13775                     }
13776                     newlocset = xmlXPtrLocationSetCreate(NULL);
13777
13778                     for (i = 0; i < oldlocset->locNr; i++) {
13779                         /*
13780                          * Run the evaluation with a node list made of a
13781                          * single item in the nodelocset.
13782                          */
13783                         ctxt->context->node = oldlocset->locTab[i]->user;
13784                         ctxt->context->contextSize = oldlocset->locNr;
13785                         ctxt->context->proximityPosition = i + 1;
13786                         tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13787                             ctxt->context->node);
13788                         valuePush(ctxt, tmp);
13789
13790                         if (op->ch2 != -1)
13791                             total +=
13792                                 xmlXPathCompOpEval(ctxt,
13793                                                    &comp->steps[op->ch2]);
13794                         if (ctxt->error != XPATH_EXPRESSION_OK) {
13795                             xmlXPathFreeObject(obj);
13796                             return(0);
13797                         }
13798
13799                         /*
13800                          * The result of the evaluation need to be tested to
13801                          * decided whether the filter succeeded or not
13802                          */
13803                         res = valuePop(ctxt);
13804                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13805                             xmlXPtrLocationSetAdd(newlocset,
13806                                                   xmlXPathObjectCopy
13807                                                   (oldlocset->locTab[i]));
13808                         }
13809
13810                         /*
13811                          * Cleanup
13812                          */
13813                         if (res != NULL) {
13814                             xmlXPathReleaseObject(ctxt->context, res);
13815                         }
13816                         if (ctxt->value == tmp) {
13817                             res = valuePop(ctxt);
13818                             xmlXPathReleaseObject(ctxt->context, res);
13819                         }
13820
13821                         ctxt->context->node = NULL;
13822                     }
13823
13824                     /*
13825                      * The result is used as the new evaluation locset.
13826                      */
13827                     xmlXPathReleaseObject(ctxt->context, obj);
13828                     ctxt->context->node = NULL;
13829                     ctxt->context->contextSize = -1;
13830                     ctxt->context->proximityPosition = -1;
13831                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13832                     ctxt->context->node = oldnode;
13833                     return (total);
13834                 }
13835 #endif /* LIBXML_XPTR_ENABLED */
13836
13837                 /*
13838                  * Extract the old set, and then evaluate the result of the
13839                  * expression for all the element in the set. use it to grow
13840                  * up a new set.
13841                  */
13842                 CHECK_TYPE0(XPATH_NODESET);
13843                 obj = valuePop(ctxt);
13844                 oldset = obj->nodesetval;
13845
13846                 oldnode = ctxt->context->node;
13847                 oldDoc = ctxt->context->doc;
13848                 ctxt->context->node = NULL;
13849
13850                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13851                     ctxt->context->contextSize = 0;
13852                     ctxt->context->proximityPosition = 0;
13853 /*
13854                     if (op->ch2 != -1)
13855                         total +=
13856                             xmlXPathCompOpEval(ctxt,
13857                                                &comp->steps[op->ch2]);
13858                     CHECK_ERROR0;
13859                     res = valuePop(ctxt);
13860                     if (res != NULL)
13861                         xmlXPathFreeObject(res);
13862 */
13863                     valuePush(ctxt, obj);
13864                     ctxt->context->node = oldnode;
13865                     CHECK_ERROR0;
13866                 } else {
13867                     tmp = NULL;
13868                     /*
13869                      * Initialize the new set.
13870                      * Also set the xpath document in case things like
13871                      * key() evaluation are attempted on the predicate
13872                      */
13873                     newset = xmlXPathNodeSetCreate(NULL);
13874                     /*
13875                     * SPEC XPath 1.0:
13876                     *  "For each node in the node-set to be filtered, the
13877                     *  PredicateExpr is evaluated with that node as the
13878                     *  context node, with the number of nodes in the
13879                     *  node-set as the context size, and with the proximity
13880                     *  position of the node in the node-set with respect to
13881                     *  the axis as the context position;"
13882                     * @oldset is the node-set" to be filtered.
13883                     *
13884                     * SPEC XPath 1.0:
13885                     *  "only predicates change the context position and
13886                     *  context size (see [2.4 Predicates])."
13887                     * Example:
13888                     *   node-set  context pos
13889                     *    nA         1
13890                     *    nB         2
13891                     *    nC         3
13892                     *   After applying predicate [position() > 1] :
13893                     *   node-set  context pos
13894                     *    nB         1
13895                     *    nC         2
13896                     *
13897                     * removed the first node in the node-set, then
13898                     * the context position of the
13899                     */
13900                     for (i = 0; i < oldset->nodeNr; i++) {
13901                         /*
13902                          * Run the evaluation with a node list made of
13903                          * a single item in the nodeset.
13904                          */
13905                         ctxt->context->node = oldset->nodeTab[i];
13906                         if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13907                             (oldset->nodeTab[i]->doc != NULL))
13908                             ctxt->context->doc = oldset->nodeTab[i]->doc;
13909                         if (tmp == NULL) {
13910                             tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13911                                 ctxt->context->node);
13912                         } else {
13913                             if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13914                                                ctxt->context->node) < 0) {
13915                                 ctxt->error = XPATH_MEMORY_ERROR;
13916                             }
13917                         }
13918                         valuePush(ctxt, tmp);
13919                         ctxt->context->contextSize = oldset->nodeNr;
13920                         ctxt->context->proximityPosition = i + 1;
13921                         /*
13922                         * Evaluate the predicate against the context node.
13923                         * Can/should we optimize position() predicates
13924                         * here (e.g. "[1]")?
13925                         */
13926                         if (op->ch2 != -1)
13927                             total +=
13928                                 xmlXPathCompOpEval(ctxt,
13929                                                    &comp->steps[op->ch2]);
13930                         if (ctxt->error != XPATH_EXPRESSION_OK) {
13931                             xmlXPathFreeNodeSet(newset);
13932                             xmlXPathFreeObject(obj);
13933                             return(0);
13934                         }
13935
13936                         /*
13937                          * The result of the evaluation needs to be tested to
13938                          * decide whether the filter succeeded or not
13939                          */
13940                         /*
13941                         * OPTIMIZE TODO: Can we use
13942                         * xmlXPathNodeSetAdd*Unique()* instead?
13943                         */
13944                         res = valuePop(ctxt);
13945                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13946                             if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13947                                 < 0)
13948                                 ctxt->error = XPATH_MEMORY_ERROR;
13949                         }
13950
13951                         /*
13952                          * Cleanup
13953                          */
13954                         if (res != NULL) {
13955                             xmlXPathReleaseObject(ctxt->context, res);
13956                         }
13957                         if (ctxt->value == tmp) {
13958                             valuePop(ctxt);
13959                             xmlXPathNodeSetClear(tmp->nodesetval, 1);
13960                             /*
13961                             * Don't free the temporary nodeset
13962                             * in order to avoid massive recreation inside this
13963                             * loop.
13964                             */
13965                         } else
13966                             tmp = NULL;
13967                         ctxt->context->node = NULL;
13968                     }
13969                     if (tmp != NULL)
13970                         xmlXPathReleaseObject(ctxt->context, tmp);
13971                     /*
13972                      * The result is used as the new evaluation set.
13973                      */
13974                     xmlXPathReleaseObject(ctxt->context, obj);
13975                     ctxt->context->node = NULL;
13976                     ctxt->context->contextSize = -1;
13977                     ctxt->context->proximityPosition = -1;
13978                     /* may want to move this past the '}' later */
13979                     ctxt->context->doc = oldDoc;
13980                     valuePush(ctxt,
13981                         xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13982                 }
13983                 ctxt->context->node = oldnode;
13984                 return (total);
13985             }
13986         case XPATH_OP_SORT:
13987             if (op->ch1 != -1)
13988                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13989             CHECK_ERROR0;
13990             if ((ctxt->value != NULL) &&
13991                 (ctxt->value->type == XPATH_NODESET) &&
13992                 (ctxt->value->nodesetval != NULL) &&
13993                 (ctxt->value->nodesetval->nodeNr > 1))
13994             {
13995                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13996             }
13997             return (total);
13998 #ifdef LIBXML_XPTR_ENABLED
13999         case XPATH_OP_RANGETO:{
14000                 xmlXPathObjectPtr range;
14001                 xmlXPathObjectPtr res, obj;
14002                 xmlXPathObjectPtr tmp;
14003                 xmlLocationSetPtr newlocset = NULL;
14004                     xmlLocationSetPtr oldlocset;
14005                 xmlNodeSetPtr oldset;
14006                 int i, j;
14007
14008                 if (op->ch1 != -1)
14009                     total +=
14010                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
14011                 if (op->ch2 == -1)
14012                     return (total);
14013
14014                 if (ctxt->value->type == XPATH_LOCATIONSET) {
14015                     /*
14016                      * Extract the old locset, and then evaluate the result of the
14017                      * expression for all the element in the locset. use it to grow
14018                      * up a new locset.
14019                      */
14020                     CHECK_TYPE0(XPATH_LOCATIONSET);
14021                     obj = valuePop(ctxt);
14022                     oldlocset = obj->user;
14023
14024                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
14025                         ctxt->context->node = NULL;
14026                         ctxt->context->contextSize = 0;
14027                         ctxt->context->proximityPosition = 0;
14028                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
14029                         res = valuePop(ctxt);
14030                         if (res != NULL) {
14031                             xmlXPathReleaseObject(ctxt->context, res);
14032                         }
14033                         valuePush(ctxt, obj);
14034                         CHECK_ERROR0;
14035                         return (total);
14036                     }
14037                     newlocset = xmlXPtrLocationSetCreate(NULL);
14038
14039                     for (i = 0; i < oldlocset->locNr; i++) {
14040                         /*
14041                          * Run the evaluation with a node list made of a
14042                          * single item in the nodelocset.
14043                          */
14044                         ctxt->context->node = oldlocset->locTab[i]->user;
14045                         ctxt->context->contextSize = oldlocset->locNr;
14046                         ctxt->context->proximityPosition = i + 1;
14047                         tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14048                             ctxt->context->node);
14049                         valuePush(ctxt, tmp);
14050
14051                         if (op->ch2 != -1)
14052                             total +=
14053                                 xmlXPathCompOpEval(ctxt,
14054                                                    &comp->steps[op->ch2]);
14055                         if (ctxt->error != XPATH_EXPRESSION_OK) {
14056                             xmlXPathFreeObject(obj);
14057                             return(0);
14058                         }
14059
14060                         res = valuePop(ctxt);
14061                         if (res->type == XPATH_LOCATIONSET) {
14062                             xmlLocationSetPtr rloc =
14063                                 (xmlLocationSetPtr)res->user;
14064                             for (j=0; j<rloc->locNr; j++) {
14065                                 range = xmlXPtrNewRange(
14066                                   oldlocset->locTab[i]->user,
14067                                   oldlocset->locTab[i]->index,
14068                                   rloc->locTab[j]->user2,
14069                                   rloc->locTab[j]->index2);
14070                                 if (range != NULL) {
14071                                     xmlXPtrLocationSetAdd(newlocset, range);
14072                                 }
14073                             }
14074                         } else {
14075                             range = xmlXPtrNewRangeNodeObject(
14076                                 (xmlNodePtr)oldlocset->locTab[i]->user, res);
14077                             if (range != NULL) {
14078                                 xmlXPtrLocationSetAdd(newlocset,range);
14079                             }
14080                         }
14081
14082                         /*
14083                          * Cleanup
14084                          */
14085                         if (res != NULL) {
14086                             xmlXPathReleaseObject(ctxt->context, res);
14087                         }
14088                         if (ctxt->value == tmp) {
14089                             res = valuePop(ctxt);
14090                             xmlXPathReleaseObject(ctxt->context, res);
14091                         }
14092
14093                         ctxt->context->node = NULL;
14094                     }
14095                 } else {        /* Not a location set */
14096                     CHECK_TYPE0(XPATH_NODESET);
14097                     obj = valuePop(ctxt);
14098                     oldset = obj->nodesetval;
14099                     ctxt->context->node = NULL;
14100
14101                     newlocset = xmlXPtrLocationSetCreate(NULL);
14102
14103                     if (oldset != NULL) {
14104                         for (i = 0; i < oldset->nodeNr; i++) {
14105                             /*
14106                              * Run the evaluation with a node list made of a single item
14107                              * in the nodeset.
14108                              */
14109                             ctxt->context->node = oldset->nodeTab[i];
14110                             /*
14111                             * OPTIMIZE TODO: Avoid recreation for every iteration.
14112                             */
14113                             tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14114                                 ctxt->context->node);
14115                             valuePush(ctxt, tmp);
14116
14117                             if (op->ch2 != -1)
14118                                 total +=
14119                                     xmlXPathCompOpEval(ctxt,
14120                                                    &comp->steps[op->ch2]);
14121                             if (ctxt->error != XPATH_EXPRESSION_OK) {
14122                                 xmlXPathFreeObject(obj);
14123                                 return(0);
14124                             }
14125
14126                             res = valuePop(ctxt);
14127                             range =
14128                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14129                                                       res);
14130                             if (range != NULL) {
14131                                 xmlXPtrLocationSetAdd(newlocset, range);
14132                             }
14133
14134                             /*
14135                              * Cleanup
14136                              */
14137                             if (res != NULL) {
14138                                 xmlXPathReleaseObject(ctxt->context, res);
14139                             }
14140                             if (ctxt->value == tmp) {
14141                                 res = valuePop(ctxt);
14142                                 xmlXPathReleaseObject(ctxt->context, res);
14143                             }
14144
14145                             ctxt->context->node = NULL;
14146                         }
14147                     }
14148                 }
14149
14150                 /*
14151                  * The result is used as the new evaluation set.
14152                  */
14153                 xmlXPathReleaseObject(ctxt->context, obj);
14154                 ctxt->context->node = NULL;
14155                 ctxt->context->contextSize = -1;
14156                 ctxt->context->proximityPosition = -1;
14157                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14158                 return (total);
14159             }
14160 #endif /* LIBXML_XPTR_ENABLED */
14161     }
14162     xmlGenericError(xmlGenericErrorContext,
14163                     "XPath: unknown precompiled operation %d\n", op->op);
14164     ctxt->error = XPATH_INVALID_OPERAND;
14165     return (total);
14166 }
14167
14168 /**
14169  * xmlXPathCompOpEvalToBoolean:
14170  * @ctxt:  the XPath parser context
14171  *
14172  * Evaluates if the expression evaluates to true.
14173  *
14174  * Returns 1 if true, 0 if false and -1 on API or internal errors.
14175  */
14176 static int
14177 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14178                             xmlXPathStepOpPtr op,
14179                             int isPredicate)
14180 {
14181     xmlXPathObjectPtr resObj = NULL;
14182
14183 start:
14184     /* comp = ctxt->comp; */
14185     switch (op->op) {
14186         case XPATH_OP_END:
14187             return (0);
14188         case XPATH_OP_VALUE:
14189             resObj = (xmlXPathObjectPtr) op->value4;
14190             if (isPredicate)
14191                 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14192             return(xmlXPathCastToBoolean(resObj));
14193         case XPATH_OP_SORT:
14194             /*
14195             * We don't need sorting for boolean results. Skip this one.
14196             */
14197             if (op->ch1 != -1) {
14198                 op = &ctxt->comp->steps[op->ch1];
14199                 goto start;
14200             }
14201             return(0);
14202         case XPATH_OP_COLLECT:
14203             if (op->ch1 == -1)
14204                 return(0);
14205
14206             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14207             if (ctxt->error != XPATH_EXPRESSION_OK)
14208                 return(-1);
14209
14210             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14211             if (ctxt->error != XPATH_EXPRESSION_OK)
14212                 return(-1);
14213
14214             resObj = valuePop(ctxt);
14215             if (resObj == NULL)
14216                 return(-1);
14217             break;
14218         default:
14219             /*
14220             * Fallback to call xmlXPathCompOpEval().
14221             */
14222             xmlXPathCompOpEval(ctxt, op);
14223             if (ctxt->error != XPATH_EXPRESSION_OK)
14224                 return(-1);
14225
14226             resObj = valuePop(ctxt);
14227             if (resObj == NULL)
14228                 return(-1);
14229             break;
14230     }
14231
14232     if (resObj) {
14233         int res;
14234
14235         if (resObj->type == XPATH_BOOLEAN) {
14236             res = resObj->boolval;
14237         } else if (isPredicate) {
14238             /*
14239             * For predicates a result of type "number" is handled
14240             * differently:
14241             * SPEC XPath 1.0:
14242             * "If the result is a number, the result will be converted
14243             *  to true if the number is equal to the context position
14244             *  and will be converted to false otherwise;"
14245             */
14246             res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14247         } else {
14248             res = xmlXPathCastToBoolean(resObj);
14249         }
14250         xmlXPathReleaseObject(ctxt->context, resObj);
14251         return(res);
14252     }
14253
14254     return(0);
14255 }
14256
14257 #ifdef XPATH_STREAMING
14258 /**
14259  * xmlXPathRunStreamEval:
14260  * @ctxt:  the XPath parser context with the compiled expression
14261  *
14262  * Evaluate the Precompiled Streamable XPath expression in the given context.
14263  */
14264 static int
14265 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14266                       xmlXPathObjectPtr *resultSeq, int toBool)
14267 {
14268     int max_depth, min_depth;
14269     int from_root;
14270     int ret, depth;
14271     int eval_all_nodes;
14272     xmlNodePtr cur = NULL, limit = NULL;
14273     xmlStreamCtxtPtr patstream = NULL;
14274
14275     int nb_nodes = 0;
14276
14277     if ((ctxt == NULL) || (comp == NULL))
14278         return(-1);
14279     max_depth = xmlPatternMaxDepth(comp);
14280     if (max_depth == -1)
14281         return(-1);
14282     if (max_depth == -2)
14283         max_depth = 10000;
14284     min_depth = xmlPatternMinDepth(comp);
14285     if (min_depth == -1)
14286         return(-1);
14287     from_root = xmlPatternFromRoot(comp);
14288     if (from_root < 0)
14289         return(-1);
14290 #if 0
14291     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14292 #endif
14293
14294     if (! toBool) {
14295         if (resultSeq == NULL)
14296             return(-1);
14297         *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14298         if (*resultSeq == NULL)
14299             return(-1);
14300     }
14301
14302     /*
14303      * handle the special cases of "/" amd "." being matched
14304      */
14305     if (min_depth == 0) {
14306         if (from_root) {
14307             /* Select "/" */
14308             if (toBool)
14309                 return(1);
14310             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14311                                      (xmlNodePtr) ctxt->doc);
14312         } else {
14313             /* Select "self::node()" */
14314             if (toBool)
14315                 return(1);
14316             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14317         }
14318     }
14319     if (max_depth == 0) {
14320         return(0);
14321     }
14322
14323     if (from_root) {
14324         cur = (xmlNodePtr)ctxt->doc;
14325     } else if (ctxt->node != NULL) {
14326         switch (ctxt->node->type) {
14327             case XML_ELEMENT_NODE:
14328             case XML_DOCUMENT_NODE:
14329             case XML_DOCUMENT_FRAG_NODE:
14330             case XML_HTML_DOCUMENT_NODE:
14331 #ifdef LIBXML_DOCB_ENABLED
14332             case XML_DOCB_DOCUMENT_NODE:
14333 #endif
14334                 cur = ctxt->node;
14335                 break;
14336             case XML_ATTRIBUTE_NODE:
14337             case XML_TEXT_NODE:
14338             case XML_CDATA_SECTION_NODE:
14339             case XML_ENTITY_REF_NODE:
14340             case XML_ENTITY_NODE:
14341             case XML_PI_NODE:
14342             case XML_COMMENT_NODE:
14343             case XML_NOTATION_NODE:
14344             case XML_DTD_NODE:
14345             case XML_DOCUMENT_TYPE_NODE:
14346             case XML_ELEMENT_DECL:
14347             case XML_ATTRIBUTE_DECL:
14348             case XML_ENTITY_DECL:
14349             case XML_NAMESPACE_DECL:
14350             case XML_XINCLUDE_START:
14351             case XML_XINCLUDE_END:
14352                 break;
14353         }
14354         limit = cur;
14355     }
14356     if (cur == NULL) {
14357         return(0);
14358     }
14359
14360     patstream = xmlPatternGetStreamCtxt(comp);
14361     if (patstream == NULL) {
14362         /*
14363         * QUESTION TODO: Is this an error?
14364         */
14365         return(0);
14366     }
14367
14368     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14369
14370     if (from_root) {
14371         ret = xmlStreamPush(patstream, NULL, NULL);
14372         if (ret < 0) {
14373         } else if (ret == 1) {
14374             if (toBool)
14375                 goto return_1;
14376             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14377         }
14378     }
14379     depth = 0;
14380     goto scan_children;
14381 next_node:
14382     do {
14383         nb_nodes++;
14384
14385         switch (cur->type) {
14386             case XML_ELEMENT_NODE:
14387             case XML_TEXT_NODE:
14388             case XML_CDATA_SECTION_NODE:
14389             case XML_COMMENT_NODE:
14390             case XML_PI_NODE:
14391                 if (cur->type == XML_ELEMENT_NODE) {
14392                     ret = xmlStreamPush(patstream, cur->name,
14393                                 (cur->ns ? cur->ns->href : NULL));
14394                 } else if (eval_all_nodes)
14395                     ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14396                 else
14397                     break;
14398
14399                 if (ret < 0) {
14400                     /* NOP. */
14401                 } else if (ret == 1) {
14402                     if (toBool)
14403                         goto return_1;
14404                     if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14405                         < 0) {
14406                         ctxt->lastError.domain = XML_FROM_XPATH;
14407                         ctxt->lastError.code = XML_ERR_NO_MEMORY;
14408                     }
14409                 }
14410                 if ((cur->children == NULL) || (depth >= max_depth)) {
14411                     ret = xmlStreamPop(patstream);
14412                     while (cur->next != NULL) {
14413                         cur = cur->next;
14414                         if ((cur->type != XML_ENTITY_DECL) &&
14415                             (cur->type != XML_DTD_NODE))
14416                             goto next_node;
14417                     }
14418                 }
14419             default:
14420                 break;
14421         }
14422
14423 scan_children:
14424         if (cur->type == XML_NAMESPACE_DECL) break;
14425         if ((cur->children != NULL) && (depth < max_depth)) {
14426             /*
14427              * Do not descend on entities declarations
14428              */
14429             if (cur->children->type != XML_ENTITY_DECL) {
14430                 cur = cur->children;
14431                 depth++;
14432                 /*
14433                  * Skip DTDs
14434                  */
14435                 if (cur->type != XML_DTD_NODE)
14436                     continue;
14437             }
14438         }
14439
14440         if (cur == limit)
14441             break;
14442
14443         while (cur->next != NULL) {
14444             cur = cur->next;
14445             if ((cur->type != XML_ENTITY_DECL) &&
14446                 (cur->type != XML_DTD_NODE))
14447                 goto next_node;
14448         }
14449
14450         do {
14451             cur = cur->parent;
14452             depth--;
14453             if ((cur == NULL) || (cur == limit))
14454                 goto done;
14455             if (cur->type == XML_ELEMENT_NODE) {
14456                 ret = xmlStreamPop(patstream);
14457             } else if ((eval_all_nodes) &&
14458                 ((cur->type == XML_TEXT_NODE) ||
14459                  (cur->type == XML_CDATA_SECTION_NODE) ||
14460                  (cur->type == XML_COMMENT_NODE) ||
14461                  (cur->type == XML_PI_NODE)))
14462             {
14463                 ret = xmlStreamPop(patstream);
14464             }
14465             if (cur->next != NULL) {
14466                 cur = cur->next;
14467                 break;
14468             }
14469         } while (cur != NULL);
14470
14471     } while ((cur != NULL) && (depth >= 0));
14472
14473 done:
14474
14475 #if 0
14476     printf("stream eval: checked %d nodes selected %d\n",
14477            nb_nodes, retObj->nodesetval->nodeNr);
14478 #endif
14479
14480     if (patstream)
14481         xmlFreeStreamCtxt(patstream);
14482     return(0);
14483
14484 return_1:
14485     if (patstream)
14486         xmlFreeStreamCtxt(patstream);
14487     return(1);
14488 }
14489 #endif /* XPATH_STREAMING */
14490
14491 /**
14492  * xmlXPathRunEval:
14493  * @ctxt:  the XPath parser context with the compiled expression
14494  * @toBool:  evaluate to a boolean result
14495  *
14496  * Evaluate the Precompiled XPath expression in the given context.
14497  */
14498 static int
14499 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14500 {
14501     xmlXPathCompExprPtr comp;
14502
14503     if ((ctxt == NULL) || (ctxt->comp == NULL))
14504         return(-1);
14505
14506     if (ctxt->valueTab == NULL) {
14507         /* Allocate the value stack */
14508         ctxt->valueTab = (xmlXPathObjectPtr *)
14509                          xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14510         if (ctxt->valueTab == NULL) {
14511             xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14512             xmlFree(ctxt);
14513         }
14514         ctxt->valueNr = 0;
14515         ctxt->valueMax = 10;
14516         ctxt->value = NULL;
14517         ctxt->valueFrame = 0;
14518     }
14519 #ifdef XPATH_STREAMING
14520     if (ctxt->comp->stream) {
14521         int res;
14522
14523         if (toBool) {
14524             /*
14525             * Evaluation to boolean result.
14526             */
14527             res = xmlXPathRunStreamEval(ctxt->context,
14528                 ctxt->comp->stream, NULL, 1);
14529             if (res != -1)
14530                 return(res);
14531         } else {
14532             xmlXPathObjectPtr resObj = NULL;
14533
14534             /*
14535             * Evaluation to a sequence.
14536             */
14537             res = xmlXPathRunStreamEval(ctxt->context,
14538                 ctxt->comp->stream, &resObj, 0);
14539
14540             if ((res != -1) && (resObj != NULL)) {
14541                 valuePush(ctxt, resObj);
14542                 return(0);
14543             }
14544             if (resObj != NULL)
14545                 xmlXPathReleaseObject(ctxt->context, resObj);
14546         }
14547         /*
14548         * QUESTION TODO: This falls back to normal XPath evaluation
14549         * if res == -1. Is this intended?
14550         */
14551     }
14552 #endif
14553     comp = ctxt->comp;
14554     if (comp->last < 0) {
14555         xmlGenericError(xmlGenericErrorContext,
14556             "xmlXPathRunEval: last is less than zero\n");
14557         return(-1);
14558     }
14559     if (toBool)
14560         return(xmlXPathCompOpEvalToBoolean(ctxt,
14561             &comp->steps[comp->last], 0));
14562     else
14563         xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14564
14565     return(0);
14566 }
14567
14568 /************************************************************************
14569  *                                                                      *
14570  *                      Public interfaces                               *
14571  *                                                                      *
14572  ************************************************************************/
14573
14574 /**
14575  * xmlXPathEvalPredicate:
14576  * @ctxt:  the XPath context
14577  * @res:  the Predicate Expression evaluation result
14578  *
14579  * Evaluate a predicate result for the current node.
14580  * A PredicateExpr is evaluated by evaluating the Expr and converting
14581  * the result to a boolean. If the result is a number, the result will
14582  * be converted to true if the number is equal to the position of the
14583  * context node in the context node list (as returned by the position
14584  * function) and will be converted to false otherwise; if the result
14585  * is not a number, then the result will be converted as if by a call
14586  * to the boolean function.
14587  *
14588  * Returns 1 if predicate is true, 0 otherwise
14589  */
14590 int
14591 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14592     if ((ctxt == NULL) || (res == NULL)) return(0);
14593     switch (res->type) {
14594         case XPATH_BOOLEAN:
14595             return(res->boolval);
14596         case XPATH_NUMBER:
14597             return(res->floatval == ctxt->proximityPosition);
14598         case XPATH_NODESET:
14599         case XPATH_XSLT_TREE:
14600             if (res->nodesetval == NULL)
14601                 return(0);
14602             return(res->nodesetval->nodeNr != 0);
14603         case XPATH_STRING:
14604             return((res->stringval != NULL) &&
14605                    (xmlStrlen(res->stringval) != 0));
14606         default:
14607             STRANGE
14608     }
14609     return(0);
14610 }
14611
14612 /**
14613  * xmlXPathEvaluatePredicateResult:
14614  * @ctxt:  the XPath Parser context
14615  * @res:  the Predicate Expression evaluation result
14616  *
14617  * Evaluate a predicate result for the current node.
14618  * A PredicateExpr is evaluated by evaluating the Expr and converting
14619  * the result to a boolean. If the result is a number, the result will
14620  * be converted to true if the number is equal to the position of the
14621  * context node in the context node list (as returned by the position
14622  * function) and will be converted to false otherwise; if the result
14623  * is not a number, then the result will be converted as if by a call
14624  * to the boolean function.
14625  *
14626  * Returns 1 if predicate is true, 0 otherwise
14627  */
14628 int
14629 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14630                                 xmlXPathObjectPtr res) {
14631     if ((ctxt == NULL) || (res == NULL)) return(0);
14632     switch (res->type) {
14633         case XPATH_BOOLEAN:
14634             return(res->boolval);
14635         case XPATH_NUMBER:
14636 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14637             return((res->floatval == ctxt->context->proximityPosition) &&
14638                    (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14639 #else
14640             return(res->floatval == ctxt->context->proximityPosition);
14641 #endif
14642         case XPATH_NODESET:
14643         case XPATH_XSLT_TREE:
14644             if (res->nodesetval == NULL)
14645                 return(0);
14646             return(res->nodesetval->nodeNr != 0);
14647         case XPATH_STRING:
14648             return((res->stringval != NULL) && (res->stringval[0] != 0));
14649 #ifdef LIBXML_XPTR_ENABLED
14650         case XPATH_LOCATIONSET:{
14651             xmlLocationSetPtr ptr = res->user;
14652             if (ptr == NULL)
14653                 return(0);
14654             return (ptr->locNr != 0);
14655             }
14656 #endif
14657         default:
14658             STRANGE
14659     }
14660     return(0);
14661 }
14662
14663 #ifdef XPATH_STREAMING
14664 /**
14665  * xmlXPathTryStreamCompile:
14666  * @ctxt: an XPath context
14667  * @str:  the XPath expression
14668  *
14669  * Try to compile the XPath expression as a streamable subset.
14670  *
14671  * Returns the compiled expression or NULL if failed to compile.
14672  */
14673 static xmlXPathCompExprPtr
14674 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14675     /*
14676      * Optimization: use streaming patterns when the XPath expression can
14677      * be compiled to a stream lookup
14678      */
14679     xmlPatternPtr stream;
14680     xmlXPathCompExprPtr comp;
14681     xmlDictPtr dict = NULL;
14682     const xmlChar **namespaces = NULL;
14683     xmlNsPtr ns;
14684     int i, j;
14685
14686     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14687         (!xmlStrchr(str, '@'))) {
14688         const xmlChar *tmp;
14689
14690         /*
14691          * We don't try to handle expressions using the verbose axis
14692          * specifiers ("::"), just the simplied form at this point.
14693          * Additionally, if there is no list of namespaces available and
14694          *  there's a ":" in the expression, indicating a prefixed QName,
14695          *  then we won't try to compile either. xmlPatterncompile() needs
14696          *  to have a list of namespaces at compilation time in order to
14697          *  compile prefixed name tests.
14698          */
14699         tmp = xmlStrchr(str, ':');
14700         if ((tmp != NULL) &&
14701             ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14702             return(NULL);
14703
14704         if (ctxt != NULL) {
14705             dict = ctxt->dict;
14706             if (ctxt->nsNr > 0) {
14707                 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14708                 if (namespaces == NULL) {
14709                     xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14710                     return(NULL);
14711                 }
14712                 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14713                     ns = ctxt->namespaces[j];
14714                     namespaces[i++] = ns->href;
14715                     namespaces[i++] = ns->prefix;
14716                 }
14717                 namespaces[i++] = NULL;
14718                 namespaces[i] = NULL;
14719             }
14720         }
14721
14722         stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14723                         &namespaces[0]);
14724         if (namespaces != NULL) {
14725             xmlFree((xmlChar **)namespaces);
14726         }
14727         if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14728             comp = xmlXPathNewCompExpr();
14729             if (comp == NULL) {
14730                 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14731                 return(NULL);
14732             }
14733             comp->stream = stream;
14734             comp->dict = dict;
14735             if (comp->dict)
14736                 xmlDictReference(comp->dict);
14737             return(comp);
14738         }
14739         xmlFreePattern(stream);
14740     }
14741     return(NULL);
14742 }
14743 #endif /* XPATH_STREAMING */
14744
14745 static void
14746 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14747 {
14748     /*
14749     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14750     * internal representation.
14751     */
14752
14753     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14754         (op->ch1 != -1) &&
14755         (op->ch2 == -1 /* no predicate */))
14756     {
14757         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14758
14759         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14760             ((xmlXPathAxisVal) prevop->value ==
14761                 AXIS_DESCENDANT_OR_SELF) &&
14762             (prevop->ch2 == -1) &&
14763             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14764             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14765         {
14766             /*
14767             * This is a "descendant-or-self::node()" without predicates.
14768             * Try to eliminate it.
14769             */
14770
14771             switch ((xmlXPathAxisVal) op->value) {
14772                 case AXIS_CHILD:
14773                 case AXIS_DESCENDANT:
14774                     /*
14775                     * Convert "descendant-or-self::node()/child::" or
14776                     * "descendant-or-self::node()/descendant::" to
14777                     * "descendant::"
14778                     */
14779                     op->ch1   = prevop->ch1;
14780                     op->value = AXIS_DESCENDANT;
14781                     break;
14782                 case AXIS_SELF:
14783                 case AXIS_DESCENDANT_OR_SELF:
14784                     /*
14785                     * Convert "descendant-or-self::node()/self::" or
14786                     * "descendant-or-self::node()/descendant-or-self::" to
14787                     * to "descendant-or-self::"
14788                     */
14789                     op->ch1   = prevop->ch1;
14790                     op->value = AXIS_DESCENDANT_OR_SELF;
14791                     break;
14792                 default:
14793                     break;
14794             }
14795         }
14796     }
14797
14798     /* OP_VALUE has invalid ch1. */
14799     if (op->op == XPATH_OP_VALUE)
14800         return;
14801
14802     /* Recurse */
14803     if (op->ch1 != -1)
14804         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14805     if (op->ch2 != -1)
14806         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14807 }
14808
14809 /**
14810  * xmlXPathCtxtCompile:
14811  * @ctxt: an XPath context
14812  * @str:  the XPath expression
14813  *
14814  * Compile an XPath expression
14815  *
14816  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14817  *         the caller has to free the object.
14818  */
14819 xmlXPathCompExprPtr
14820 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14821     xmlXPathParserContextPtr pctxt;
14822     xmlXPathCompExprPtr comp;
14823
14824 #ifdef XPATH_STREAMING
14825     comp = xmlXPathTryStreamCompile(ctxt, str);
14826     if (comp != NULL)
14827         return(comp);
14828 #endif
14829
14830     xmlXPathInit();
14831
14832     pctxt = xmlXPathNewParserContext(str, ctxt);
14833     if (pctxt == NULL)
14834         return NULL;
14835     xmlXPathCompileExpr(pctxt, 1);
14836
14837     if( pctxt->error != XPATH_EXPRESSION_OK )
14838     {
14839         xmlXPathFreeParserContext(pctxt);
14840         return(NULL);
14841     }
14842
14843     if (*pctxt->cur != 0) {
14844         /*
14845          * aleksey: in some cases this line prints *second* error message
14846          * (see bug #78858) and probably this should be fixed.
14847          * However, we are not sure that all error messages are printed
14848          * out in other places. It's not critical so we leave it as-is for now
14849          */
14850         xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14851         comp = NULL;
14852     } else {
14853         comp = pctxt->comp;
14854         pctxt->comp = NULL;
14855     }
14856     xmlXPathFreeParserContext(pctxt);
14857
14858     if (comp != NULL) {
14859         comp->expr = xmlStrdup(str);
14860 #ifdef DEBUG_EVAL_COUNTS
14861         comp->string = xmlStrdup(str);
14862         comp->nb = 0;
14863 #endif
14864         if ((comp->nbStep > 1) && (comp->last >= 0)) {
14865             xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14866         }
14867     }
14868     return(comp);
14869 }
14870
14871 /**
14872  * xmlXPathCompile:
14873  * @str:  the XPath expression
14874  *
14875  * Compile an XPath expression
14876  *
14877  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14878  *         the caller has to free the object.
14879  */
14880 xmlXPathCompExprPtr
14881 xmlXPathCompile(const xmlChar *str) {
14882     return(xmlXPathCtxtCompile(NULL, str));
14883 }
14884
14885 /**
14886  * xmlXPathCompiledEvalInternal:
14887  * @comp:  the compiled XPath expression
14888  * @ctxt:  the XPath context
14889  * @resObj: the resulting XPath object or NULL
14890  * @toBool: 1 if only a boolean result is requested
14891  *
14892  * Evaluate the Precompiled XPath expression in the given context.
14893  * The caller has to free @resObj.
14894  *
14895  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14896  *         the caller has to free the object.
14897  */
14898 static int
14899 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14900                              xmlXPathContextPtr ctxt,
14901                              xmlXPathObjectPtr *resObj,
14902                              int toBool)
14903 {
14904     xmlXPathParserContextPtr pctxt;
14905 #ifndef LIBXML_THREAD_ENABLED
14906     static int reentance = 0;
14907 #endif
14908     int res;
14909
14910     CHECK_CTXT_NEG(ctxt)
14911
14912     if (comp == NULL)
14913         return(-1);
14914     xmlXPathInit();
14915
14916 #ifndef LIBXML_THREAD_ENABLED
14917     reentance++;
14918     if (reentance > 1)
14919         xmlXPathDisableOptimizer = 1;
14920 #endif
14921
14922 #ifdef DEBUG_EVAL_COUNTS
14923     comp->nb++;
14924     if ((comp->string != NULL) && (comp->nb > 100)) {
14925         fprintf(stderr, "100 x %s\n", comp->string);
14926         comp->nb = 0;
14927     }
14928 #endif
14929     pctxt = xmlXPathCompParserContext(comp, ctxt);
14930     res = xmlXPathRunEval(pctxt, toBool);
14931
14932     if (resObj) {
14933         if (pctxt->value == NULL) {
14934             xmlGenericError(xmlGenericErrorContext,
14935                 "xmlXPathCompiledEval: evaluation failed\n");
14936             *resObj = NULL;
14937         } else {
14938             *resObj = valuePop(pctxt);
14939         }
14940     }
14941
14942     /*
14943     * Pop all remaining objects from the stack.
14944     */
14945     if (pctxt->valueNr > 0) {
14946         xmlXPathObjectPtr tmp;
14947         int stack = 0;
14948
14949         do {
14950             tmp = valuePop(pctxt);
14951             if (tmp != NULL) {
14952                 stack++;
14953                 xmlXPathReleaseObject(ctxt, tmp);
14954             }
14955         } while (tmp != NULL);
14956         if ((stack != 0) &&
14957             ((toBool) || ((resObj) && (*resObj))))
14958         {
14959             xmlGenericError(xmlGenericErrorContext,
14960                 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14961                 stack);
14962         }
14963     }
14964
14965     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14966         xmlXPathFreeObject(*resObj);
14967         *resObj = NULL;
14968     }
14969     pctxt->comp = NULL;
14970     xmlXPathFreeParserContext(pctxt);
14971 #ifndef LIBXML_THREAD_ENABLED
14972     reentance--;
14973 #endif
14974
14975     return(res);
14976 }
14977
14978 /**
14979  * xmlXPathCompiledEval:
14980  * @comp:  the compiled XPath expression
14981  * @ctx:  the XPath context
14982  *
14983  * Evaluate the Precompiled XPath expression in the given context.
14984  *
14985  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14986  *         the caller has to free the object.
14987  */
14988 xmlXPathObjectPtr
14989 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14990 {
14991     xmlXPathObjectPtr res = NULL;
14992
14993     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14994     return(res);
14995 }
14996
14997 /**
14998  * xmlXPathCompiledEvalToBoolean:
14999  * @comp:  the compiled XPath expression
15000  * @ctxt:  the XPath context
15001  *
15002  * Applies the XPath boolean() function on the result of the given
15003  * compiled expression.
15004  *
15005  * Returns 1 if the expression evaluated to true, 0 if to false and
15006  *         -1 in API and internal errors.
15007  */
15008 int
15009 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
15010                               xmlXPathContextPtr ctxt)
15011 {
15012     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
15013 }
15014
15015 /**
15016  * xmlXPathEvalExpr:
15017  * @ctxt:  the XPath Parser context
15018  *
15019  * Parse and evaluate an XPath expression in the given context,
15020  * then push the result on the context stack
15021  */
15022 void
15023 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
15024 #ifdef XPATH_STREAMING
15025     xmlXPathCompExprPtr comp;
15026 #endif
15027
15028     if (ctxt == NULL) return;
15029
15030 #ifdef XPATH_STREAMING
15031     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
15032     if (comp != NULL) {
15033         if (ctxt->comp != NULL)
15034             xmlXPathFreeCompExpr(ctxt->comp);
15035         ctxt->comp = comp;
15036         if (ctxt->cur != NULL)
15037             while (*ctxt->cur != 0) ctxt->cur++;
15038     } else
15039 #endif
15040     {
15041         xmlXPathCompileExpr(ctxt, 1);
15042         if ((ctxt->error == XPATH_EXPRESSION_OK) &&
15043             (ctxt->comp != NULL) &&
15044             (ctxt->comp->nbStep > 1) &&
15045             (ctxt->comp->last >= 0))
15046         {
15047             xmlXPathOptimizeExpression(ctxt->comp,
15048                 &ctxt->comp->steps[ctxt->comp->last]);
15049         }
15050     }
15051     CHECK_ERROR;
15052     xmlXPathRunEval(ctxt, 0);
15053 }
15054
15055 /**
15056  * xmlXPathEval:
15057  * @str:  the XPath expression
15058  * @ctx:  the XPath context
15059  *
15060  * Evaluate the XPath Location Path in the given context.
15061  *
15062  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15063  *         the caller has to free the object.
15064  */
15065 xmlXPathObjectPtr
15066 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15067     xmlXPathParserContextPtr ctxt;
15068     xmlXPathObjectPtr res, tmp, init = NULL;
15069     int stack = 0;
15070
15071     CHECK_CTXT(ctx)
15072
15073     xmlXPathInit();
15074
15075     ctxt = xmlXPathNewParserContext(str, ctx);
15076     if (ctxt == NULL)
15077         return NULL;
15078     xmlXPathEvalExpr(ctxt);
15079
15080     if (ctxt->value == NULL) {
15081         xmlGenericError(xmlGenericErrorContext,
15082                 "xmlXPathEval: evaluation failed\n");
15083         res = NULL;
15084     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
15085 #ifdef XPATH_STREAMING
15086             && (ctxt->comp->stream == NULL)
15087 #endif
15088               ) {
15089         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15090         res = NULL;
15091     } else {
15092         res = valuePop(ctxt);
15093     }
15094
15095     do {
15096         tmp = valuePop(ctxt);
15097         if (tmp != NULL) {
15098             if (tmp != init)
15099                 stack++;
15100             xmlXPathReleaseObject(ctx, tmp);
15101         }
15102     } while (tmp != NULL);
15103     if ((stack != 0) && (res != NULL)) {
15104         xmlGenericError(xmlGenericErrorContext,
15105                 "xmlXPathEval: %d object left on the stack\n",
15106                 stack);
15107     }
15108     if (ctxt->error != XPATH_EXPRESSION_OK) {
15109         xmlXPathFreeObject(res);
15110         res = NULL;
15111     }
15112
15113     xmlXPathFreeParserContext(ctxt);
15114     return(res);
15115 }
15116
15117 /**
15118  * xmlXPathSetContextNode:
15119  * @node: the node to to use as the context node
15120  * @ctx:  the XPath context
15121  *
15122  * Sets 'node' as the context node. The node must be in the same
15123  * document as that associated with the context.
15124  *
15125  * Returns -1 in case of error or 0 if successful
15126  */
15127 int
15128 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15129     if ((node == NULL) || (ctx == NULL))
15130         return(-1);
15131
15132     if (node->doc == ctx->doc) {
15133         ctx->node = node;
15134         return(0);
15135     }
15136     return(-1);
15137 }
15138
15139 /**
15140  * xmlXPathNodeEval:
15141  * @node: the node to to use as the context node
15142  * @str:  the XPath expression
15143  * @ctx:  the XPath context
15144  *
15145  * Evaluate the XPath Location Path in the given context. The node 'node'
15146  * is set as the context node. The context node is not restored.
15147  *
15148  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15149  *         the caller has to free the object.
15150  */
15151 xmlXPathObjectPtr
15152 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15153     if (str == NULL)
15154         return(NULL);
15155     if (xmlXPathSetContextNode(node, ctx) < 0)
15156         return(NULL);
15157     return(xmlXPathEval(str, ctx));
15158 }
15159
15160 /**
15161  * xmlXPathEvalExpression:
15162  * @str:  the XPath expression
15163  * @ctxt:  the XPath context
15164  *
15165  * Evaluate the XPath expression in the given context.
15166  *
15167  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15168  *         the caller has to free the object.
15169  */
15170 xmlXPathObjectPtr
15171 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15172     xmlXPathParserContextPtr pctxt;
15173     xmlXPathObjectPtr res, tmp;
15174     int stack = 0;
15175
15176     CHECK_CTXT(ctxt)
15177
15178     xmlXPathInit();
15179
15180     pctxt = xmlXPathNewParserContext(str, ctxt);
15181     if (pctxt == NULL)
15182         return NULL;
15183     xmlXPathEvalExpr(pctxt);
15184
15185     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
15186         xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15187         res = NULL;
15188     } else {
15189         res = valuePop(pctxt);
15190     }
15191     do {
15192         tmp = valuePop(pctxt);
15193         if (tmp != NULL) {
15194             xmlXPathReleaseObject(ctxt, tmp);
15195             stack++;
15196         }
15197     } while (tmp != NULL);
15198     if ((stack != 0) && (res != NULL)) {
15199         xmlGenericError(xmlGenericErrorContext,
15200                 "xmlXPathEvalExpression: %d object left on the stack\n",
15201                 stack);
15202     }
15203     xmlXPathFreeParserContext(pctxt);
15204     return(res);
15205 }
15206
15207 /************************************************************************
15208  *                                                                      *
15209  *      Extra functions not pertaining to the XPath spec                *
15210  *                                                                      *
15211  ************************************************************************/
15212 /**
15213  * xmlXPathEscapeUriFunction:
15214  * @ctxt:  the XPath Parser context
15215  * @nargs:  the number of arguments
15216  *
15217  * Implement the escape-uri() XPath function
15218  *    string escape-uri(string $str, bool $escape-reserved)
15219  *
15220  * This function applies the URI escaping rules defined in section 2 of [RFC
15221  * 2396] to the string supplied as $uri-part, which typically represents all
15222  * or part of a URI. The effect of the function is to replace any special
15223  * character in the string by an escape sequence of the form %xx%yy...,
15224  * where xxyy... is the hexadecimal representation of the octets used to
15225  * represent the character in UTF-8.
15226  *
15227  * The set of characters that are escaped depends on the setting of the
15228  * boolean argument $escape-reserved.
15229  *
15230  * If $escape-reserved is true, all characters are escaped other than lower
15231  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15232  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15233  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15234  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15235  * A-F).
15236  *
15237  * If $escape-reserved is false, the behavior differs in that characters
15238  * referred to in [RFC 2396] as reserved characters are not escaped. These
15239  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15240  *
15241  * [RFC 2396] does not define whether escaped URIs should use lower case or
15242  * upper case for hexadecimal digits. To ensure that escaped URIs can be
15243  * compared using string comparison functions, this function must always use
15244  * the upper-case letters A-F.
15245  *
15246  * Generally, $escape-reserved should be set to true when escaping a string
15247  * that is to form a single part of a URI, and to false when escaping an
15248  * entire URI or URI reference.
15249  *
15250  * In the case of non-ascii characters, the string is encoded according to
15251  * utf-8 and then converted according to RFC 2396.
15252  *
15253  * Examples
15254  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15255  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15256  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15257  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15258  *
15259  */
15260 static void
15261 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15262     xmlXPathObjectPtr str;
15263     int escape_reserved;
15264     xmlBufPtr target;
15265     xmlChar *cptr;
15266     xmlChar escape[4];
15267
15268     CHECK_ARITY(2);
15269
15270     escape_reserved = xmlXPathPopBoolean(ctxt);
15271
15272     CAST_TO_STRING;
15273     str = valuePop(ctxt);
15274
15275     target = xmlBufCreate();
15276
15277     escape[0] = '%';
15278     escape[3] = 0;
15279
15280     if (target) {
15281         for (cptr = str->stringval; *cptr; cptr++) {
15282             if ((*cptr >= 'A' && *cptr <= 'Z') ||
15283                 (*cptr >= 'a' && *cptr <= 'z') ||
15284                 (*cptr >= '0' && *cptr <= '9') ||
15285                 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15286                 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15287                 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15288                 (*cptr == '%' &&
15289                  ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15290                   (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15291                   (cptr[1] >= '0' && cptr[1] <= '9')) &&
15292                  ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15293                   (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15294                   (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15295                 (!escape_reserved &&
15296                  (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15297                   *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15298                   *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15299                   *cptr == ','))) {
15300                 xmlBufAdd(target, cptr, 1);
15301             } else {
15302                 if ((*cptr >> 4) < 10)
15303                     escape[1] = '0' + (*cptr >> 4);
15304                 else
15305                     escape[1] = 'A' - 10 + (*cptr >> 4);
15306                 if ((*cptr & 0xF) < 10)
15307                     escape[2] = '0' + (*cptr & 0xF);
15308                 else
15309                     escape[2] = 'A' - 10 + (*cptr & 0xF);
15310
15311                 xmlBufAdd(target, &escape[0], 3);
15312             }
15313         }
15314     }
15315     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15316         xmlBufContent(target)));
15317     xmlBufFree(target);
15318     xmlXPathReleaseObject(ctxt->context, str);
15319 }
15320
15321 /**
15322  * xmlXPathRegisterAllFunctions:
15323  * @ctxt:  the XPath context
15324  *
15325  * Registers all default XPath functions in this context
15326  */
15327 void
15328 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15329 {
15330     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15331                          xmlXPathBooleanFunction);
15332     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15333                          xmlXPathCeilingFunction);
15334     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15335                          xmlXPathCountFunction);
15336     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15337                          xmlXPathConcatFunction);
15338     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15339                          xmlXPathContainsFunction);
15340     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15341                          xmlXPathIdFunction);
15342     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15343                          xmlXPathFalseFunction);
15344     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15345                          xmlXPathFloorFunction);
15346     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15347                          xmlXPathLastFunction);
15348     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15349                          xmlXPathLangFunction);
15350     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15351                          xmlXPathLocalNameFunction);
15352     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15353                          xmlXPathNotFunction);
15354     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15355                          xmlXPathNameFunction);
15356     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15357                          xmlXPathNamespaceURIFunction);
15358     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15359                          xmlXPathNormalizeFunction);
15360     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15361                          xmlXPathNumberFunction);
15362     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15363                          xmlXPathPositionFunction);
15364     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15365                          xmlXPathRoundFunction);
15366     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15367                          xmlXPathStringFunction);
15368     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15369                          xmlXPathStringLengthFunction);
15370     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15371                          xmlXPathStartsWithFunction);
15372     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15373                          xmlXPathSubstringFunction);
15374     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15375                          xmlXPathSubstringBeforeFunction);
15376     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15377                          xmlXPathSubstringAfterFunction);
15378     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15379                          xmlXPathSumFunction);
15380     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15381                          xmlXPathTrueFunction);
15382     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15383                          xmlXPathTranslateFunction);
15384
15385     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15386          (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15387                          xmlXPathEscapeUriFunction);
15388 }
15389
15390 #endif /* LIBXML_XPATH_ENABLED */
15391 #define bottom_xpath
15392 #include "elfgcchack.h"